理系学生日記

おまえはいつまで学生気分なのか

json schema を jq で再帰的に処理し、省略されている `"type": "object"` を付与する

Qiita の json schema に"type": "object" がない

Qiita の API レスポンスは json schema で表現されています。

Go 用の struct を作るのが面倒だったので、この json schema を解析して struct を自動生成したら楽だろと思いまして、schematyper で解析しようと試みました。

github.com

しかしできない。解析に失敗する。 この失敗理由が何かというと、Qiita の json scheme には "type": "object" が省略されているんですよね。。。

  "properties": {
      "properties": {
        "client_id": {
          "description": "An unique ID to identify a registered client",
          "example": "a91f0396a0968ff593eafdd194e3d17d32c41b1da7b25e873b42e9058058cd9d",
          "pattern": "^[0-9a-f]{40}$",
          "type": "string"
        },
(snip)
      },
      "required": [
        "client_id",
        "scopes",
        "token"
      ],
      "title": "Access token"
ここに "type": "object" がない
    },

json schema 的には "type": "object" がなくても valid なようです。なぜなら、 properties key があればそれが object だとわかるから。 しかし、今回使おうとする schematyper が対応していないのでどうしようもない。手動で "type": "object" をつけるしかありません。

"type": "object" の付与

面倒なのは、"type": "object" をつけるべき階層はいくらでも深くなり得ることです。 これは人類がやるべきことではないので、なんとか楽をしなければならない。

jq での再帰的な処理戦略

JSON の処理というと jq なわけですが、jq の walk を使えば再帰的な処理が可能です。 今回は以下のようなコマンドを実行することで、 properties key がある object を再帰的に探し、当該の object に対して "type": "object" を付与するようにしました。

$ curl --silent --output schema.json https://qiita.com/api/v2/schema
$ jq 'walk(if type=="object" and has("properties") then .type|="object" else . end)' schema.json

walk(f) は引数として jq の関数 f を取ります。関数 f は、引数として JSON の要素を取ります。 ここでは、引数の要素が object であり、かつ、properties という key を保つ場合に "type": "object" を付与するように構成しました。

参考文献