Blog::kobaken

prove t/foo/bar/baz.t

型に厳しい言語とCpanel::JSON::XS::Typeで仲良く

この記事はPerl Advent Calendar 2018の10日目の記事です。

JSONをdecodeする時、例えば、123"123"は型に厳しい言語であれば、別々に扱いたいものです。 ですが、Perlでぼやっとencodeすると、これらをいっしょくたにしてしまいます。

例えば、次のコードは123とencodeされることを期待しても、"123"とencodeします。 これは、123perl内部の値のフラグが意図せず、文字列になり*1、encodeされてしまったからです。

use JSON::XS;

my $row = { id => 123 };
# ぼやっと hash key として触る
my %fg; $fg{$row->{id}} = 1;

print encode_json($row);
# => { "id":"123" }

これでは、型に厳しい言語と仲良くできませんね..! 型指定無くencodeしできるのは手軽ではありますが、decode側の言語が期待する型通りencodeできれば、異なる言語間で仲良くできそうです *2

ここでは、PerlCpanel::JSON::XS::Type を用いて、期待する型を定義し、encodeする方法について紹介します。

Cpanel::JSON::XS::Typeで型指定をしてencodeする例

早速ですが、型指定をしてencodeする例を示します。 次のコードは、{ id => JSON_TYPE_INT }という型指定をし、値を"123"という文字列でなく123という数値にencodeしています。

use Cpanel::JSON::XS;
use Cpanel::JSON::XS::Type;

# 型指定
my $type = { id => JSON_TYPE_INT };
print encode_json({ id => "123" }, $type);
# => { "id":123 }

encode_jsonの第二引数に型を指定しなければ、従来のencodeを行うので取り入れやすいのではないかと思います。

Cpanel::JSON::XS::Typeで型を定義する

JSONで期待される型は、基本型は数値、文字列、真偽値、nullの4種で、また構造を表現するため、配列、ハッシュがあります。 基本型は、それぞれ、JSON_TYPE_INT|JSON_TYPE_FLOAT、JSON_TYPE_STRING, JSON_TYPE_BOOL、JSON_TYPE_NULLという定数で表し、もし基本型がNULLを取りうるのであれば、_OR_NULL というsuffixを付けます。 配列、ハッシュは、[],{}というリテラル表現か、json_type_arrayofjson_type_hashofといった関数を用います。 詳細は、ドキュメントを確認ください。

例えば、このようなデータをencodeする例を考えてみます。

# http://dist.schmorp.de/misc/json/short.json
my $data = {
    'id' => undef,
    'params' => ['user1','we were just talking'],
    'array' => ['1',11.01,234,-5,1e5,1e7,!!1,!!0],
    'method' => 'handleMessage'
};

この場合、型は次のように定義できます。見たままの型定義で、特に理解に支障はないと思います。

my $type = {
    id     => JSON_TYPE_INT_OR_NULL,
    params => json_type_arrayof(JSON_TYPE_STRING),
    array  => json_type_arrayof(JSON_TYPE_INT_OR_NULL),
    method => JSON_TYPE_STRING,
};

この型を指定し、encodeすると次のようになります。

print encode_json($data, $type)
# => {"array":[1,11,234,-5,100000,10000000,1,0],"id":null,"params":["user1","we were just talking"],"method":"handleMessage"}

まとめ

  • decode側が期待する型通りに、Perlがencodeできない時がある
  • そこで、Cpanel::JSON::XS::Typeを用いて期待する型を指定する方法を紹介した

宣伝

YAPC::Tokyo 2019 が1/26(土) に開催されますね! 最高に楽しくなると思う!! ので、来て欲しいです!!!!

チケット販売期限が、今週末予定なので、買い逃しなく!!!!!!

yapcjapan.org

*1:SVが、IV→PVIVに変わった

*2:実際、JSON Schema、OpenAPI、Protcol Buffers、GraphQL といった中間表現を用意し、encode/decodeするコードを利用言語ごとに自動生成するアプローチで、言語間の境界を意識する経験をした人もいるかもしれません。