Como Express e hapi se comparam?

133

Do ponto de vista do design e desenvolvimento de aplicativos da web, como o Express e o Hapi se comparam? Para exemplos básicos, eles parecem semelhantes, no entanto, estou interessado em aprender mais sobre as principais diferenças na estrutura geral do aplicativo.

Por exemplo, tanto quanto eu aprendi, o Hapi usa um mecanismo de roteamento diferente que não leva em conta a ordem de registro, pode fazer pesquisas mais rápidas, mas é limitado em comparação ao Express. Existem outras diferenças importantes?

Há também um artigo sobre a escolha da Hapi (sobre Express) para o desenvolvimento do novo site npmjs.com, este artigo afirma que "o sistema de plug-in da Hapi significa que podemos isolar diferentes facetas e serviços do aplicativo de maneiras que permitiriam microsserviços no Express, por outro lado, requer um pouco mais de configuração para obter a mesma funcionalidade ", o que significa exatamente?

Ali Shakiba
fonte

Respostas:

231

Essa é uma grande pergunta e requer uma resposta longa para ser concluída; portanto, abordarei apenas um subconjunto das diferenças mais importantes. Desculpas por ainda ser uma resposta longa.

Como eles são semelhantes?

Você está absolutamente certo quando diz:

Para exemplos básicos, eles parecem semelhantes

Ambas as estruturas estão resolvendo o mesmo problema básico: Fornecer uma API conveniente para a construção de servidores HTTP no nó. Ou seja, mais conveniente do que usar o httpmódulo nativo de nível inferior sozinho. O httpmódulo pode fazer tudo o que queremos, mas é entediante escrever aplicativos.

Para conseguir isso, os dois usam conceitos que existem há muito tempo em estruturas da Web de alto nível: roteamento, manipuladores, plugins, módulos de autenticação. Eles podem nem sempre ter o mesmo nome, mas são aproximadamente equivalentes.

A maioria dos exemplos básicos se parece com isso:

  • Crie uma rota
  • Execute uma função quando a rota for solicitada, preparando a resposta
  • Responder ao pedido

Expressar:

app.get('/', function (req, res) {

    getSomeValue(function (obj) {

        res.json({an: 'object'});
    });
});

hapi:

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        getSomeValue(function (obj) {

            reply(obj);
        });
    }
});

A diferença não é exatamente inovadora aqui, certo? Então, por que escolher um sobre o outro?

Como eles são diferentes?

A resposta simples é que há muito mais e faz muito mais fora da caixa. Isso pode não ficar claro quando você olha apenas o exemplo simples de cima. De fato, isso é intencional. Os casos simples são mantidos simples. Então, vamos examinar algumas das grandes diferenças:

Filosofia

Express pretende ser muito mínimo. Ao fornecer uma pequena API com apenas uma fina camada de poeira http, você ainda estará por conta própria em termos de adição de funcionalidade adicional. Se você quiser ler o corpo de uma solicitação recebida (uma tarefa bastante comum), precisará instalar um módulo separado . Se você espera que vários tipos de conteúdo sejam enviados para essa rota, também é necessário verificar o Content-typecabeçalho para verificar qual é e analisá-lo adequadamente (dados do formulário vs JSON vs várias partes, por exemplo), geralmente usando módulos separados .

O hapi possui um rico conjunto de recursos, geralmente exposto por meio de opções de configuração, em vez de exigir que o código seja gravado. Por exemplo, se queremos garantir que um corpo de solicitação (carga útil) seja totalmente lido na memória e analisado adequadamente (automaticamente com base no tipo de conteúdo) antes da execução do manipulador, é apenas uma opção simples :

