Python の JSON Schema ライブラリ を使ったらなかなか便利だったので Erlang 版を使って見ます。
for-GET/jesse: jesse (JSon Schema Erlang) is an implementation of a JSON Schema validator for Erlang.
- JSON Scheam ライブラリ
- JSON ライブラリ
jesse は Draft バージョン 4 まで対応しています。
まずは rebar.config の deps に jsone と jesse を指定します
{deps,
[
{jsone,
".*", {git, "git@github.com:sile/jsone.git", {branch, "master"}}},
{jesse,
".*", {git, "git@github.com:klarna/jesse.git", {branch, "master"}}}
]
}.
基本的な流れは Schema の定義をして、あとはそれに JSON を食べさせるだけです。
%% スキーマの定義
> Schema = jsone:encode([{<<"properties">>, [{<<"a">>, [{<<"type">>, <<"integer">>}]}, {<<"b">>, [{<<"type">>, <<"string">>}]}, {<<"c">>, [{<<"type">>, <<"boolean">>}]}]}]).
<<"{\"properties\":{\"a\":{\"type\":\"integer\"},\"b\":{\"type\":\"string\"},\"c\":{\"type\":\"boolean\"}}}">>
%% バリデーション成功
> jesse:validate_with_schema(Schema, <<"{\"a\": 1, \"b\": \"b\", \"c\": true}">>, [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
{ok,[{<<"a">>,1},{<<"b">>,<<"b">>},{<<"c">>,true}]}
%% b が string ではなくて integer なのでエラーになっている
> jesse:validate_with_schema(Schema, <<"{\"a\": 1, \"b\": 1, \"c\": true}">>, [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
{error,[{data_invalid,[{<<"type">>,<<"string">>}],
wrong_type,1}]}
面倒な JSON バリデーションがこれで少しは楽になると思います。
また jesse は JSON Schema の管理機能も付いています。
%% Schema を設定する
> Schema = jsone:encode([{<<"properties">>, [{<<"a">>, [{<<"type">>, <<"integer">>}]}, {<<"b">>, [{<<"type">>, <<"string">>}]}, {<<"c">>, [{<<"type">>, <<"boolean">>}]}]}]).
<<"{\"properties\":{\"a\":{\"type\":\"integer\"},\"b\":{\"type\":\"string\"},\"c\":{\"type\":\"boolean\"}}}">>
%% コールバック付きで Schema を登録する
> jesse:add_schema(spam, Schema, [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
ok
%% スキーマに対して処理をする
> jesse:validate(spam, <<"{\"a\": 1, \"b\": 1, \"c\": true}">>, [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
{error,[{data_invalid,[{<<"type">>,<<"string">>}],
wrong_type,1,
[<<"b">>]}]}
%% 存在しないスキーマを呼び出したときのエラー
> jesse:validate(egg, <<"{\"a\": 1, \"b\": 1, \"c\": true}">>, [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
{error,{database_error,egg,schema_not_found}}
この機能を使えばサーバ起動時にスキーマを全て読み込んでおき後は jesse:validate/2 を呼び出すだけになります。
複数の型を定義する
戻りのパターンが二種類ある場合に使う
1> Schema = jsone:encode([{type, [<<"null">>, <<"object">>]}, {properties, [{a, [{type, <<"integer">>}, {required, true}]}]}]).
<<"{\"type\":[\"null\",\"object\"],\"properties\":{\"a\":{\"type\":\"integer\",\"required\":true}}}">>
2> jesse:validate_with_schema(Schema, jsone:encode(null), [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
src/jesse.erl:207:<0.32.0>: ParsedSchema = [{<<"type">>,[<<"null">>,<<"object">>]},
{<<"properties">>,
[{<<"a">>,
[{<<"type">>,<<"integer">>},{<<"required">>,true}]}]}]
src/jesse.erl:208:<0.32.0>: ParsedData = null
{ok,null}
3> jesse:validate_with_schema(Schema, jsone:encode([{a, 10}]), [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
src/jesse.erl:207:<0.32.0>: ParsedSchema = [{<<"type">>,[<<"null">>,<<"object">>]},
{<<"properties">>,
[{<<"a">>,
[{<<"type">>,<<"integer">>},{<<"required">>,true}]}]}]
src/jesse.erl:208:<0.32.0>: ParsedData = [{<<"a">>,10}]
{ok,[{<<"a">>,10}]}
4> jesse:validate_with_schema(Schema, jsone:encode([{b, 10}]), [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
src/jesse.erl:207:<0.32.0>: ParsedSchema = [{<<"type">>,[<<"null">>,<<"object">>]},
{<<"properties">>,
[{<<"a">>,
[{<<"type">>,<<"integer">>},{<<"required">>,true}]}]}]
src/jesse.erl:208:<0.32.0>: ParsedData = [{<<"b">>,10}]
{error,[{data_invalid,[{<<"type">>,
[<<"null">>,<<"object">>]},
{<<"properties">>,
[{<<"a">>,
[{<<"type">>,<<"integer">>},{<<"required">>,true}]}]}],
{missing_required_property,<<"a">>},
[{<<"b">>,10}],
[]}]}
5> jesse:validate_with_schema(Schema, jsone:encode([{a, <<"abc">>}]), [{parser_fun, fun(Binary) -> jsone:decode(Binary, [{format, proplist}]) end}]).
src/jesse.erl:207:<0.32.0>: ParsedSchema = [{<<"type">>,[<<"null">>,<<"object">>]},
{<<"properties">>,
[{<<"a">>,
[{<<"type">>,<<"integer">>},{<<"required">>,true}]}]}]
src/jesse.erl:208:<0.32.0>: ParsedData = [{<<"a">>,<<"abc">>}]
{error,[{data_invalid,[{<<"type">>,<<"integer">>},
{<<"required">>,true}],
wrong_type,<<"abc">>,
[<<"a">>]}]}
Top comments (0)