Expressとhapiはどのように比較されますか?


133

Webアプリケーションの設計と開発の観点から、ExpressとHapiはどのように比較されますか?基本的な例では似ているように見えますが、全体的なアプリケーション構造の主な違いについて詳しく知りたいと思います。

たとえば、私が学んだ限り、ハピは 登録順序を考慮しない別のルーティングメカニズムを高速な検索を実行できますが、Expressと比較すると制限されます。他に重要な違いはありますか?

新しいnpmjs.com Webサイトを開発するためのHapi(over Express)の選択に関する記事もあります。この記事では、「Hapiのプラグインシステムは、アプリケーションのさまざまなファセットとサービスを、一方、Expressは、同じ機能を実現するためにもう少し設定が必要です」とはどういう意味ですか?

回答:


231

これは大きな質問であり、完全な回答には長い回答が必要なので、最も重要な違いのサブセットについてのみ説明します。それはまだ長い答えであることをお詫びします。

それらはどのように似ていますか?

あなたが言うときあなたは絶対に正しいです:

基本的な例では、彼らは似ているようです

どちらのフレームワークも同じ基本的な問題を解決しています。ノードでHTTPサーバーを構築するための便利なAPIを提供します。つまり、下位レベルのネイティブhttpモジュールを単独で使用するよりも便利です。httpモジュールは、私たちが望むすべてを行うことができますが、それはしてアプリケーションを作成するために退屈です。

これを実現するために、どちらも、ルーティング、ハンドラー、プラグイン、認証モジュールなど、高レベルのWebフレームワークで長い間使用されてきた概念を使用しています。それらは常に同じ名前であったとは限らないかもしれませんが、おおむね同等です。

基本的な例のほとんどは次のようになります。

  • ルートを作成する
  • ルートがリクエストされたときに関数を実行し、レスポンスを準備する
  • リクエストに応答する