server.route({
    config: {
        payload: {
            output: 'data',
            parse: true
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply(request.payload);
    }
});

Recursos

Você só precisa comparar a documentação da API nos dois projetos para ver que o hapi oferece um conjunto maior de recursos.

O hapi inclui alguns dos seguintes recursos internos que o Express não inclui (tanto quanto eu sei):

Extensibilidade e modularidade

O hapi e o Express estudam a extensibilidade de uma maneira bem diferente. Com o Express, você tem funções de middleware . As funções de middleware são como filtros que você empilha e todas as solicitações são executadas antes de acessar seu manipulador.

O hapi possui o ciclo de vida da solicitação e oferece pontos de extensão , que são comparáveis ​​às funções do middleware, mas existem vários pontos definidos no ciclo de vida da solicitação.

Uma das razões pelas quais o Walmart criou o hapi e parou de usar o Express foi uma frustração com a dificuldade de dividir um aplicativo Express em partes separadas, e fazer com que diferentes membros da equipe trabalhassem com segurança em seu bloco. Por esse motivo, eles criaram o sistema de plugins no hapi.

Um plug-in é como um sub-aplicativo, você pode fazer tudo o que puder em um aplicativo hapi, adicionar rotas, pontos de extensões etc. Em um plug-in, você pode ter certeza de que não está quebrando outra parte do aplicativo, porque a ordem de os registros de rotas não importam e você não pode criar rotas conflitantes. Você pode combinar esses plugins em um servidor e implantá-lo.

Ecossistema

Como o Express oferece muito pouco, você precisa olhar para fora quando precisar adicionar algo ao seu projeto. Muitas vezes, ao trabalhar com o hapi, o recurso que você precisa está embutido ou existe um módulo criado pela equipe principal.

Mínimo parece ótimo. Mas se você estiver criando um aplicativo de produção sério, as chances são de que você precisará de todas essas coisas eventualmente.

Segurança

O hapi foi projetado pela equipe do Walmart para administrar o tráfego da Black Friday, de modo que a segurança e a estabilidade sempre foram uma das principais preocupações. Por esse motivo, a estrutura faz muitas coisas extras, como limitar o tamanho da carga útil recebida para evitar o esgotamento da memória do processo. Ele também tem opções para coisas como atraso máximo do loop de eventos, memória RSS máxima usada e tamanho máximo do heap da v8, além do qual o servidor responderá com um tempo limite de 503 em vez de apenas travar.

Resumo

Avalie os dois você mesmo. Pense em suas necessidades e qual dos dois atende às suas maiores preocupações. Dê um mergulho nas duas comunidades (IRC, Gitter, Github), veja qual você prefere. Não aceite apenas minha palavra. E hacking feliz!


AVISO LEGAL: Sou tendencioso como autor de um livro sobre o hapi e o que foi exposto acima é em grande parte minha opinião pessoal.

Matt Harrison
fonte
7
Matt, obrigado pela extensa publicação, as seções "extensibilidade e modularidade" e "segurança" foram as seções mais úteis para mim. Acho que vale a pena mencionar que o novo sistema de roteamento no Express 4 fornece modularidade aprimorada para subaplicações.
Ali Shakiba
1
Ótima resposta Matt. Também estamos confusos entre o Hapi e o Express, uma desvantagem que estamos vendo com o Hapi é que ele não tem suporte comunitário tão extenso quanto o Express e pode ser um grande problema se ficarmos presos em algum lugar. Precisa da sua opinião sobre o mesmo.
Aman Gupta
1
Express é genérico, enquanto hapi é um pouco mais corporativo.
precisa saber é
1
@MattHarrison ótima resposta, agora estou lendo seu livro sobre a Hapi, é ótimo. Estou prestes a desenvolver um novo mercado para livros usando Hapi no backend e vue.js no frontend. Depois de me acostumar com o Hapi, gostaria de participar ativamente do projeto Hapi.
Humoyun Ahmad
1
@Humoyun Great! Esteja ciente de que existe uma nova versão principal do hapi com algumas mudanças consideráveis ​​desde <= v16.0.0. Atualmente estou produzindo uma série de screencasts projetados para as pessoas aprenderem v17: youtube.com/playlist?list=PLi303AVTbxaxqjaSWPg94nccYIfqNoCHz
Matt Harrison
54

Minha organização está indo com a Hapi. É por isso que gostamos.

Hapi é:

  • Apoiado pelos principais corpos. Isso significa que o suporte da comunidade será forte e estará disponível para você em versões futuras. É fácil encontrar pessoas Hapi apaixonadas, e existem bons tutoriais por aí (embora não tão numerosos e abrangentes quanto os tutoriais do ExpressJs). Até essa data de publicação, a NPM e o Walmart usavam o Hapi.
  • Ele pode facilitar o trabalho de equipes distribuídas que trabalham em várias partes dos serviços de back-end sem precisar ter um conhecimento abrangente do restante da superfície da API (a arquitetura de plug-ins da Hapi é o epítome dessa qualidade).
  • Deixe a estrutura fazer o que uma estrutura deve: configurar as coisas. Depois disso, a estrutura deve ficar invisível e permitir que os desenvolvedores concentrem sua energia criativa real na construção da lógica de negócios. Depois de usar o Hapi por um ano, definitivamente sinto que o Hapi realiza isso. Eu me sinto feliz!

Se você quiser ouvir diretamente de Eran Hammer (líder de Hapi)

Nos últimos quatro anos, o hapi passou a ser a estrutura de escolha para muitos projetos, grandes ou pequenos. O que torna o hapi único é sua capacidade de expandir para grandes implantações e grandes equipes. À medida que um projeto cresce, sua complexidade também cresce - complexidade de engenharia e complexidade de processos. A arquitetura e a filosofia da hapi lida com o aumento da complexidade sem a necessidade de refatorar constantemente o código [leia mais]

Começar com o Hapi não será tão fácil quanto o ExpressJs, porque o Hapi não tem o mesmo "poder estelar" ... mas, quando você se sentir confortável, terá MUITA milhagem. Demorei cerca de 2 meses como um novo hacker que usou ExpressJs de forma irresponsável por alguns anos. Se você é um desenvolvedor de back-end experiente, saberá ler os documentos e provavelmente nem perceberá isso.

Áreas em que a documentação do Hapi pode melhorar:

  1. como autenticar usuários e criar sessões
  2. tratamento de solicitações de origem cruzada (CORS)
  3. upload de arquivos (multipart, em pedaços)

Eu acho que a autenticação seria a parte mais desafiadora, porque você precisa decidir qual tipo de estratégia de autenticação usar (autenticação básica, cookies, toques JWT, OAuth). Embora tecnicamente não seja problema da Hapi que o cenário de sessões / autenticação seja tão fragmentado ... mas eu desejo que eles tenham fornecido alguma ajuda para isso. Aumentaria bastante a felicidade do desenvolvedor.

Os dois restantes não são realmente tão difíceis, os documentos podem ser escritos um pouco melhor.

wle8300
fonte
3

Fatos rápidos sobre o Hapi ou por que o Hapi JS?

O Hapi é centralizado na configuração. Possui autenticação e autorização incorporadas na estrutura. Foi lançado em uma atmosfera testada em batalha e realmente provou seu valor. Todos os módulos têm 100% de cobertura de teste. Registra o nível mais alto de abstração fora do HTTP principal. através da arquitetura do plugin

O Hapi é uma escolha melhor em termos de desempenho. O Hapi usa um mecanismo de roteamento diferente, que pode fazer pesquisas mais rápidas e levar em consideração o pedido de registro. No entanto, é bastante limitado quando comparado ao Express. E, graças ao sistema de plug-in Hapi, é possível isolar as diferentes facetas e serviços que ajudariam o aplicativo de várias maneiras no futuro.

Uso

Hapi é a estrutura mais preferida quando comparada ao Express. O Hapi é usado principalmente para aplicativos corporativos em larga escala.

Algumas razões pelas quais os desenvolvedores não escolhem o Express ao criar aplicativos corporativos são:

As rotas são mais difíceis de compor no Express

O middleware atrapalha a maior parte do tempo; toda vez que você definir as rotas, precisará escrever o maior número de códigos.

O Hapi seria a melhor opção para um desenvolvedor que deseja criar uma API RESTful. O Hapi possui arquitetura de microsserviço e também é possível transferir o controle de um manipulador para outro com base em determinados parâmetros. Com o plug-in Hapi, você pode desfrutar de um nível maior de abstração em torno do HTTP porque pode dividir a lógica de negócios em partes facilmente gerenciáveis.

Outra grande vantagem do Hapi é que ele fornece mensagens de erro detalhadas quando você configura incorretamente. O Hapi também permite que você configure o tamanho do upload do arquivo por padrão. Se o tamanho máximo de upload for limitado, você poderá enviar uma mensagem de erro ao usuário informando que o tamanho do arquivo é muito grande. Isso protegeria seu servidor contra falhas, porque os uploads de arquivos não tentarão mais armazenar em buffer um arquivo inteiro.

  1. Tudo o que você pode conseguir usando o express também pode ser facilmente alcançado usando hapi.js.

  2. O Hapi.js é muito estiloso e organiza muito bem o código. Se você ver como ele faz o roteamento e coloca a lógica principal nos controladores, certamente vai adorar.

  3. O Hapi.js fornece oficialmente vários plugins exclusivamente para os intervalos do hapi.js. de autenticação baseada em token a gerenciamento de sessões e muito mais, que é um anúncio. Isso não significa que o npm tradicional não possa ser usado, todos eles são suportados pelo hapi.js

  4. Se você codificar em hapi.js, um código seria muito sustentável.

user9961607
fonte
"Se você ver como ele faz o roteamento e coloca a lógica principal nos controladores ...". Não vejo nenhum exemplo na documentação que mostra o uso de controladores. Todos os exemplos de roteamento usam a propriedade handler, que é uma função. Comparo desta maneira com o que o Laravel (framework PHP) e o AdonisJs (framework Node.js.) fazem para roteamento, no qual podemos usar controladores para roteamento. Provavelmente perdi partes do documento HAPI que mostram o uso de controladores para roteamento. Portanto, se esse recurso existir, será bom para mim, porque estou acostumado a usar controladores para roteamento no Laravel.
Lex Soft
1

Comecei a usar o Hapi recentemente e estou muito feliz com isso. Minhas razões são

  1. Mais fácil de testar. Por exemplo:

    • server.inject permite que você execute o aplicativo e obtenha uma resposta sem executá-lo e ouvi-lo.
    • server.info dá a uri atual, porta etc.
    • server.settingsacessa a configuração, por exemplo, server.settings.cacheobtém o provedor de cache atual
    • em caso de dúvida, procure nas /testpastas qualquer parte do aplicativo ou plug-ins suportados para ver sugestões de como simular / testar / stub etc.
    • eu acho que o modelo arquitetural do hapi permite que você confie, mas verifique, por exemplo. Meus plugins estão registrados ? Como posso declarar uma dependência de módulo ?
  2. Funciona imediatamente , por exemplo , uploads de arquivos , fluxos de retorno de terminais etc.

  3. Os plug-ins essenciais são mantidos junto com a biblioteca principal. por exemplo , análise de modelo , armazenamento em cache etc. O benefício adicional é o mesmo padrão de codificação aplicado nos itens essenciais.

  4. Erros sãos e manipulação de erros. O Hapi valida as opções de configuração e mantém uma tabela de rotas interna para evitar rotas duplicadas. Isso é bastante útil durante o aprendizado, porque erros são gerados mais cedo, em vez de comportamentos inesperados, que exigem depuração.

Peter
fonte
-1

Apenas mais um ponto a acrescentar: a Hapi começou a suportar chamadas 'http2' da versão 16 em diante (se não estiver errado). No entanto, o Express ainda não suporta o módulo 'http2' diretamente até o Express 4. Embora eles tenham lançado o recurso na versão alfa do Express 5.

Uchiha Itachi
fonte
-2
'use strict';
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const server = new Hapi.Server();
server.connection({
    port: 2090,
    host: 'localhost'
});


var vorpal = require('vorpal')();
const chalk = vorpal.chalk;
var fs = require("fs");

var utenti = [{
        name: 'a',
        pass: 'b'
    },
    {
        name: 'c',
        pass: 'd'
    }
];

const users = {
    john: {
        username: 'john',
        password: 'secret',
        name: 'John Doe',
        id: '2133d32a'
    },
    paul: {
        username: 'paul',
        password: 'password',
        name: 'Paul Newman',
        id: '2133d32b'
    }
};

var messaggi = [{
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'ciao'
    },
    {
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'addio'
    },
    {
        destinazione: 'c',
        sorgente: 'a',
        messsaggio: 'arrivederci'
    }
];

var login = '';
var loggato = false;

vorpal
    .command('login <name> <pass>')
    .description('Effettua il login al sistema')
    .action(function (args, callback) {
        loggato = false;
        utenti.forEach(element => {
            if ((element.name == args.name) && (element.pass == args.pass)) {
                loggato = true;
                login = args.name;
                console.log("Accesso effettuato");
            }
        });
        if (!loggato)
            console.log("Login e Password errati");
        callback();
    });

vorpal
    .command('leggi')
    .description('Leggi i messaggi ricevuti')
    .action(function (args, callback) {
        if (loggato) {
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == login;
            });

            estratti.forEach(element => {
                console.log("mittente : " + element.sorgente);
                console.log(chalk.red(element.messsaggio));
            });
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('invia <dest> "<messaggio>"')
    .description('Invia un messaggio ad un altro utente')
    .action(function (args, callback) {
        if (loggato) {
            var trovato = utenti.find(function (element) {
                return element.name == args.dest;
            });
            if (trovato != undefined) {
                messaggi.push({
                    destinazione: args.dest,
                    sorgente: login,
                    messsaggio: args.messaggio
                });
                console.log(messaggi);
            }
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('crea <login> <pass>')
    .description('Crea un nuovo utente')
    .action(function (args, callback) {
        var trovato = utenti.find(function (element) {
            return element.name == args.login;
        });
        if (trovato == undefined) {
            utenti.push({
                name: args.login,
                pass: args.pass
            });
            console.log(utenti);
        }
        callback();
    });

vorpal
    .command('file leggi utenti')
    .description('Legge il file utenti')
    .action(function (args, callback) {
        var contents = fs.readFileSync("utenti.json");
        utenti = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi utenti')
    .description('Scrive il file utenti')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(utenti);
        fs.writeFile('utenti.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

vorpal
    .command('file leggi messaggi')
    .description('Legge il file messaggi')
    .action(function (args, callback) {
        var contents = fs.readFileSync("messaggi.json");
        messaggi = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi messaggi')
    .description('Scrive il file messaggi')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(messaggi);
        fs.writeFile('messaggi.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

// leggi file , scrivi file

vorpal
    .delimiter(chalk.yellow('messaggi$'))
    .show();




const validate = function (request, username, password, callback) {
    loggato = false;


    utenti.forEach(element => {
        if ((element.name == username) && (element.pass == password)) {
            loggato = true;
            console.log("Accesso effettuato");
            return callback(null, true, {
                name: username
            })
        }
    });
    if (!loggato)
        return callback(null, false);
};

server.register(Basic, function (err) {
    if (err) {
        throw err;
    }
});

server.auth.strategy('simple', 'basic', {
    validateFunc: validate
});



server.route({
    method: 'GET',
    path: '/',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            reply('hello, ' + request.auth.credentials.name);
        }
    }
});

//route scrivere
server.route({
    method: 'POST',
    path: '/invia',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            //console.log("Received POST from " + request.payload.name + "; id=" + (request.payload.id || 'anon'));
            var payload = encodeURIComponent(request.payload)
            console.log(request.payload);
            console.log(request.payload.dest);
            console.log(request.payload.messaggio);
            messaggi.push({
                destinazione: request.payload.dest,
                sorgente: request.auth.credentials.name,
                messsaggio: request.payload.messaggio
            });
            var jsontostring = JSON.stringify(messaggi);
            fs.writeFile('messaggi.json', jsontostring, function (err) {
                if (err) {
                    return console.error(err);
                }
            });
            console.log(messaggi);
            reply(messaggi[messaggi.length - 1]);

        }
    }
});


//route leggere (json)
server.route({
    method: 'GET',
    path: '/messaggi',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            messaggi = fs.readFileSync("messaggi.json");
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == request.auth.credentials.name;
            });
            var s = [];

            console.log(request.auth.credentials.name);
            console.log(estratti.length);
            estratti.forEach(element => {

                s.push(element);

                //fare l'array con stringify
                //s+="mittente : "+element.sorgente+": "+element.messsaggio+"\n";

            });
            var a = JSON.stringify(s);
            console.log(a);
            console.log(s);
            reply(a);
        }
    }
});



server.start(function () {
    console.log('Hapi is listening to ' + server.info.uri);
});

function EseguiSql(connection, sql, reply) {
    var rows = [];
    request = new Request(sql, function (err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request.on('row', function (columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request);
}

server.route({
    method: 'POST',
    path: '/query',
    handler: function (request, reply) {
        // Qui dovrebbe cercare i dati nel body e rispondere con la query eseguita
        var connection = new Connection(config);

        // Attempt to connect and execute queries if connection goes through
        connection.on('connect', function (err) {
            if (err) {
                console.log(err);
            } else {

                console.log('Connected');
                console.log(request.payload.sql);
                EseguiSql(connection, request.payload.sql, reply);
            }
        });

    }
});

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 8080
});

var config = {
    userName: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    server: process.env.DB_SERVER,
    options: {
        database: process.env.DB_NAME,
        encrypt: true
    }
}
alberdo dellagiacoma
fonte
Bem-vindo ao StackOverflow. Você poderia elaborar mais sobre sua resposta e como ela se relaciona com a pergunta postada pelo OP?
Szymon Maszke 20/02/19
-3
    const Hapi = require('hapi');
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
const server = new Hapi.Server();
var vorpal = require('vorpal')();

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 3000
});
server.start(function (err) {
    if (err) {
        throw err;
    }
    console.log("server running at : " + server.info.uri);
});

var config =
{
    userName: 'sa',
    password: 'password.123',
    server: 'localhost',

    options:
    {
        database: '',
        port: 1433
    }
}

server.route(
    {
        method: 'GET',
        path: '/{categoria}',
        handler: function (request, reply) {
            var connection = new Connection(config);
            connection.on('connect', function (err) {
                if (err) {
                    console.log(err);
                }
                else {
                    console.log('Connected');
                    EseguiSqlGet(connection, request.params.categoria, reply);
                }
            });
        }
    }
);
function EseguiSqlGet(connection, cat, reply) {
    var rows = [];
    var sql = 'SELECT * FROM Prodotti INNER JOIN Categorie
 on Categorie.IdCategoria = Prodotti.IdCategoria
 WHERE Categorie.IdCategoria = ' + cat ;
    request_sql = new Request(sql, function(err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request_sql.on('row', function(columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request_sql);
}
// POST
server.route(
    {
        method: 'POST',
        path: '/inserisci',
        handler: function (request, reply) {
            var connection = new Connection(config);
            connection.on('connect', function (err) {
                if (err) {
                    console.log(err);
                }
                else {
                    console.log('Connected');
                    EseguiSqlPost(connection,reply, 
request.payload.idcat, request.payload.nome, request.payload.prezzo );
                }
            });
        }
    }
);
function EseguiSqlPost(connection,reply, cat,nome,prezzo) {

    var sql = "INSERT INTO Prodotti
 VALUES("+ cat +",'"+nome+"',"+prezzo+")";
    request_sql = new Request(sql, function(err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply('riga aggiunta');
        }
    });

    /*request_sql.on('row', function(columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });
*/
    connection.execSql(request_sql);
}






//VORPAL COMMAND PROMT
var categoria = [
    {

        'idcategoria':'1',
        'nome':'ciao',

    }
]


vorpal
    .command('inserisci <categoria> <nome>')
    .action(function(args, callback)
    {
        categoria.push(   
{'idcategoria':args.categoria,'nome':args.nome}     );
        console.log(JSON.stringify(categoria));
        callback();
    });

vorpal
.delimiter("delimeter")
.show();
alberdo dellagiacoma
fonte