ちょっとしたswagger spec(yaml, json)の取り扱いというか変換というか
過去に自分が作ったやつの使い方について。もう少しマシなものを考えてみたのでメモ。
yaml上のデータから一部分を取り出したい
こういうyamlがあるとする。swagger specの一部のようなもの。people,person,name,ageが定義されている。
# definitions.yaml definitions: people: items: $ref: "#/definitions/person" person: properties: name: $ref: "#/definitions/name" age: $ref: "#/definitions/age" name: type: string description: 名前 age: type: integer maximum: 100
この定義に$refによる参照が使われている。この$refを取り除くためにderefというコマンドを作っていた。
$ jsonknife deref --src definitions.yaml
結果はこうなる。
definitions: people: items: properties: name: type: string description: 名前 age: type: integer maximum: 100 person: properties: name: type: string description: 名前 age: type: integer maximum: 100 name: type: string description: 名前 age: type: integer maximum: 100
全てが展開される。この内personだけが欲しい場合には --ref
を使う。
$ jsonknife deref --src definitions.yaml --ref "#/definitions/person"
こういう結果になる。
properties: name: type: string description: 名前 age: type: integer maximum: 100
取り出した結果をwrapしたい場合
--ref
によりyamlのデータの中から一部だけ取り出せはしたものの。 #/definitions/person
の位置にあるデータを取り出すということになってしまう。
今までこういう時に再度 definitions/person でラップするために、別のコマンドに渡していた。以下の様な形。
$ jsonknife deref --src definitions.yaml --ref "#/definitions/person" | dictknife transform --code 'lambda d: {"definitions": {"PERSON": d}}'
結果はこう。
definitions: PERSON: properties: name: type: string description: 名前 age: type: integer maximum: 100
もちろん、結果は期待通りなのだけれど。わざわざこの種の変換を手書きするのも面倒くさい。単に包むだけなのだからオプションにしてしまえば良い。元の階層に復元する処理をwrapと呼ぶとすればrefで取り出すことはunwrapにほかならない。そんなわけでwrapとunwrapで指定できるようにしてみると良いかもしれない。
$ jsonknife deref --src definitions.yaml --unwrap "#/definitions/person" --wrap "#/definitions/PERSON"
definitions: PERSON: properties: name: type: string description: 名前 age: type: integer maximum: 100
複数の値を同時に返す場合
全体に対するある部分の内、複数の部分の値が欲しい場合がある。例えば、nameとageを名前付きで欲しい場合。すごく真面目にやるならconcatを使う形になる。 プロセス置換なども使ってすごく頑張った見た目になるけれど。これで上手くいく。
$ dictknife concat <(jsonknife deref --src definitions.yaml --unwrap "#/definitions/name" --wrap "name") <(jsonknife deref --src definitions.yaml --unwrap "#/definitions/age" --wrap "age")
name: type: string description: 名前 age: type: integer maximum: 100
ところで、--ref
は複数渡せた。過去には --with-name
というオプションがあり。これによって名前でラッピングされた結果がマージされて返されていた(今は存在していないオプション)。上と同様のものを以下の様に書けた。ただ元の名前でラップするだけなので全くおんなじというわけではない。
# 今は動かない jsonknife deref --src definitions.yaml --ref "#/definitions/name" --ref "#/definitions/age" --with-name
ここでdefinitionsで包みたい場合に結局またdictknife transformによる同様の変換が必要になる。またwrap,unwrapの対応を数を数えてペアにするというのも馬鹿馬鹿しい。結局以下の様に書けるようにした。unwrapとwrapのペアを@でつなげるという記法。
jsonknife deref --src definitions.yaml --ref "#/definitions/name@#/definitions/NAME" --ref "#/definitions/age@#/definitions/AGE"
結果はこう。
definitions: AGE: type: integer maximum: 100 NAME: type: string description: 名前