purescript-conveyorにBatch operationの機能を足した

追記

本記事のパッケージは現在メンテされておりません。

サーバー向けパッケージは再実装されたものがこちらにあります。

Bucketchain

はじめに

年が明けてますが、PureScript Advent Calendar 2017 - Qiitaの21日目の記事にしてしまいます。

前回、PureScriptでAPIサーバー用のパッケージつくってみた - oreshinyaのブログというようなAPIフレームワークをつくったことを記事にしましたが、 このフレームワークにBatch opearationの機能を足しました。 また、その際に全面的にソースコードを書き直したため、変更点を書きます。

Batch operationってなに

複数のエンドポイントを1回のリクエストで実行する機能です。

複雑なアプリケーションになると、ひとつの画面に必要なデータが非常に多岐に渡ります。 そのような状況下の中、ひとつのAPIで色々な多くのデータを返すか、単機能なAPIを複数回叩くかという選択をすることを最初に考えるかと思います。 このことに対して、何も対策的な仕組みを入れない場合、前者の場合はUIによりすぎたメンテのしにくいAPIによっていくし、後者は何度もリクエスト往復するのでとても時間がかかります。

こういったことに対して、数年前からBFFという概念が公に出るようになりました。 ただ、気合の入ったBFFをしなくても、単純なbatch operationだけでもあると、経験上、わりと快適になるため、自分で使うためのライトユースとして、この機能を足しました。

Servableのメンバの型が変わった

変更コミットたちです。

Batch operationを入れるために、Servableのメンバの型を変えました。 以前の型はserve :: c -> s -> Request -> Response -> String -> Maybe (Eff (http :: HTTP | e) Unit)で、新しい型はserve :: s -> c -> RawData -> Aff e Responderになります。

大きな変更点は、返り値の型となります。

以前の型では、serveの実行文脈の中でレスポンスをクライアントに返すことを期待した型付けでしたが、新しい型では、serveの文脈でレスポンスとなるデータをつくって返すだけになっています。

新しい型にしたことによって、batch operationの実装は、serveを指定された各エンドポイントのパラメータの配列を用いて、traverseして複数のレスポンスをまとめればいいだけになりました。

その他の変更

  • Request bodyのdecodeに関しては、purescript-simple-jsonに依存するように変更して、Readable型クラスを削除した
  • Respondable型クラスの全面的な書き直し
  • Handlerを削除して、普通にAffで動くように変更した
  • 関数の引数の順番とか数とか引数そのものを地味に変えた
  • まぁ、なんか色々書き直した

まだ改善できるところはある

現状は、各エンドポイントを順番に処理してるだけなので、concurrentに実行できるようにするとよりよさそうです。

使い方

ServableインスタンスBatch型で包んで初期化すれば、OKです。 リポジトリのサンプルコードとほぼコピペですが、以下のような感じで初期化します。

runWithContext config 777 $ Batch { contextTest, errorTest, rawDataTest, createBlog }

以下のようなデータをrequestのbodyとして、POST /batchにおくりつけると、

[
  {"path": "errorTest"},
  {"path": "contextTest"},
  {"path": "createBlog", "body": { "title": "hoge", "content": "うんち in batch" }},
  {"path": "rawDataTest", "body": "ろーでーた"}
]

以下のようにかえってきます。

[
    {
        "contentType": "application/json",
        "code": 500,
        "body": {
            "messages": [
                "Internal server error ;)"
            ]
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "yours": "777"
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "fuck": "title: hoge, content: うんち in batch requested."
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "yours": "\"ろーでーた\""
        }
    }
]