Canonical な JSON エンコーディング

あるデータ表現を JSONエンコーディングする際、常に同じキーの順番でエンコーディングして欲しいことがあります。 例えば JSON Web Token (参考) は JSON 文字列をトークンとして用いるので(正確には更に Base64 エンコーディングしたもの)、 中身は同じ内容でも JSON へのエンコーディングの仕方によっては最終的なトークン文字列が異なるものになってしまいます。 特に Perl の場合は Perl v5.18 からハッシュのランダム化 がされるので、 JSON エンコーディングする度に異なる文字列が得られる可能性が高いです。

Canonical JSON

常に同じキーの順番でエンコーディングされる JSON のことを Canonical (正準) JSON と言ったりするそうです。 Perl では JSON.pm の canonical メソッドCanonical モードにすることが出来ます。

use JSON;

my $json = JSON->new->canonical;

Example

#!/usr/bin/env perl

use strict;
use warnings;
use v5.18;

use JSON;

for (1..3) {
    my $hash = +{ foo => 1, bar => 2, baz => 3 };
    say JSON->new->encode($hash);
}

say '';

for (1..3) {
    my $hash = +{ foo => 1, bar => 2, baz => 3 };
    say JSON->new->canonical->encode($hash);
}

結果

{"bar":2,"baz":3,"foo":1}
{"foo":1,"baz":3,"bar":2}
{"baz":3,"bar":2,"foo":1}

{"bar":2,"baz":3,"foo":1}
{"bar":2,"baz":3,"foo":1}
{"bar":2,"baz":3,"foo":1}

CanonicalJSON は常にキーでソートされた順番でエンコーディングされていることがわかると思います。 JSON Web Token など常に同じ JSON 文字列を期待する場面では Canonical JSON を使用しましょう。