※ 「JSON Schema からドキュメントを生成する」ではなく,「ドキュメントから JSON Schema を生成する」です.
はじめに
SDD (Specification Driven Development) では,Swagger,RAML といった API 定義フォーマットや,JSON Schema といった JSON Object 定義フォーマットなどがよく利用されます.これらのフォーマットからコードジェネレートしつつ,ドキュメントも生成することで,仕様と実装の乖離がなくなるといったメリットがあります.
よく見かけるのは,JSON (YAML) をソースとして管理し,それから HTML ドキュメントを生成するようなものですが,エンジニア以外のステークホルダがいる環境で運用するにあたっては,HTML のホスティングサーバを用意したり,それをアップデートし続けるジョブを用意したりと少々面倒なこともあります.
そこで今回は,JSON からドキュメントを生成するのではなく,ドキュメントから JSON を生成する ことで,上記の解決を試みます.ドキュメントはマークダウンで記述します.GitHub などは,マークダウンを HTML に変換して表示してくれるので,記述したマークダウンそのものがドキュメントとなります.つまり,ドキュメントが生成物ではなくソースになるため,GitHub などでソース管理するだけで,常に最新のドキュメントを閲覧することができます.
mdconf を使って JSON にパースする
例として,以下のような JSON Schema を利用します.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "user",
"type": "object",
"additionalproperties": "false",
"required": [
"id",
"lastName",
"firstName",
"state"
],
"properties": {
"id": {
"type": "number"
},
"lastname": {
"type": "string"
},
"firstname": {
"type": "string"
},
"state": {
"type": "number",
"enum": [
"1",
"2"
]
}
}
}
マークダウンをパースして JSON にするために, mdconf を使います.mdconf では,#
と -
を用いてプロパティや値を表現します.これらのいずれも付いていない行はパースの対象外なので,自由に記述することができます.
以下は,上記の JSON Schema を生成するマークダウンを記述したものになります.
- $schema: http://json-schema.org/draft-04/schema#
- id: user
- type: object
- additionalProperties: false
# required
- id
- lastName
- firstName
- state
# properties
## id
user id
- type: number
## lastName
user's last name
- type: string
## firstName
user's first name
- type: string
## state
user state
- type: number
### enum
active
- 1
inactive
- 2
GitHub では,以下のように表示されます.スキーマ定義が見やすいドキュメントになっていますね.このドキュメントをメンテナンスしていくことになります.
以下が,このマークダウンをコードで利用し,バリデーションをおこなう例です.mdconf により簡単にパースすることができます.
import fs from 'fs'
import path from 'path'
import isMyJsonValid from 'is-my-json-valid'
import parse from 'mdconf'
import assert from 'assert'
// マークダウンを読み込み, JSON にパース
const mdFilePath = path.resolve(__dirname, 'user.md')
const schema = parse(fs.readFileSync(mdFilePath, 'utf8').toString()))
const userData = { id: 1, lastName: 'Yamada', firstName: 'Taro', state: 1 }
// データが想定しているフォーマットかどうか検証
const validator = isMyJsonValid(schema)
assert(validator(userData), validator.errors)
おわりに
マークダウンで Schema 定義を記述することで,ドキュメントとして利用しつつ,かつコードからも直接利用することができるようになりました.少々アグレッシブではありますが,Swagger や RAML などでも汎用的に使える方法ですので,興味を持たれた方はぜひ試してみてください.