Jasonは、Elixir開発者のひとりMichał Muskała氏により純粋なElixirで書かれた最速のJSONパーサおよびジェネレータです。他のライブラリ、とくにPoisonより少なくとも2倍高速です。CでNIFとして実装されているjiffyにも劣りません(処理時間は2倍程度に収まります)。本稿はMuskała氏の許諾を得て、JasonライブラリのREADME.mdにもとづいてその内容をご紹介します。
パーサとジェネレータは、ともにRFC 8259とECMA 404規格に完全に準拠しています。また、パーサーは、JSONTestSuiteを用いてテストされています。
インストール
このパッケージをインストールするには、mix.exsのdepsに依存関係としてjasonを加えてください。
def deps do
[{:jason, "~> 1.1"}]
end
基本的な使い方
Jasonによるエンコードとデコードのコードは、たとえばつぎのとおりです。詳しくは、Jasonのドキュメントをご参照ください。
iex> Jason.encode!(%{"age" => 44, "name" => "Steve Irwin", "nationality" => "Australian"})
"{\"age\":44,\"name\":\"Steve Irwin\",\"nationality\":\"Australian\"}"
iex> Jason.decode!(~s({"age":44,"name":"Steve Irwin","nationality":"Australian"}))
%{"age" => 44, "name" => "Steve Irwin", "nationality" => "Australian"}
他のライブラリとの使い方
Postgrex
lib内の.exファイルで、Postgrex.Types.define/3によりカスタムの型を定めなければなりません。
Postgrex.Types.define(MyApp.PostgresTypes, [], json: Jason)
## Ectoで使うときはデフォルト拡張を渡さなければなりません
Postgrex.Types.define(MyApp.PostgresTypes, [] ++ Ecto.Adapters.Postgres.extensions(), json: Jason)
これで、Postgrex.start_link/1にモジュールを渡せば使えるようになります。
Ecto
EctoアプリケーションでPoisonの現行の動作を完全に再現するには、config/config.exs内でJasonをデフォルトエンコーダに定めなければなりません。
config :ecto, json_library: Jason
さらに、PostgreSQLを使う場合は、config/config.exsまたはconfig/<env>.exsにカスタム型モジュールを定めてください。
config :my_app, MyApp.Repo, types: MyApp.PostgresTypes
Plug (およびPhoenix)
まず、JSONの解析にJasonを用いるようPlug.Parsersに定めなければなりません。そして、Plug.Parsersプラグをどこに差し込むか決めます。Phoenixであれば、エンドポイントモジュールlib/app_web/endpoint.exに加えるコードは、たとえばつぎのとおりです。
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Jason
さらに、Phoenixではconfig/config.exsにエンコーダをつぎのように定めてください。
config :phoenix, :format_encoders,
json: Jason
Phoenixチャンネル用のカスタムJSONエンコーダはもう少し手間がかかります。カスタムシリアライザのコードとその使い方についてはjson_transport_serializer.exをご参照ください。
Absinthe
Absinthe.Plugに:json_codecオプションを定めてください。
# 直に呼び出すとき
plug Absinthe.Plug,
schema: MyApp.Schema,
json_codec: Jason
# Phoenixルータで使うとき
forward "/api",
to: Absinthe.Plug,
init_opts: [schema: MyApp.Schema, json_codec: Jason]
ベンチマーク
メモリの計測も含めたベンチマークはdecode.txtをご覧ください。HTMLのパフォーマンスレポートはjason/decode.htmlとjason/encode.htmlで公開されています。
実行
広く使われているElixirとErlangのJSONライブラリは、mix bench.encodeおよびmix bench.decodeでベンチマークが行われます。ベンチマークを実行した結果は、それぞれbench/output/encode.htmlとbench/output/decode.htmlでお確かめください。
Poisonとの違い
JasonはPoisonといくつか異なる機能があります。
- JSON仕様への準拠はより厳密です。
- JSON文字列内のエスケープされていない改行(たとえば"\"\n\"")はデコードエラーになります。
- データ構造へのデコード(
:asオプション)には対応しません。 -
MapSetとRangeおよびStreamの組み込みエンコーダーはありません。 - 任意の構造体へのエンコードはサポートされません。
-
Jason.Encoderプロトコルを明示的に実装してください。
-
- 高品質出力(デフォルト
pretty: true)のカスタマイズオプションが異なります。
サポートされていないコレクション型のエンコーダが必要な場合には、プロジェクトに直接追加することが推奨されます。
defimpl Jason.Encoder, for: [MapSet, Range, Stream] do
def encode(struct, opts) do
Jason.Encode.list(Enum.to_list(struct), opts)
end
end
プロトコルを実装していない構造体をエンコードしなければならないときは、どのフィールドをJSONにするのが実装で明示できます。
@derive {Jason.Encoder, only: [....]}
defstruct # ...
すべてのフィールドをエンコードすることもできます。けれど、新たなフィールドを加えるとき、誤ってプライベートな情報が漏れることのないように注意してください。
@derive Jason.Encoder
defstruct # ...
ライセンス
JasonはApache 2.0のライセンスでリリースされています。詳しくはLICENSEファイルをご参照ください。
テストとベンチマークについては、Poisonライブラリをもとにしています。このライセンスははじめCC0-1.0とされていました。
Top comments (0)