JSON Schemaで型を保証する基本 - API契約と設定ファイルを壊さない
最終更新日: 2026年4月19日
「フロントが期待するレスポンス形式とサーバが返すJSONがズレていて、undefined参照で画面が真っ白になった」 「設定ファイルのキー名をtypoしたまま本番デプロイした」。 こうした事故の大半はJSON Schemaによる型チェックで防げます。 この記事ではJSON Schemaの基本文法と、実際にAPIや設定ファイルを守るための実装パターンをまとめます。
図1: JSON Schemaはデータとコードの間の「契約書」
スキーマで弾けば、不正データがビジネスロジックまで到達しない
最小のスキーマ
ユーザー登録APIのリクエストを想定します。email と age が必須、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: バリデーション層の配置
TypeScriptの型と同期する
同じ情報を型とスキーマに二重メンテするのは地獄です。現実的な選択肢は2つ。
- スキーマから型を生成する:
json-schema-to-typescriptなどでビルド時に.d.tsを出力。 スキーマが真実の源(source of truth)になる。 - Zod / Valibot など「型とスキーマ一体型」のライブラリを使う: TypeScriptの型とバリデータが同じ宣言から導かれるため、手書きJSON Schemaより保守が楽。 必要なら
zod-to-json-schemaで外部公開用JSON Schemaを書き出せる。
既に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にマージされるのを防げます。
よくある落とし穴
type: "number"は小数を許す。 整数が欲しいならinteger。numberだと1.5も通る。requiredは配列、propertiesはオブジェクト。 これを逆に書くエラーが非常に多い。format: "date"はISO 8601のYYYY-MM-DD。 日本式の2026/04/19は通らない。nullを許したいならtype: ["string", "null"]。nullable: trueはJSON Schemaではなく OpenAPI 3.0 の拡張。- 巨大スキーマの参照は
$refで分割。 共通のUser型を1箇所に書き、各エンドポイントで$refする。
実装で使うツール
スキーマを書く前に、対象のサンプルJSONを整形して構造を把握するのが効率的です。JSON Formatter で整形後、 ネストの深さや繰り返し構造を見てからスキーマを設計すると抜けが減ります。 サンプルJSONから型を素早く作りたい場合はJSON to TypeScript で下書きを作り、 それをZodやJSON Schemaに書き換える方が手早いです。
まとめ
JSON Schemaは「データとコードの間の契約書」です。 APIリクエスト・レスポンス・設定ファイルの境界にバリデーション層を1枚置くだけで、 本番障害の相当数を未然に防げます。 ZodやOpenAPIを source of truth にしてスキーマを生成する運用に乗せれば、 型の二重管理コストも避けられます。