JSON Schema をバージョン管理する

2 min read読了の目安(約1800字

JSON Schemaをバージョン管理したいことがあったのでメモしておきます。

利用イメージ

1行目にschemaVersionを記すことで、バリデーションするスキーマのバージョンを切り替えます。

バリデーションしたい.yml
schemaVersion: 1.0.1
hogehoge: fugafuga
...以下略

ディレクトリ構造

root
├── meta.yml
└── schemas
    ├── v1.0.0
    │   └── config.yml
    ├── v1.0.1
    │   └── config.yml
    └── v1.1.0
        └── config.yml

というイメージです。

meta.yml

このファイルに各バージョンのschemaを結合させます (これをprmdでいうメタファイルとします)。

meta.yml
---
$schema: http://json-schema.org/draft-07/schema#
title: meta schema
description: バージョン管理するためのスキーマの枠
id: meta
allOf:
  - if:
      properties:
        schemaVersion:
          const: 1.0.0
    then:
      allOf:
        - $ref: "#/definitions/v1.0.0"
  - if:
      properties:
        schemaVersion:
          const: 1.0.1
    then:
      allOf:
        - $ref: "#/definitions/v1.0.1"
  - if:
      properties:
        schemaVersion:
          const: 1.1.0
    then:
      allOf:
        - $ref: "#/definitions/v1.1.0"
required:
  - schemaVersion
properties:
  schemaVersion:
    type: string
    enum:
      - 1.0.0
      - 1.0.1
      - 1.1.0
    description: スキーマのバージョン

allOfなどを用いることにより、結合してバージョン指定したときにそのバージョンのスキーマを強制します。
なお、バージョン番号として1.0などを用いると浮動小数点数として扱われてしまうため、"1.0"と記す必要があります。

config.yml

上の meta.yml に結合されます。
ファイル名は用途に合わせてください。何でもいいです。

v1.0.0/config.yml
id: v1.0.0
title: ...
definitions:
  foo: ...
  bar:
    type: object
    properties:
      foo:
        $ref: "#/v1.0.0/definitions/foo" # バージョンをベタ書きする必要がある。改良したい
required: ...
additionalProperties: false
type: object
properties:
  schemaVersion: # ここでも定義しないとエラーが出る。JSON Schemaの限界
    type: string
  ...

生成コマンド

JSON Schemaの結合などに用いられるgem、prmdを濫用します (要Ruby)。もっといいCLIを開発しても良さそうです。

prmd combine -m meta.yml schemas/ -o combined.json

これにより、combined.json にバージョン管理可能な JSON Schema が結合生成されます。