JSONエコシステムのイメージ

現代の開発で、JSONは単なるデータ形式を超えて、フロントエンドとバックエンドをつなぐ「契約」になっています。1つのJSONサンプルから、型定義・実行時バリデーション・API仕様書まで派生させられるのが、JSONエコシステムの強みです。

この記事では、1つのAPIレスポンスを例に、整形 → 型生成 → バリデーション → API定義という流れを実際のコードでつないで解説します。

出発点:1つのJSONレスポンス

次のようなユーザー情報のレスポンスを例にします。

{
  "id": 42,
  "name": "Alice",
  "email": "[email protected]",
  "roles": ["admin"],
  "createdAt": "2026-06-19T10:00:00Z"
}

このたった1つのサンプルが、以降すべての出発点になります。

ステップ1:整形して構造を把握する

実際に届くJSONは改行のない1行であることが多く、そのままでは構造を読み取れません。まずはJSON整形ツールで整形し、ネストの深さや配列の有無、各値の型を確認します。整形して初めて「roles は配列なのか単一値なのか」といった構造が見えてきます。

ステップ2:TypeScriptの型を生成する

構造が把握できたら、対応するTypeScriptの型を作ります。

interface User {
  id: number;
  name: string;
  email: string;
  roles: string[];
  createdAt: string;
}

JSON → TypeScript型生成を使えば、貼り付けるだけでこの型が手に入ります。これでコンパイル時の型チェックが効くようになります。

ステップ3:Zodで実行時の安全を担保する

TypeScriptの型はコンパイル時のチェックでしかありません。外部APIが本当に型どおりのデータを返す保証はなく、仕様変更やバグで形が崩れることもあります。そこで実行時バリデーションのためにZodスキーマを用意します。

import { z } from "zod";

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
  roles: z.array(z.string()),
  createdAt: z.string().datetime(),
});

// 型はスキーマから導出できる
type User = z.infer<typeof UserSchema>;

// 入口で検証する
const user = UserSchema.parse(await res.json());

z.infer を使えば、スキーマからTypeScriptの型を自動導出できるため、型とバリデーションを一元管理できます。不正なデータは parse の時点で例外として弾けます。

ステップ4:OpenAPIでチームの共通言語にする

最後に、同じJSONからAPI仕様書(OpenAPI / Swagger)のスキーマを起こせば、フロント・バック・QA・外部連携先で共有できる「共通言語」になります。

components:
  schemas:
    User:
      type: object
      properties:
        id:       { type: integer }
        name:     { type: string }
        email:    { type: string, format: email }
        roles:    { type: array, items: { type: string } }
        createdAt: { type: string, format: date-time }

JSON → OpenAPI定義生成で、このスキーマのたたき台を素早く作れます。ドキュメント作成の手間を減らし、設計議論に時間を使えます。

全体像:1つのJSONから広がる

   実際のJSONレスポンス

   ┌──────┼───────────┬──────────────┐
 整形    TS型      Zodスキーマ     OpenAPI
(把握) (静的検査) (実行時検査)  (仕様共有)

ポイントは、これらがバラバラの作業ではなく、1つのサンプルから派生する一連の流れだということです。実データを起点にすることで、ドキュメントと実装、型とバリデーションのズレを防げます。

よくある質問

TypeScriptの型があればZodは不要では?

型はコンパイル時にしか働かず、実行時に届くデータは検証しません。外部API・フォーム入力・LocalStorageなど「信頼できない入力」には、Zodなどの実行時バリデーションを併用すると安全です。内部だけで完結する信頼できるデータなら型だけでも構いません。

YAMLとJSON、どちらで管理すべき?

機械が処理するAPI通信はJSON、人間が編集する設定ファイル(CI/CDやKubernetesなど)はコメントが書けるYAMLが向いています。両者はJSON ⇔ YAML変換で相互変換できるので、用途に応じて使い分けられます。

1つのサンプルだけで型を作って大丈夫?

省略可能フィールドやnullになりうる項目は、1つのサンプルだけでは取りこぼします。できるだけフィールドが揃った代表的なレスポンスを使い、生成後に ?| null を仕様に合わせて補うのが確実です。