1

私の目標は、Express.jsサーバー用の純粋なルートを書くことです。それも可能ですか?機能プログラミング(純粋なルート)を使用したExpress.jsサーバー

データベースにアクセスするには、素敵なFutureモナドを使用して純粋な状態を保つことができますが、ルートレンダリング自体はどうですか?

私が発見しています最大の問題の一つは、ルートのようなかなりの数の異なる方法で終わるかもしれないということです:

  • エラーリターン
  • JSONリターンをレンダリング

    • リダイレクト
    • テンプレート
    • ファイルを返します

    Futureモナド、私はエラーと成功のケースを処理することができますが、それ以降の成功事例にはそれほど細かくはありません。

    Express.jsの純粋で完全にテスト可能なルートを書く方法はありますか?

  • +1

    あなたが作業しようとしているルートのコード例をいくつか提出する必要があります。 – naomik

    +0

    ショッピングカート内のすべてのアイテムを表示するために、ルートのような単純なものがあります。 'res.render'や' res.redirect'を呼び出すことや、 'res.local'に値を代入することもすべて不純なものであることを考えると、純粋な方法で実装する方法を見てみたいと思います。これらのケースを処理する純粋な関数をどのように作成できますか? –

    +0

    @MarceloLazaroni、[here](https://gist.github.com/beardedtim/d54bf38a02ceb4df81f71c5ff52deddf)は、ルートをより機能的にするために私が試みていることの概要です。 –

    答えて

    2

    短い回答:いいえ - それはできません。

    説明:関数型プログラミングの文脈では 、我々はデータの流れを持っている - プログラムはそれを変換、いくつかの入力データを受け取り、出力データを返します。

    サーバーの場合、の2つのデータフローがあります。まず、サーバーを起動するときです。この流れでは、ポート、ホスト、データベース文字列などの設定ファイルやコマンドラインパラメータを外部の世界から読んでみるのもいいかもしれません。これは副作用であり、通常はこれをFutureに入れます。例:

    readJson(process.argv[2]) // Read configuration file 
        .chain(app)    // Get app instance (routes, middlewares, etc.) 
        .chain(start)    // Start server 
        .run().promise() 
         .then((server) => info(`Server running at: ${server.info.uri}`)) 
         .catch(error); 
    

    これはすべての副作用(読み取り設定)を含む典型的なindex.jsファイルです。次に、2番目のデータフローを見てみましょう。

    このデータフローは少し想像がつきません。最初のデータフローの出力/副作用は、サーバが外部接続のために一部のポートでリッスンすることです。 ここでは、すべてのリクエストがこのサーバーに1つの独立したデータフローとして送信されることを想像してください。

    だけなどのindex.jsは、このルートハンドラに戻って答えれるべき副作用、すなわち結果要求を処理するために意図されたすべての副作用を処理することを意図したファイル、あなたのルートファイルまたはルートハンドラ関数でした。一般的には、完全に近い機能ルートは次のようになります。

    function handler(request, reply) { 
    
        compose(serveFile(reply), fileToServe)(request) 
         .orElse((err) => err.code === 'ENOENT' ? reply404(reply) : reply500(reply)) 
         .run(); // .run() is the side effect 
    } 
    
    return { 
        method: 'GET', 
        path: '/employer/{files*}', 
        handler 
    }; 
    

    上記のスニペットではすべてが純粋です。汚いものは.run()メソッド(私はHapi.jsとFolktale.jsタスクを使用しています)です。

    AngularやReactのようなフロントエンドフレームワークと同じ考えがあります。これらのフレームワーク内のコンポーネントには、すべての影響/不純物が含まれている必要があります。ルートハンドラと同様のこれらのコンポーネントは、副作用が発生するエンドポイントです。あなたのモデル/サービスには不純物が含まれていないはずです。

    あなたのルートを完全に純粋にしたいなら、希望があります。あなたは、本質的にやりたいことはある - 抽象化のより高いレベル:Express.js場合

    1. その後、あなたはそれの上に独自の抽象化を構築する必要があり、フレームワークです。
    2. 通常、すべてのルートに対して独自の汎用ルートハンドラを作成し、独自のAPIを公開してルートを登録します。
    3. あなたのルートハンドラはfuture/task/observable、または空きを待っているすべての副作用を含む他のモナドを返します。
    4. 抽象化されたルートハンドラは、単に.fork()または.run()を呼び出します。
    5. ルートハンドラを単体テストすると副作用が発生しないということです。彼らは単に非同期モナドに包まれています。

    前述のように、フロントエンドフレームワークの場合、UIコンポーネントには副作用があります。しかし、この抽象化を超えた新しいフレームワークがあります。 Cycle.jsは私がを認識している1つのフレームワークです。 AngularまたはReactよりも高いレベルの抽象化を適用します。すべての副作用が観察可能な状態でケージに入れられ、それがフレームワークに送られ、コンポーネントを純粋にすべて(私は文字通り100%を意味します)実行します。

    私はHapi.js + Folktale.js + Ramdaを使用してサーバーを作成しようとしました。私のアイデアは、もともとCycle.jsに根付いています。しかし、私は軽度の成功を収めました。一部の部品コードは、書くのが本当に扱いにくく、制限がありませんでした。その後、私は純粋なルートを持つことをあきらめました。しかし、私のコードの残りは純粋であり、非常に読みやすいです。

    機能上のプログラミングでは、コーディング全体ではなく部分的なコーディングについて説明します。あなたや私がしようとしているのは、全体的に機能的なプログラミングです。 これは少なくともJavaScriptではほとんど気にしません。

    関連する問題