2019年7月15日月曜日

JSONとかいうもの

しばらく前からJSONとかRESTとかいうものがプログラムとか通信とかの間で使われるようになってきていたけど、全然追ってなかったのでいまさら追いかけた。 追いかけた足跡だけで細かいことは省略。
OpenIDを開いてみた気がする…。

JSONを広げる

 避けていたのは認証とかそういうところにたどり着かなかったから。今なら簡単に見つかりそうな気もする。 とりあえず仕様を探せ。JSONはRFC 8259が最新で最終版ともいわれている。ECMAの方にもECMA-404 2nd Edition というのがあるのでそれまでにあった差異などが解消されているとか。 名と値を文字列で書いたオブジェクトっぽいのがJSONの書式で、配列のもある。それだけ。JavaScriptとの受け渡しで相性がいいらしい。

RESTから関連機能を探す


 RESTは何だろうというと、HTTPやら何やらでJSONを通信する方法とでもいうか、HTMLの代わりにJSONが飛び交う。 どこで使われているのかというと、いろんなところで。XMLが流行ってたのは今は昔とでもいう勢いで。 各種サービス提供に使われているのはREST APIがほとんどらしいよ。と噂に聞いている。IoTの分野でも手軽にRESTで通信できるようになってる。人が間に入らないサービスはこういう方向でどんどん増えてもらいたい。
 RESTを使うのをRESTfulとかいうらしいよ。 ここまでは知ってた範囲。それで認証とかどうなのよというところで思考が停止。PKI使うのかBASIC認証使うのか、いろいろもやもやしてた数年前かな。
認証に使うのはRFC 2617 BASIC認証? とかCookieとかいろいろあった時代もあるようで。 RFC 7515-7519 というのがようやく安定してきた認証方法なのかな。この中からまずは JSON Web Token (JWT)を知ってみよう。PKIの基礎知識が必要。OAuth やOpenID Connect とやらもあるのであわせて後で調べる。

ABNFとJSON作ってみた

Javaで使うにはライブラリもあるのだろうけど、たまたま作りかけていたABNF(RFC 5234)で作ってみようと思ったらJSONの読み書きは簡単にできてしまったのでそういうことにしておく。
ABNFが何かというと、RFCで定義されているデータや何かの書式を書くための仕様で、プログラムで使うことはあんまり想定されていないけど作ってみたら案外使えなくもないしろもの。元はBNFという使いにくいものなんだけどRFC版のABNFは案外いろいろ書けるのでお得。曖昧な解釈とかも若干あるけども。EBNFとかBNFの派生にもいろいろあるけどまとめて実装しておいても使えないくらい他のは何もできないのでABNFは優秀。
ABNF自体もABNFで定義されているのでおもしろい。 プログラム上でもABNFを簡単にJavaにした形かABNFそのものですべての定義を書いている。

rulelist       =  1*( rule / (*c-wsp c-nl) )

というABNFの定義の一部を抜き出したサンプルと自作ライブラリの機能の紹介。
Javaでも次のように書けるので一部制限はあるものの、何も迷わない。

