エディタでの入力補完だけに頼っていたところ、レビュアーが見落とした状態のJSON設定がマージされ、本番投入直前のステージング環境で検証エラーが出て青ざめたことがあります。それ以来「人の目」と「CIでの機械チェック」は必ず両方用意する、を徹底するようになりました。最終回では、その仕組み化までをまとめます。
実践例 — ページネーション付きAPIレスポンスの設計
PART 04までの内容を踏まえ、一覧取得APIのレスポンスを例に設計してみます。件数が可変な一覧は配列、メタ情報は固定キーのオブジェクトという使い分けです。
{
"data": [
{ "id": "1001", "name": "商品A", "price": 1200 },
{ "id": "1002", "name": "商品B", "price": 980 }
],
"pagination": {
"page": 1,
"perPage": 20,
"totalItems": 42,
"totalPages": 3
}
}
一覧本体はdataキーの配列にまとめ、ページ番号や総件数など「常に1組しか存在しないメタ情報」はpaginationという固定キーのオブジェクトに分離しています。IDを文字列にしているのはPART 03で触れた大きな整数の精度問題を避けるためです。この構造に対して、PART 04と同じ要領でJSON Schemaを1つ用意しておけば、フロントエンド・バックエンド双方が同じ契約を参照できます。
ローカルでの検証 — pre-commitフック
コミット前にローカルで検証できれば、CIで失敗する前に気づけます。Gitのpre-commitフックに構文チェックとスキーマ検証を仕込む例です。
#!/bin/sh
for f in $(git diff --cached --name-only | grep '\.json$'); do
jq empty "$f" || { echo "構文エラー: $f"; exit 1; }
done
ajv validate -s schemas/response.schema.json -d "data/response.json" || exit 1
CI(GitHub Actions)への組み込み
図1: 構文チェックとスキーマ検証の2段階をCIに組み込み、機械的にマージ可否を判定する
ローカルのpre-commitフックは開発者が任意にスキップできてしまうため、最終防衛ラインとしてCIにも同じチェックを組み込みます。
name: JSON Validate
on:
pull_request:
paths:
- "**/*.json"
jobs:
json-validate:
runs-on: ubuntu-latest
steps:
- name: リポジトリをチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: "20"
- name: jq のインストール確認
run: jq --version
- name: 構文チェック(全JSONファイル)
run: |
find . -name "*.json" -not -path "./node_modules/*" \
-exec sh -c 'jq empty "$1" || exit 1' _ {} \;
- name: ajv-cli のインストール
run: npm install -g ajv-cli ajv-formats
- name: スキーマ検証
run: ajv validate -s schemas/response.schema.json -d data/response.json
このワークフローは*.jsonを含むPull Requestが作成・更新されるたびに実行され、構文エラーまたはスキーマ違反があればジョブが失敗としてマークされます。
ブランチ保護ルールとの組み合わせ
✅ Required status checksに指定する
GitHubリポジトリの Settings → Branches → Branch protection rules で「Require status checks to pass before merging」を有効にし、このjson-validateジョブを必須チェックに指定します。こうすることで、レビュアーが見落としても壊れたJSONやスキーマ違反のデータがmainブランチに混入すること自体を仕組みとして防げます。
⚠️ スキーマ自体もレビュー対象にする
スキーマファイルの変更は「検証ルールそのものの変更」であり、通常のコード変更以上に慎重なレビューが必要です。additionalProperties: falseを緩めるような変更は、意図しないデータの混入を許してしまう可能性がある点に注意してください。
シリーズ全体のまとめ
全5回を通して、JSONの特徴からツール導入、基本文法、構造設計・スキーマ検証、そしてCIでの自動化までを解説してきました。
| PART | 内容 |
|---|---|
| 01 | JSONの特徴、用途、YAML/XMLとの比較 |
| 02 | 整形・検証ツールとエディタ拡張機能の導入 |
| 03 | 基本文法とデータ型、実務で誤りやすいポイント |
| 04 | 構造設計の指針とJSON Schemaによる検証自動化 |
| 05(本記事) | 実践例とCI組み込み、シリーズまとめ |
💡 最初の一歩は「jq empty をCIに1つ置くこと」
スキーマ設計やCI全体を作り込む前に、まずは構文チェックだけをCIに追加するところから始めれば、少なくとも「壊れたJSONがマージされる」事故は防げます。スキーマによる型・値域の検証は、運用しながら段階的に育てていけば十分です。
読んでいただきありがとうございました。ここで扱いきれなかったJSON Patch・JSON Merge Patchによる部分更新の設計や、大規模JSONのストリーミングパースについては、別シリーズで改めて扱う予定です。