DevToolBox

JSON Schemaで型を保証する基本 - API契約と設定ファイルを壊さない

最終更新日: 2026年4月19日

「フロントが期待するレスポンス形式とサーバが返すJSONがズレていて、undefined参照で画面が真っ白になった」 「設定ファイルのキー名をtypoしたまま本番デプロイした」。 こうした事故の大半はJSON Schemaによる型チェックで防げます。 この記事ではJSON Schemaの基本文法と、実際にAPIや設定ファイルを守るための実装パターンをまとめます。

Most "undefined is not a function" bugs and broken config files come from mismatched shapes between what the producer sends and what the consumer expects.JSON Schema codifies that contract. This guide coverstype, required, enum, additionalProperties, validating with Ajv, and wiring schema checks into CI so a malformed payload never ships to production.

図1: JSON Schemaはデータとコードの間の「契約書」

データ
APIレスポンス / 設定ファイル / フォーム入力
JSON Schema
型・必須・値域を宣言的に定義
アプリ
検証に通ったデータだけを処理

スキーマで弾けば、不正データがビジネスロジックまで到達しない

最小のスキーマ

ユーザー登録APIのリクエストを想定します。emailage が必須、age は0〜150の整数という契約です。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["email", "age"],
  "properties": {
    "email": { "type": "string", "format": "email" },
    "age":   { "type": "integer", "minimum": 0, "maximum": 150 }
  },
  "additionalProperties": false
}

ポイントは additionalProperties: false です。 これを付けないと未知のキーが紛れても通ってしまい、typoに気付けません。 逆に拡張を許したい場合は明示的に true を指定します。

よく使うキーワード早見表

キーワード用途
type基本型の指定string, integer, boolean, array, object, null
required必須プロパティの配列["id", "name"]
enum許可する値を列挙["draft", "published"]
const単一の固定値"v2"
pattern正規表現での検証"^[A-Z]{3}$"
minimum / maximum数値の範囲価格なら 0 以上
minLength / maxLength文字列の長さパスワード長の下限など
format意味的な型(検証は実装依存)email, uri, date-time, uuid
additionalProperties未知キーを許すか基本 false 推奨

Node.jsでAjvを使って検証する

実務で最も使われるバリデータは Ajv。 Fastify や tRPC のバリデータ層の中身もAjvです。

import Ajv from "ajv";
import addFormats from "ajv-formats";

const ajv = new Ajv({ allErrors: true, strict: true });
addFormats(ajv); // format: email / uri などを有効化

const schema = {
  type: "object",
  required: ["email", "age"],
  properties: {
    email: { type: "string", format: "email" },
    age:   { type: "integer", minimum: 0, maximum: 150 },
  },
  additionalProperties: false,
};

const validate = ajv.compile(schema);
const data = { email: "test@example.com", age: 30 };

if (!validate(data)) {
  console.error(validate.errors);
  // [{ instancePath: "/age", message: "must be <= 150", ... }]
}

allErrors: true で「全エラーをまとめて返す」動作になります。 デフォルトだと最初のエラーで打ち切るため、フォーム検証用途では基本有効化しておくのが無難です。

図2: バリデーション層の配置

クライアント(ブラウザ・SDK)
↓ リクエスト
✔ JSON Schemaバリデーション
不正なら400 Bad Requestで即返す
↓ 通過したリクエストのみ
ビジネスロジック / DB
↑ レスポンス
✔ レスポンスも検証(契約テスト)
サーバ側の破壊的変更に早期に気付ける

TypeScriptの型と同期する

同じ情報を型とスキーマに二重メンテするのは地獄です。現実的な選択肢は2つ。

既にOpenAPIを運用しているなら、その中にJSON Schemaがそのまま含まれているため、 OpenAPI定義をsource of truthにしてクライアント型・バリデータを生成する方が一貫します。

設定ファイル(tsconfig.json / package.jsonなど)を守る

VS Codeは $schema フィールドを尊重するため、自作の設定ファイルでも スキーマを設置すれば補完・型チェックが効きます。

// app.config.json
{
  "$schema": "./app.config.schema.json",
  "port": 3000,
  "logLevel": "info"
}

CIでは ajv validate -s schema.json -d config.json をpre-commitまたはPRチェックに組み込むと、 設定ファイルのtypoがmainにマージされるのを防げます。

よくある落とし穴

実装で使うツール

スキーマを書く前に、対象のサンプルJSONを整形して構造を把握するのが効率的です。JSON Formatter で整形後、 ネストの深さや繰り返し構造を見てからスキーマを設計すると抜けが減ります。 サンプルJSONから型を素早く作りたい場合はJSON to TypeScript で下書きを作り、 それをZodやJSON Schemaに書き換える方が手早いです。

まとめ

JSON Schemaは「データとコードの間の契約書」です。 APIリクエスト・レスポンス・設定ファイルの境界にバリデーション層を1枚置くだけで、 本番障害の相当数を未然に防げます。 ZodやOpenAPIを source of truth にしてスキーマを生成する運用に乗せれば、 型の二重管理コストも避けられます。

English summary

JSON Schema defines the shape your API or config file must follow. Start withtype, required, and properties; useenum for closed sets and additionalProperties: false to reject typos. Validate at the boundary with Ajv and run the schema check in CI. The real leverage is catching contract violations early — before an undefined crashes the UI or a typoed config reaches production.

関連ツール・ガイド / Related tools & guides