static ABNF rulelist = REG.rule("rulelist = 1*( rule / (*c-wsp c-nl) )";

事前の定義など省略するが、次のような書き方もできるようにした。パースする手間がない分起動が速い。

static ABNF rulelist = REG.rule("rulelist", rule.or(cWsp.x().pl(cNl)).ix());

文字列(ABNFtext)
static ABNF CRLF = ABNF.text("\r\n");
または ABNF CRLF = new ABNFtext("\r\n");

a / b / c は a.or(b,c)
a b c は a.pl(b,c) a.plus(b,c)はちょっと長いので縮めた
*element は element.x(0,-1) 略 element.x()
1*element は element.x(1,-1) 略 element.ix()
[element] は element.x(0,1) 略 element.c()
とJava中に手軽に書ける構造にしてみた。組み合わせも自由にできる。
a b c の構造は解析順序でどこまでをbに振ってどこからをcに振るのかなど複雑になることもあったので厳密版も作ってみたりしているが、改良版では厳密版の出番はまだない。

a*b element は element.x(a,b) と書く。
() はJavaの処理順で。
比較 Packetというデータの入れ物を昔から使っているのでそれの例

Packet pac = new Packet(data);
String str = "abc";
CRLF.is(pac) 判定(前方一致)
CRLF.is(str) 判定(前方一致)
CRLF.eq(pac) 判定(完全一致)
CRLF.eq(str) 判定(完全一致)
文字列でもどちらでも好きな方でデータの連結を考えて前方一致が使いやすそうなのでそれを基本に組み立てる。
テストで作ってみたのはRFC 3986 URIかな。 Parserまではまだ書いてない。

次のような注意点もあるのでABNFそのまま使えるわけではない点に注意。

RFC 2396 3.2.2. にある toplabel は原文では繰り返しとその後ろに alphanum が出てきてどちらなのかURIのパースで判定に困ることがあるので次のように修正してみたり。力業で読むこともできるのだけど。

 
原文 toplabel      = alpha | alpha *( alphanum | "-" ) alphanum ; BNF?

修正 toplabel      = alpha *( alphanum / ( "-" alphanum ) )     ; ABNF
 
ABNFは一旦略。
次はJSONのライブラリか。

JSONなどもABNFで定義されているのでちょちょっと追加するだけでABNFに加えBNF,EBNF,JSON,URL,URI,IMFなども使えるようになるのでRFCを収集しているところ。
JSONも基本はJSON構造を読んでJavaなら最終的にMapやListの階層構造と相互に変換できればいい。そういう作り方でいいんだろうか。ついでにBeanっぽいけどFieldを直接変換する作りも加えておいた。RESTの準備も進む。

各構文組み立てのためのParserはJavaで若干書くのだけど。構文解析の方はABNFのライブラリだけで可能。9割ぐらいABNF文に戻すこともでき処理順も目にやさしくなる。
ABNFを作ってからBNFとEBNFをさくっと作れたので、これくらいにしてJSONへ。

JSONはJavaScript Object なんとか RFC 8259 が最終形態らしい
オブジェクト、配列、Booleanや数値、文字、これくらいをシンプルに扱える。JavaScriptの内部表現的なものを誰かが発見して広まった、という解釈。
RFC 8259の式をそのままJavaに起こすだけで半分完成。ABNFのrulelistに流し込むだけでも同じ。JSONObjectとJSONArray、JSONValueなんていうクラスを作ってしまうとだいたい使える。Parserもさくっと中身の取り出し方に迷うくらいかな。
JSON→JSONObject→JavaのMap/List/配列→Object の相互変換が可能なくらいに仕上げてみた。
RFC 6901 JSON Pointer、RFC 6902 JSON Patch も動いた。
XMLよりJSONなのがよくわかる。

難しいのは文字コードの処理などかもしれない。JavaはUTF-8かUTF-16くらいで、UCSに変換とかサロゲートペアとか畳みかけてくるといろいろ面倒くさいが文字として扱えるよう注意してみた。
最初コンパイラでいうところの2PASSで実装したらしいABNFを1.5PASSくらいで書き直してみたりはした。 その他もろもろで初期から比べるとかなり速いがどっちが高速なのかは謎。
ABNFの拡張もいくつかあり、Parser書けばどこまででも対応はできるが、差分くらいで書けるようにしようとしてみるとどこまで対応していけるのか謎。
いろいろ言語的なものがさくっと作れるようになる、と期待。


https://github.com/okomeki にて公開中
RFC 7515から7519も作ってみないと次に進まない

 RFC 5234 Augmented BNF for Syntax Specifications: ABNF
  4. ABNFによるABNFの定義
  B.2.  Core Rules
 RFC 6901 JSON Pointer
 RFC 6902 JSON Patch
 RFC 7515 JSON Web Signature (JWS)
 RFC 7516 JSON Web Encryption (JWE)
 RFC 7517 JSON Web Key (JWK)
 RFC 7518 JSON Web Algorithms (JWA)
 RFC 7519 JSON Web Token (JWT)
 RFC 8259 JSON (本体)

0 件のコメント:

コメントを投稿

RaspberryPi 4 Model B 日本発売

RaspberryPi 4 Model B 4GBモデルがKSYから発売された。 今回の製造はOkdo社、RSコンポーネント関連の企業らしい。 電源、ケースなどのセットモデルもあるが、2GB、1GBモデルは未定となっている。 その他の取り扱いがありそうなショップはスイッチ...