エクスプレス:

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

    getSomeValue(function (obj) {

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

ハピ:

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

        getSomeValue(function (obj) {

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

違いはここでまさに画期的ではありませんか?では、なぜもう一方を選ぶのでしょうか。

それらはどう違いますか?

簡単な答えは、ハピはもっとたくさんあり、すぐに使えることです。上からの単純な例だけを見ると、それは明らかではないかもしれません。実際、これは意図的なものです。単純なケースは単純に保たれます。それでは、いくつかの大きな違いを調べてみましょう。

哲学

Expressは非常に最小限であることを意図しています。の上に薄いほこりをかけただけで小さなAPIを提供することで、http追加機能を追加するという点では、まだ自分で十分です。着信リクエストの本文を読み取る(一般的なタスクを終了する)場合は、別のモジュールをインストールする必要があります。さまざまなコンテンツタイプがそのルートに送信されることを期待している場合は、Content-typeヘッダーをチェックしてどちらであるかそれに応じて解析する(たとえば、フォームデータvs JSON vsマルチパート)。 。

hapiには豊富な機能セットがあり、コードの記述を要求するのではなく、構成オプションを通じて公開されることがよくあります。たとえば、ハンドラーが実行される前に、リクエストの本文(ペイロード)が完全にメモリに読み込まれ、適切に解析(コンテンツタイプに基づいて自動的に)されるようにしたい場合、これは単純なオプションです。

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

        reply(request.payload);
    }
});

特徴

両方のプロジェクトのAPIドキュメントを比較するだけで、hapiがより大きな機能セットを提供していることを確認できます。

hapiには、Expressにはない以下の機能が組み込まれています(私の知る限り)。

拡張性とモジュール性

hapiとExpressは、拡張性をまったく異なる方法で扱います。Expressには、ミドルウェア機能があります。ミドルウェア関数は、一種のフィルターのようなものであり、ハンドラーに到達する前に、すべてのリクエストがそれらを通過します。

hapiにはリクエストライフサイクルがあり、ミドルウェア機能に相当する拡張ポイントを提供しますが、リクエストライフサイクルにはいくつかの定義済みポイントが存在します。

Walmartがハピを構築してExpressの使用をやめた理由の1つは、Expressアプリを別々の部分に分割し、異なるチームメンバーがチャンクで安全に作業するのがいかに困難であるかへの不満でした。このため、彼らはhapiでプラグインシステムを作成しました。

プラグインはサブアプリケーションのようなものであり、hapiアプリでできるすべてのことを実行でき、ルート、拡張ポイントなどを追加できます。プラグインでは、アプリケーションの別の部分を壊していないことを確認できます。ルートの登録は重要ではなく、競合するルートを作成することはできません。次に、このプラグインをサーバーに結合してデプロイできます。

生態系

Expressはすぐに使用できるので、プロジェクトに何かを追加する必要がある場合は、外を見る必要があります。hapiを使用する場合、多くの場合、必要な機能は組み込みであるか、コアチームによって作成されたモジュールがあります。

最小限の音が素晴らしい。しかし、本格的な本番用アプリを構築している場合、最終的にはこれらすべてが必要になる可能性があります。

安全保障

hapiはウォルマートのチームがブラックフライデートラフィックを実行するように設計したため、セキュリティと安定性が常に最大の関心事でした。このため、フレームワークは、プロセスメモリの枯渇を防ぐために着信ペイロードサイズを制限するなど、追加の多くのことを行います。また、最大イベントループ遅延、使用される最大RSSメモリ、v8ヒープの最大サイズなどのオプションがあり、それを超えるとサーバーはクラッシュするだけでなく、503タイムアウトで応答します。

概要

それらを自分で評価してください。あなたのニーズについて考え、2つのうちどちらがあなたの最大の懸念に対処するかを考えてください。2つのコミュニティ(IRC、Gitter、Github)でひと泳ぎして、どちらを好むか見てください。私の言葉だけを聞いてはいけません。そしてハッキングハッピー!


免責事項:私はハピに関する本の著者として偏っています。上記は主に私の個人的な意見です。


7
マット、広範な投稿ありがとうございます。「拡張性とモジュール性」と「セキュリティ」のセクションが私にとって最も役立つセクションでした。Express 4の新しいルーティングシステムにより、サブアプリケーションのモジュール性が向上したことは、言及する価値があると思います。
Ali Shakiba、2015年

1
素晴らしい答えマット。また、b / w HapiとExpressが混同されています。Hapiで見られる欠点の1つは、コミュニティサポートがExpressほど広くサポートされておらず、どこかに行き詰まった場合に大きな問題になる可能性があることです。同じことについてあなたの意見が必要です。
アマングプタ2015

1
Expressは汎用的ですが、hapiはもう少しエンタープライズです。
windmaomao

1
@MattHarrison素晴らしい答え、今私はハピに関するあなたの本を読んでいます、それはただ素晴らしいです。Hapiに慣れた後、バックエンドでHapiを、フロントエンドでvue.jsを使用して、本の新しいマーケットプレイスを開発しようとしています。Hapiプロジェクトに積極的に参加したいと思います。
Humoyun Ahmad

1
@Humoyunグレート!ただし、<= v16.0.0以降に大幅に変更されたhapiの新しいメジャーバージョンがあることに注意してください。私は現在、v17を学ぶために設計されたスクリーンキャストシリーズを制作しています:youtube.com/playlist
Matt Harrison

54

私の組織はハピと行っています。これが私たちが気に入っている理由です。

ハピは:

  • 主要な軍団に支えられています。これは、コミュニティのサポートが強力になることを意味し、今後のリリースを通じてあなたのためになります。情熱的なHapiの人々を見つけるのは簡単で、そこには優れたチュートリアルがあります(ただし、ExpressJのチュートリアルほど多くなく、広大ではありません)。この投稿日現在、npmとWalmartはHapiを使用しています。
  • それは、APIサーフェスの残りの部分に関する包括的な知識がなくても、バックエンドサービスのさまざまな部分で作業する分散チームの作業を容易にすることができます(Hapiのプラグインアーキテクチャは、この品質の縮図です)。
  • フレームワークに想定されていることをフレームワークに実行させます。その後、フレームワークは見えなくなり、開発者がビジネスロジックの構築に真の創造的エネルギーを集中できるようにする必要があります。Hapiを1年間使用した後、私は間違いなくHapiがこれを達成したと感じています。私は...幸せを感じます!

エラン・ハンマー(ハピのリーダー)から直接聞きたい場合

過去4年間で、ハピは、大小を問わず、多くのプロジェクトで選択されるフレームワークに成長しました。hapiのユニークな点は、大規模な展開と大規模なチームに拡張できることです。プロジェクトが成長するにつれて、その複雑さも増加します-エンジニアリングの複雑さとプロセスの複雑さ。hapiのアーキテクチャと哲学は、絶えずコードをリファクタリングする必要なしに、増大する複雑さを処理します[続きを読む]

Hapiには同じ「スターパワー」がないため、Hapiを使い始めるのはExpressJほど簡単ではありません...しかし、快適に感じると、多くの走行距離が得られます。無数のExpressJを無責任に数年間使用した新しいハッカーとして、約2か月かかりました。あなたがベテランのバックエンド開発者であれば、ドキュメントの読み方を知っているでしょうし、おそらくこれにも気付かないでしょう。

Hapiドキュメントが改善できる領域:

  1. ユーザーを認証してセッションを作成する方法
  2. Cross-Origin-Requests(CORS)の処理
  3. ファイルのアップロード(マルチパート、チャンク)

どのような認証戦略を使用するか(基本認証、Cookie、JWTトークン、OAuth)を決定する必要があるため、認証はその中で最も難しい部分だと思います。セッション/認証ランドスケープが非常に断片化されていることは、技術的にはHapiの問題ではありませんが...私は彼らがこれのためにいくつかの手掛かりを提供したいと思います。それは開発者の幸せを大いに増加させるでしょう。

残りの2つは実際にはそれほど難しくありません。ドキュメントは少しだけ上手に書くことができます。


3

Hapiの概要またはHapi JSを選ぶ理由

Hapiは構成中心ですフレームワークに認証と承認が組み込まれていますそれは戦いでテストされた雰囲気でリリースされ、本当にその価値を証明していますすべてのモジュールは100%テストカバレッジを持っていますそれはコアHTTPから離れた最高レベルの抽象化を登録しますプラグインアーキテクチャ経由

Hapiの方がパフォーマンスが優れています。Hapiは別のルーティングメカニズムを使用しています。これにより、検索を高速化し、登録の順序を考慮することができます。それにもかかわらず、Expressと比較すると、それはかなり制限されています。また、Hapiプラグインシステムのおかげで、将来さまざまな方法でアプリケーションを支援するさまざまなファセットとサービスを分離することができます。

使用法

Expressと比較した場合、Hapiは最も推奨されるフレームワークです。Hapiは主に大規模なエンタープライズアプリケーションに使用されます。

エンタープライズアプリケーションの作成時に開発者がExpressを選択しない理由はいくつかあります。

ルートはExpressで作成するのが難しい

ほとんどの場合、ミドルウェアが邪魔になります。ルートを定義するたびに、コードをいくつでも書く必要があります。

RESTful APIの構築を検討している開発者にとって、Hapiは最良の選択です。Hapiにはマイクロサービスアーキテクチャがあり、特定のパラメーターに基づいて、あるハンドラーから別のハンドラーにコントロールを転送することもできます。Hapiプラグインを使用すると、ビジネスロジックを簡単に管理できる断片に分割できるため、HTTPをより高度に抽象化できます。

Hapiのもう1つの大きな利点は、設定を誤ると詳細なエラーメッセージが表示されることです。Hapiでは、デフォルトでファイルのアップロードサイズを設定することもできます。最大アップロードサイズが制限されている場合は、ファイルサイズが大きすぎることを伝えるエラーメッセージをユーザーに送信できます。これにより、ファイルのアップロードでファイル全体がバッファリングされなくなるため、サーバーがクラッシュするのを防ぐことができます。

  1. expressを使用して達成できることは何でも、hapi.jsを使用して簡単に達成できます。

  2. Hapi.jsは非常にスタイリッシュで、コードを適切に整理します。ルーティングがどのように行われ、コアロジックがコントローラーに配置されているかがわかると、間違いなくそれが気に入るでしょう。

  3. Hapi.jsは、トークンベースの認証からセッション管理など、広告であるhapi.js専用のいくつかのプラグインを公式に提供しています。これは、従来のnpmが使用できないことを意味するのではなく、それらすべてがhapi.jsによってサポートされています

  4. hapi.jsでコーディングすると、コードは非常に保守しやすくなります。


「ルーティングがどのように行われ、コアロジックがコントローラーに配置されるかを確認した場合...」コントローラの使用法を示すドキュメントに例はありません。すべてのルーティングの例では、関数であるハンドラープロパティを使用しています。この方法を、ルーティングにコントローラーを使用できるルーティングのためにLaravel(PHPフレームワーク)およびAdonisJs(Node.jsフレームワーク)が行うことと比較します。ルーティングにコントローラーを使用することを示すHAPIドキュメントの一部を見逃した可能性があります。したがって、この機能が存在する場合は、Laravelでのルーティングにコントローラーを使用することに慣れているので、この機能が役立ちます。
Lex Soft

1

最近ハピを使い始めて、とても満足しています。私の理由は

  1. テストが簡単です。例えば:

    • server.inject アプリを実行して、実行して聞くことなく応答を取得できます。
    • server.info 現在のURI、ポートなどを与えます
    • server.settings構成にアクセスします。たとえばserver.settings.cache、現在のキャッシュプロバイダーを取得します。
    • 疑わしい場合/testは、アプリまたはサポートされているプラ​​グインの任意の部分のフォルダーを見て、モック/テスト/スタブなどの提案を確認してください。
    • 私の感覚では、hapiのアーキテクチャモデルでは信頼できますが、たとえば検証できます。たとえば、私のプラグインは登録されていますか?モジュールの依存関係を宣言するにはどうすればよいですか?
  2. ファイルのアップロード、エンドポイントからのストリームの返送など、そのまま使用できます。

  3. 必須のプラグインは、コアライブラリと共に維持されます。たとえば、テンプレートの解析キャッシングなど。追加の利点は、重要なもの全体に同じコーディング標準が適用されることです。

  4. 健全なエラーとエラー処理。Hapi は構成オプション検証し、ルートの重複を防ぐために内部ルートテーブルを保持します。デバッグを必要とする予期しない動作の代わりにエラーが早期にスローされるため、これは学習中に非常に役立ちます。


-1

追加するポイントとして、Hapiはバージョン16以降から「http2」呼び出しのサポートを開始しました(私が間違っていなければ)。ただし、ExpressはExpress 4まで直接「http2」モジュールをサポートしていません。Express5のアルファ版で機能がリリースされていますが、


-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
    }
}

StackOverflowへようこそ。回答についてさらに詳しく教えてください。それがOPによって投稿された質問とどのように関連しているか。
Szymon Maszke

-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();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.