development·

Claude Code × API開発ガイド|スキーマファーストで設計から実装・テストまで一気通貫

Claude Codeを使ったバックエンドAPI開発の実践ガイド。OpenAPIスキーマファースト設計、データベース設計、認証・認可(JWT+RBAC)、Zodバリデーション、OWASP対策、テスト自動生成、マルチテナントSaaS実装まで、プロンプト例とコード例で解説します。

Claude Code × API開発ガイド|スキーマファーストで設計から実装・テストまで一気通貫

Claude Codeでフロントエンドのコンポーネントを生成した経験がある方は多いでしょう。しかし、バックエンドのAPI開発となると「どこまで任せられるのか」「設計の一貫性をどう保つのか」で迷うケースが少なくありません。フロントエンドと違い、バックエンドはデータベース設計、認証・認可、セキュリティ、テストなど考慮事項が多層にわたるためです。

本記事では、OpenAPI仕様を起点にしたスキーマファースト開発をClaude Codeで実践する方法を、設計から実装、テスト、ドキュメント生成まで一気通貫で解説します。単なるコード生成の話ではなく、CLAUDE.mdによる設計規約の永続化や、OWASP Top 10を意識したセキュリティ実装、さらにはマルチテナントSaaS APIの構築例まで踏み込みます。

Claude Codeの基本についてはClaude Codeとは?できること・料金・始め方を、全体像はClaude Code完全ガイドを参照してください。

この記事のポイント

  • OpenAPI仕様を先に設計し、実装・型定義・テスト・ドキュメントをすべて派生させるスキーマファーストのワークフローをClaude Codeで実現する
  • CLAUDE.mdにAPI設計規約を定義することで、セッションをまたいでも一貫した設計品質を維持できる
  • 認証(JWT)・認可(RBAC)・バリデーション(Zod)・エラーハンドリングの各レイヤーを体系的に構築する
  • OWASP Top 10:2021を意識したセキュリティ対策をClaude Codeで生成する方法を紹介する
  • マルチテナントSaaS APIの構築を実践例として、テナント分離やコンテキストミドルウェアの設計を解説する

Claude Code × バックエンド API開発の全体像

Claude Codeを使ったバックエンドAPI開発とは、AIコーディングエージェントにAPI設計・実装・テスト・ドキュメント生成を支援させるアプローチです。 単発のコード生成ではなく、設計思想を共有した上でプロジェクト全体を一貫して構築できる点が、スニペット生成ツールとの決定的な違いです。

なぜClaude CodeがAPI開発を変えるのか

バックエンドAPI開発の作業の大半は、実はパターン化されています。CRUD操作の実装、バリデーションスキーマの定義、エラーハンドリング、テストケースの記述。これらは「何をすべきか」が明確でありながら、書く量が多く時間を取られる作業です。

Claude Codeが効果を発揮するのは、まさにこの領域です。Claude Codeはプロジェクト全体のコードベースを読み取った上でコードを生成するため、既存の命名規則やディレクトリ構成に沿った一貫性のあるコードを出力します。さらに、後述するCLAUDE.mdの設計規約と組み合わせることで、この一貫性をセッション横断で維持できます。

ただし、Claude Codeに丸投げするだけでは品質は担保されません。重要なのは「設計を先に固めてからClaude Codeに実装を任せる」というスキーマファーストのアプローチです。

従来のAPI開発との比較で整理します。

観点従来の開発Claude Code活用
CRUD実装手動でボイラープレートを記述プロンプト1回でリソース全体を生成
バリデーションルールを手動で定義・型と二重管理Zodスキーマから型を自動推論
テスト実装後に手動で作成(後回しになりやすい)実装と同時にテストケースを生成
ドキュメント別途手動で作成・乖離が発生OpenAPI仕様から自動生成・同期
設計一貫性コードレビューで担保CLAUDE.mdの規約で構造的に担保

この表の各項目は、後続のステップで具体的に解説します。

スキーマファースト開発とは

スキーマファースト開発とは、OpenAPI仕様などのAPI定義を先に設計し、そこからバックエンド実装、フロントエンドの型定義、テストケース、ドキュメントを派生させるアプローチです。コードを書いてから仕様書を起こす「コードファースト」の逆のフローになります。

このアプローチがClaude Codeと相性が良い理由は明確です。OpenAPI仕様という「正解の定義」が先にあることで、Claude Codeが生成すべきコードの仕様が曖昧さなく伝わります。「ユーザー管理のAPIを作って」という曖昧な指示より、「このOpenAPI仕様に基づいてExpressのルートを実装して」という指示の方が、はるかに精度の高い出力を得られます。

スキーマファースト開発のワークフロー全体像は次のようになります。

OpenAPI仕様(設計の起点)
 ├→ TypeScript型定義(フロントエンド・バックエンド共通)
 ├→ Zodバリデーションスキーマ(入力検証)
 ├→ Prismaスキーマ(データベース)
 ├→ コントローラー・サービス(ビジネスロジック)
 ├→ テストケース(統合テスト・E2E)
 └→ Swagger UI / ドキュメント(API仕様公開)

すべてがOpenAPI仕様から派生するため、仕様変更があれば起点を修正してClaude Codeに再生成を依頼するだけで、プロジェクト全体の整合性を維持できます。

スキーマファースト開発の詳しい手法は仕様駆動開発 × Claude Code実践ガイドでも解説しています。

CLAUDE.mdにAPI設計規約を定義する

CLAUDE.mdにAPI設計規約を記述しておくと、Claude Codeがセッションをまたいでも一貫した命名規則・レスポンス形式・エラー体系でコードを生成します。 プロンプトで毎回指示する必要がなくなるため、チーム開発でも個人の指示スタイルに依存しない品質を維持できます。

なぜ設計規約をCLAUDE.mdに書くのか

API開発では「一貫性」がとりわけ重要です。エンドポイントの命名規則がリソースによって異なる、エラーレスポンスのフォーマットが統一されていない、といった不整合はAPIの利用者にとって大きなストレスになります。

CLAUDE.mdに規約を書く利点は、セッションが変わっても規約が引き継がれることです。新しいリソースのAPIを追加する際も、Claude Codeは既存の規約に従ってコードを生成します。チーム開発では、メンバーごとにプロンプトの書き方が異なっていても、CLAUDE.mdの規約がベースラインとして機能するため、生成されるコードの品質が均一化されます。

CLAUDE.mdに書くべき内容と書くべきでない内容の判断基準も重要です。API設計規約のように「プロジェクト全体で一貫して守るべきルール」はCLAUDE.mdに書きます。一方、特定のチケットに紐づく一時的な実装方針は、プロンプトで直接指示する方が適切です。

API設計規約の記述例

CLAUDE.mdに記述するAPI設計規約の例を示します。

## API設計規約

### 命名規則
- エンドポイント: ケバブケース、複数形(例: /api/v1/user-profiles)
- リクエスト/レスポンス: キャメルケース(例: userId, createdAt)
- HTTPメソッド: GET=取得, POST=作成, PUT=全置換, PATCH=部分更新, DELETE=削除

### レスポンス形式
- 成功: { data: T, meta?: { pagination } }
- エラー: { error: { code: string, message: string, details?: unknown[] } }
- ステータスコード: 200=成功, 201=作成, 400=バリデーション, 401=認証, 403=認可, 404=未存在, 500=サーバー

### バリデーション
- 入力バリデーションはZodスキーマで定義する
- ZodスキーマからTypeScript型を推論する(z.infer)
- エラーメッセージは日本語で記述する

### エラーコード体系
- VALIDATION_xxx: バリデーションエラー
- AUTH_xxx: 認証・認可エラー
- RESOURCE_xxx: リソース操作エラー
- SYSTEM_xxx: システムエラー

この規約がCLAUDE.mdに存在するだけで、Claude Codeは新しいエンドポイントを作成する際にも自動的にこの形式に従います。「エラーレスポンスの形式は?」と聞く必要がなくなるのです。

ステップ1 — OpenAPI仕様でAPI設計を始める

API開発の最初のステップは、実装ではなくOpenAPI仕様の設計です。 Claude CodeにOpenAPI仕様を生成させ、それをレビューしてから実装に進むことで、手戻りを大幅に減らせます。

要件定義からOpenAPI仕様を生成する

Claude Codeに以下のようなプロンプトを投げると、要件定義からOpenAPI仕様を生成できます。

以下の要件でOpenAPI 3.1仕様を生成してください。
CLAUDE.mdのAPI設計規約に従ってください。

## 要件
- タスク管理API
- リソース: ユーザー、プロジェクト、タスク
- ユーザーは複数のプロジェクトに所属できる
- タスクは1つのプロジェクトに属する
- タスクには担当者(ユーザー)を割り当てられる
- タスクのステータス: todo, in_progress, done

## 必要なエンドポイント
- ユーザー: CRUD + 所属プロジェクト一覧
- プロジェクト: CRUD + メンバー管理 + タスク一覧
- タスク: CRUD + ステータス変更 + 担当者変更

Claude Codeはこの要件から、パス定義、リクエスト/レスポンススキーマ、エラーレスポンスまで含んだOpenAPI仕様を生成します。生成された仕様をレビューし、過不足があれば対話的に修正していきます。

ここでのポイントは、最初から完璧な仕様を求めないことです。まずClaude Codeに骨格を生成させ、その上で「ページネーションのパラメータを追加して」「フィルタリングの仕様を詳細化して」と対話的に仕上げていく方が効率的です。Claude Codeはプロジェクト内のOpenAPI仕様ファイルを読み取れるため、前回の出力を踏まえた上で追加・修正を行えます。

また、APIバージョニング(/api/v1/)の設計もこの段階で決めておきます。後からバージョニングを追加すると、ルーティング構造の大幅な変更が必要になるためです。

型安全なコードの派生

OpenAPI仕様が確定したら、そこからTypeScriptの型定義やZodバリデーションスキーマを派生させます。

先ほど作成したOpenAPI仕様から以下を生成してください:
1. src/types/api.ts — リクエスト/レスポンスのTypeScript型
2. src/schemas/ — 各リソースのZodバリデーションスキーマ
3. Zodスキーマはz.inferで型推論できるようにする

このアプローチの利点は、OpenAPI仕様・TypeScript型・Zodスキーマが常に同期している点です。仕様変更があればOpenAPIを修正し、Claude Codeに型とスキーマの再生成を依頼するだけで、整合性を保てます。

この仕組みにより、仕様書・型定義・バリデーションスキーマの三重管理による変更漏れを構造的に解消できます。

ステップ2 — データベーススキーマの設計

OpenAPI仕様でAPIの「外側」を定義したら、次はデータベーススキーマで「内側」を設計します。 Claude CodeはOpenAPI仕様のリソース定義を読み取り、対応するPrismaスキーマを生成できます。

Prismaスキーマの自動生成

Claude Codeに以下のように依頼します。

OpenAPI仕様のリソース定義に基づいて、Prismaスキーマを生成してください。
- データベース: PostgreSQL
- リレーション: ユーザー↔プロジェクトは多対多、プロジェクト↔タスクは一対多
- 共通フィールド: id(UUID), createdAt, updatedAt
- 論理削除: deletedAtカラムで対応
- インデックス: 検索頻度の高いカラムに設定

Claude Codeは、OpenAPI仕様に定義されたリソースの構造を理解した上で、リレーションやインデックスを含むPrismaスキーマを生成します。APIレスポンスのフィールドとDBカラムの対応関係が自動的に保たれる点がスキーマファースト開発の強みです。

生成されたスキーマをレビューする際は、以下の点に注目してください。

  • リレーションの方向と多重度が要件と一致しているか
  • 論理削除(deletedAt)を使うテーブルと物理削除を使うテーブルの判断が適切か
  • String型のカラムに最大長の制約が設定されているか
  • Decimal型を使うべき箇所にFloat型が使われていないか(金額計算など)

Claude Codeは指示に忠実にスキーマを生成しますが、ビジネス要件に基づく判断(たとえば「この中間テーブルに追加属性が必要か」)は開発者が行うべきです。

マイグレーション・シーディング・インデックス設計

Prismaスキーマの生成後、Claude Codeにマイグレーションの実行とシードデータの作成を依頼できます。

1. prisma migrate dev で初回マイグレーションを実行してください
2. prisma/seed.ts にテスト用シードデータを作成してください
   - ユーザー3名、プロジェクト2件、タスク10件
   - リレーションを正しく設定する
3. 検索用インデックスの提案もお願いします

インデックス設計では、Claude Codeがクエリパターン(WHERE句やORDER BY句の頻出パターン)を推測し、適切なインデックスを提案します。典型的には、外部キーカラム、ステータスカラム、作成日時カラムなどにインデックスが設定されます。複合インデックスが必要なケース(テナントID + 作成日時でのソートなど)も、クエリパターンを伝えればClaude Codeが提案できます。

ただし、実際のクエリパターンはアプリケーション完成後に負荷テストで検証すべきです。Claude Codeの提案はあくまで初期設計の出発点として捉えてください。本番データの分布やアクセスパターンに基づくインデックス最適化は、EXPLAIN ANALYZEの結果を見ながら人間が判断する領域です。

ステップ3 — CRUD APIの実装

スキーマが整ったら、CRUD APIの実装に進みます。 OpenAPI仕様とPrismaスキーマの両方がプロジェクト内に存在する状態で依頼することで、Claude Codeは仕様とデータモデルの双方に整合したコードを生成します。

コントローラーとルーティングの生成

OpenAPI仕様とPrismaスキーマに基づいて、タスクリソースの
CRUDエンドポイントを実装してください。

- フレームワーク: Express + TypeScript
- ディレクトリ構造:
  - src/routes/tasks.ts(ルーティング)
  - src/controllers/tasks.ts(コントローラー)
  - src/services/tasks.ts(ビジネスロジック)
- コントローラーはリクエスト/レスポンスの変換のみ
- ビジネスロジックはserviceレイヤーに分離

レイヤー分離を明示的に指示することで、Claude Codeはコントローラーにビジネスロジックを混ぜない設計を維持します。この指示もCLAUDE.mdに書いておけば、全リソースで一貫した構造を保てます。

レイヤー分離の意義を補足します。コントローラーがHTTPリクエスト/レスポンスの変換のみを担当し、ビジネスロジックがサービスレイヤーに分離されていると、テストの書きやすさが格段に向上します。サービスレイヤーのテストはHTTP層を介さずに直接呼び出せるため、テストの実行速度も速くなります。Claude Codeにテスト生成を依頼する際も、レイヤーが分離されている方が的確なテストコードが生成されます。

また、1つのリソースのCRUD実装が完成したら、すぐに次のリソースを追加するのではなく、まず生成されたコードの品質を確認してください。最初のリソースの実装品質が高ければ、Claude Codeは2つ目以降のリソースでもその品質を維持します。逆に、最初の実装に問題があると、それが全リソースに伝播します。

バリデーション設計(Zod × 型推論)

バリデーションはAPIの信頼性を左右する重要なレイヤーです。Claude CodeはZodスキーマの生成に優れており、OpenAPI仕様から自動的にバリデーションルールを導出できます。

// src/schemas/tasks.ts
import { z } from "zod";

export const createTaskSchema = z.object({
  title: z
    .string()
    .min(1, "タイトルは必須です")
    .max(200, "タイトルは200文字以内で入力してください"),
  description: z
    .string()
    .max(2000, "説明は2000文字以内で入力してください")
    .optional(),
  projectId: z.string().uuid("プロジェクトIDの形式が不正です"),
  assigneeId: z.string().uuid("担当者IDの形式が不正です").optional(),
  status: z.enum(["todo", "in_progress", "done"]).default("todo"),
});

// Zodスキーマから型を推論 — OpenAPIの型定義と自動的に一致する
export type CreateTaskInput = z.infer<typeof createTaskSchema>;

Zodの z.infer でTypeScript型を推論することで、バリデーションスキーマと型定義の二重管理を避けられます。エラーメッセージを日本語で記述しておけば、フロントエンドでそのまま表示できます。

バリデーションの適用はミドルウェアとして共通化するのが定石です。Claude Codeに以下のような汎用バリデーションミドルウェアを生成させると、全エンドポイントで一貫したバリデーション処理を適用できます。

// src/middleware/validate.ts
import { Request, Response, NextFunction } from "express";
import { ZodSchema } from "zod";

export function validate(schema: ZodSchema) {
  return (req: Request, _res: Response, next: NextFunction) => {
    const result = schema.safeParse(req.body);
    if (!result.success) {
      throw result.error; // グローバルエラーハンドラーでキャッチ
    }
    req.body = result.data; // パース済みデータで上書き(型安全)
    next();
  };
}

safeParse を使い、エラー時は例外をスローしてグローバルエラーハンドラーに処理を委譲します。result.data で上書きすることで、バリデーション通過後の req.body が型安全になる点も重要です。

ステップ4 — 認証・認可の実装

認証(Authentication)は「誰なのか」、認可(Authorization)は「何ができるのか」を制御するレイヤーです。 Claude Codeは両方のミドルウェアを生成できますが、設計の意思決定は人間が行う必要があります。

JWT認証の構築

Claude Codeに認証ミドルウェアの生成を依頼する際は、トークン戦略を明示的に指示します。

JWT認証ミドルウェアを実装してください。

- アクセストークン: 有効期限15分、ペイロードにuserId/email/roleを含む
- リフレッシュトークン: 有効期限7日、DBに保存(取り消し可能にする)
- トークン検証はmiddleware/auth.tsに配置
- 環境変数: JWT_SECRET, JWT_REFRESH_SECRET
- パスワードハッシュ: bcrypt(ソルトラウンド10)

アクセストークンの有効期限やリフレッシュトークンの保存先は、セキュリティ要件に直結する設計判断です。Claude Codeは指示された通りに実装しますが、これらの値をどう設定するかは開発者が決めるべきポイントです。

一般的な推奨値として、アクセストークンは15〜30分、リフレッシュトークンは7〜30日が多く採用されています。リフレッシュトークンをDBに保存するのは、管理者がユーザーのセッションを即座に無効化できるようにするためです。JWTの署名検証だけでは、トークンの有効期限が切れるまでアクセスを遮断できません。

ロールベースアクセス制御(RBAC)

認証だけでは「ログインしているかどうか」しか判定できません。「管理者だけがプロジェクトを削除できる」「メンバーは自分のタスクだけ編集できる」といった制御にはRBACが必要です。

RBACミドルウェアを実装してください。

- ロール: admin, manager, member
- 権限マッピング:
  - admin: すべての操作
  - manager: プロジェクト内のCRUD + メンバー管理
  - member: 自分のタスクのCRUD
- ミドルウェアはルートごとに適用できる設計
- 自分のリソースかどうかの判定(ownership check)も含める

Claude Codeが生成するRBACミドルウェアの例を示します。

// src/middleware/authorize.ts
import { Request, Response, NextFunction } from "express";

type Role = "admin" | "manager" | "member";

interface AuthorizeOptions {
  roles: Role[];
  ownershipCheck?: (req: Request) => Promise<boolean>;
}

export function authorize(options: AuthorizeOptions) {
  return async (req: Request, res: Response, next: NextFunction) => {
    // req.user は認証ミドルウェアで設定される拡張プロパティ
    // 型定義例: declare global { namespace Express { interface Request { user?: { id: string; role: string } } } }
    const user = req.user;
    if (!user) {
      return res.status(401).json({
        error: { code: "AUTH_UNAUTHENTICATED", message: "認証が必要です" },
      });
    }

    // 簡略化のため型アサーションを使用。本番ではランタイム型ガードを推奨
    if (!options.roles.includes(user.role as Role)) {
      return res.status(403).json({
        error: { code: "AUTH_FORBIDDEN", message: "この操作を行う権限がありません" },
      });
    }

    if (options.ownershipCheck) {
      const isOwner = await options.ownershipCheck(req);
      if (!isOwner && user.role !== "admin") {
        return res.status(403).json({
          error: { code: "AUTH_NOT_OWNER", message: "自分のリソースのみ操作できます" },
        });
      }
    }

    next();
  };
}

このミドルウェアをルートに適用する形で、エンドポイントごとに柔軟な権限制御を実現します。ルートでの使用例を示します。

以下はルートでの使用例です(prismataskService などのimportは省略しています)。

// タスク削除: adminまたはタスクの作成者のみ
router.delete(
  "/tasks/:id",
  authenticate,
  authorize({
    roles: ["admin", "manager", "member"],
    ownershipCheck: async (req) => {
      // 実運用ではreq.params.idのUUIDバリデーションも行う
      const task = await taskService.findById(req.params.id);
      return task?.createdBy === req.user.id;
    },
  }),
  taskController.delete
);

ownershipCheck を省略すればロールだけで判定し、指定すれば「自分のリソースかどうか」の追加チェックが入ります。この柔軟性により、エンドポイントごとに異なるアクセス制御ポリシーを宣言的に記述できます。

ステップ5 — エラーハンドリングとセキュリティ

エラーハンドリングとセキュリティは、API の信頼性と安全性を決定する基盤レイヤーです。 この2つは後回しにされがちですが、設計段階から組み込むことで手戻りを防げます。

統一エラーレスポンス設計

APIのエラーレスポンスを統一することで、フロントエンドのエラーハンドリングが大幅に簡素化されます。CLAUDE.mdに定義したエラーコード体系に基づいて、Claude Codeにグローバルエラーハンドラーを生成させます。

// src/middleware/error-handler.ts
import { Request, Response, NextFunction } from "express";
import { ZodError } from "zod";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";

// Expressのエラーハンドラーは4引数が必須(3引数だと通常のミドルウェアとして扱われる)
export function errorHandler(
  err: unknown,
  _req: Request,
  res: Response,
  _next: NextFunction
) {
  // Zodバリデーションエラー
  if (err instanceof ZodError) {
    const details = err.errors.map((e) => ({
      path: e.path.join("."),
      message: e.message,
    }));
    return res.status(400).json({
      error: {
        code: "VALIDATION_FAILED",
        message: "入力内容に誤りがあります",
        details,
      },
    });
  }

  // Prisma固有エラー(一意制約違反など)
  if (err instanceof PrismaClientKnownRequestError) {
    if (err.code === "P2002") {
      return res.status(409).json({
        error: {
          code: "RESOURCE_DUPLICATE",
          message: "指定されたリソースは既に存在します",
        },
      });
    }
    if (err.code === "P2025") {
      return res.status(404).json({
        error: {
          code: "RESOURCE_NOT_FOUND",
          message: "指定されたリソースが見つかりません",
        },
      });
    }
  }

  // 想定外のエラー(本番環境ではpino等のロガーに置き換えてください)
  console.error("Unhandled error:", err);
  return res.status(500).json({
    error: {
      code: "SYSTEM_INTERNAL_ERROR",
      message: "サーバー内部エラーが発生しました",
    },
  });
}

エラーの分類(バリデーション / リソース操作 / システム)を体系化しておくことで、フロントエンドはerror.codeの接頭辞だけで表示方法を判断できます。

OWASP Top 10を意識したセキュリティ対策

OWASP Top 10:2021では、Broken Access Control(アクセス制御の不備)が引き続き1位に位置しています。API開発ではこれに加え、OWASP API Security Top 10 2023の脅威にも対策が必要です。

Claude Codeにセキュリティミドルウェアの生成を依頼する際は、具体的な脅威を列挙します。

以下のセキュリティ対策を実装してください。
OWASP Top 10:2021とAPI Security Top 10を意識してください。

1. レート制限(express-rate-limit)
   - 一般API: 100リクエスト/15分
   - 認証API: 5リクエスト/15分(ブルートフォース防止)

2. CORS設定(cors)
   - 許可オリジン: 環境変数 ALLOWED_ORIGINS から取得
   - credentialsを有効化

3. セキュリティヘッダー(helmet)
   - CSP, X-Content-Type-Options, X-Frame-Options

4. 入力サニタイゼーション
   - SQLインジェクション: Prismaのパラメータ化クエリで対策済み
   - XSS: レスポンスのHTMLエスケープ

5. リクエストサイズ制限
   - JSONボディ: 最大1MB

Prismaを使用している場合、SQLインジェクションはORMのパラメータ化クエリで構造的に防がれます。ただし、生のSQLクエリ($queryRaw)を使う場合は、パラメータバインドを明示的に行う必要がある点に注意してください。

Claude Codeにセキュリティミドルウェアの生成を依頼する際の注意点として、生成されたコードが「動作するが不十分」なケースがあります。たとえば、CORS設定でorigin: '*'(全オリジン許可)が生成されることがあります。開発環境では便利ですが、本番環境ではセキュリティリスクになるため、環境変数で制御する形に修正してください。Claude Codeは指示が曖昧だと「安全側に倒す」のではなく「動作する方を優先する」傾向があるため、セキュリティ要件は明示的に指示することが重要です。

セキュリティ対策の全体像についてはClaude Code × エンタープライズセキュリティで詳しく解説しています。

ステップ6 — テストとドキュメント自動生成

テストとドキュメントは「後で書く」と後回しにされがちですが、Claude Codeを使えば実装と同時に生成できます。 スキーマファースト開発では、OpenAPI仕様からテストケースの骨格も自動導出できるため、テストの網羅性を高めやすい利点があります。

統合テスト・E2Eテストの生成

Claude Codeにテスト生成を依頼する際は、テストの種類と期待する構成を指示します。

タスクAPIの統合テストを生成してください。

- テストフレームワーク: Vitest + Supertest
- テスト用データベース: テスト用PostgreSQLコンテナ(docker-compose.test.yml)
- テストデータ: 各テストケースの前にシードデータを挿入、後にクリーンアップ
- テストケース:
  - 正常系: 各CRUD操作の成功パス
  - 異常系: バリデーションエラー、認証エラー、権限エラー、存在しないリソース
  - 境界値: タイトル最大長、ページネーションの端

Claude Codeは、コントローラーの実装とZodスキーマの両方を読み取った上でテストを生成するため、バリデーションルールと一致したテストデータを自動的に構成します。

テスト生成でClaude Codeが特に効果を発揮するのは、異常系のテストケースです。正常系は開発者自身が思いつきやすいですが、「タイトルが200文字ちょうどのとき」「存在しないプロジェクトIDを指定したとき」「認証トークンが期限切れのとき」といった境界値や異常系の網羅は手作業では漏れやすい領域です。Claude Codeはバリデーションスキーマと認証ミドルウェアの実装を読み取った上で、これらのケースを自動的にカバーします。

テストの書き方についてはClaude CodeでTDD駆動のテスト戦略を実践する方法も参考にしてください。

テスト環境のDocker構成についてはClaude Code × Docker活用ガイドで解説しています。

OpenAPIドキュメントとSwagger UI

スキーマファースト開発では、OpenAPI仕様が最初から存在するため、ドキュメントの「初回作成」は不要です。必要なのは、実装の進行に合わせた仕様の更新と、Swagger UIでの閲覧環境の構築です。

以下を設定してください:
1. swagger-ui-express で /api-docs にSwagger UIを公開
2. 開発環境でのみ有効化(NODE_ENV === 'development')
3. OpenAPI仕様ファイルのパス: docs/openapi.yaml

仕様と実装の乖離を防ぐために、CIパイプラインでOpenAPI仕様と実装の整合性チェックを行うことを推奨します。Claude CodeにHooks自動化を設定させれば、コミット前に自動的にチェックを走らせることもできます。

実装の変更が必要になった場合は、まずOpenAPI仕様を修正し、それに合わせて実装を更新するフローを徹底してください。仕様が常に先行するため、ドキュメントと実装の乖離が構造的に起きにくくなります。

実践例 — マルチテナントSaaS APIの構築

ここまでのステップを統合し、より実践的な例としてマルチテナントSaaS APIの構築を紹介します。 TODOアプリやタスク管理アプリの例は他の記事でも多く見られますが、マルチテナント対応は現実のSaaS開発で避けて通れない設計課題です。

SaaS開発の基本的な考え方はSaaS開発の要点ガイドを参照してください。

テナント分離の設計

マルチテナントSaaSでは、テナント間のデータ分離が最重要の設計課題です。主なアプローチは2つあります。

アプローチ仕組みメリットデメリット
RLS(Row Level Security)全テナントが1つのDBを共有し、行レベルでアクセス制御インフラコスト低、マイグレーション容易クエリパフォーマンスへの影響、設定ミスのリスク
スキーマ分離テナントごとにDBスキーマを分離強い分離、パフォーマンス独立インフラコスト高、マイグレーション複雑

小〜中規模のSaaSではRLSが一般的です。Claude Codeにテナント分離の設計を依頼する例を示します。

PostgreSQLのRLSを使ったマルチテナント分離を実装してください。

- 全テーブルにtenant_idカラムを追加
- RLSポリシー: current_setting('app.tenant_id')と一致する行のみアクセス可能
- Prismaのミドルウェアで自動的にtenant_idをフィルタリング
- テナント作成時のセットアップスクリプト

テナントコンテキストミドルウェア

リクエストからテナントを特定し、以降の処理にテナントコンテキストを引き渡すミドルウェアが必要です。

// src/middleware/tenant-context.ts
import { Request, Response, NextFunction } from "express";
import { z } from "zod";

const tenantIdSchema = z.string().uuid("テナントIDの形式が不正です");

export async function tenantContext(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const rawTenantId = req.headers["x-tenant-id"];
  const parsed = tenantIdSchema.safeParse(rawTenantId);

  if (!parsed.success) {
    return res.status(400).json({
      error: {
        code: "VALIDATION_INVALID_TENANT",
        message: "テナントIDが未指定または不正な形式です",
      },
    });
  }

  const tenantId = parsed.data;

  // テナントの存在確認
  const tenant = await prisma.tenant.findUnique({
    where: { id: tenantId },
  });

  if (!tenant) {
    return res.status(404).json({
      error: {
        code: "RESOURCE_TENANT_NOT_FOUND",
        message: "指定されたテナントが見つかりません",
      },
    });
  }

  // PostgreSQLのセッション変数にテナントIDを設定(RLS用)
  // $executeRaw のタグ付きテンプレートリテラルで自動パラメータバインド
  await prisma.$executeRaw`SET LOCAL app.tenant_id = ${tenantId}`;

  req.tenantId = tenantId;
  next();
}

このミドルウェアを認証ミドルウェアの直後に配置することで、認証済みユーザーのテナントコンテキストが全APIエンドポイントで利用可能になります。

マルチテナントAPIの構築でClaude Codeに依頼する際は、以下の点を明示的に指示してください。

  • テナントIDのバリデーション(UUIDフォーマットチェック)
  • テナントが存在しない場合のエラーレスポンス
  • RLSポリシーのテスト(異なるテナントのデータにアクセスできないことの検証)
  • テナント作成時の初期設定(デフォルトロール、初期ユーザーの生成)

RLSを採用する場合の運用上の注意点として、SET LOCAL でセッション変数を設定する方式では、コネクションプーリングとの相互作用に注意が必要です。Prismaの $transaction 内で SET LOCAL を使えばトランザクション単位で変数がリセットされるため、コネクションの再利用時にテナントIDが漏洩するリスクを軽減できます。この種の設計判断は、Claude Codeの提案をそのまま採用するのではなく、セキュリティ要件に照らして開発者が検証すべき領域です。

Claude Code API開発チェックリスト

API開発の各段階で確認すべき項目をチェックリストにまとめました。Claude Codeに実装を依頼した後の品質確認に活用してください。

設計フェーズ

  • OpenAPI仕様が要件を正しく反映しているか
  • CLAUDE.mdにAPI設計規約が記述されているか
  • リソース間のリレーションが適切に定義されているか

実装フェーズ

  • コントローラー・サービス・リポジトリのレイヤー分離ができているか
  • Zodバリデーションスキーマが全エンドポイントに適用されているか
  • エラーレスポンスが統一フォーマットに従っているか

セキュリティフェーズ

  • JWT認証ミドルウェアが全保護エンドポイントに適用されているか
  • RBACが適切に設定されているか
  • レート制限・CORS・セキュリティヘッダーが有効か
  • 環境変数にシークレット情報がハードコードされていないか

テスト・ドキュメントフェーズ

  • 正常系・異常系・境界値のテストケースがあるか
  • テストが独立して実行でき、副作用がないか
  • OpenAPIドキュメントが実装と一致しているか

変更管理にはClaude Code × Git連携ワークフローの活用も有効です。

よくある質問(FAQ)

Claude CodeでREST APIを作る方法は?

OpenAPI仕様を先に設計し、Claude Codeにスキーマ→実装→テスト→ドキュメントの順で生成を依頼するスキーマファースト開発が効率的です。CLAUDE.mdにAPI設計規約を記述しておくと、一貫した品質でコードが生成されます。本記事のステップ1〜6の流れに沿って進めてください。

Claude CodeとClaude APIの違いは何ですか?

Claude Codeはターミナルやエディタ上で動作するAIコーディングエージェントです。コードベース全体を読み取り、ファイルの作成・編集・コマンド実行を行います。一方、Claude APIはAnthropicが提供するLLMのHTTP APIであり、自分のアプリケーションからClaude(LLM)を呼び出すためのインターフェースです。API開発の文脈では、Claude Codeが「API開発を支援するツール」、Claude APIが「APIの裏側で使うLLMサービス」という関係になります。

Claude Codeでデータベース設計はできますか?

はい、PrismaなどのORMスキーマの自動生成、マイグレーションファイルの作成、シードデータの生成に対応しています。OpenAPI仕様からDBスキーマを派生させるスキーマファーストの手法では、APIのリソース定義とDBの構造が自動的に一致するため、設計の整合性を保ちやすくなります。ただし、本番環境のパフォーマンスチューニングやインデックス最適化は、実際の負荷テスト結果に基づいて人間が判断すべき領域です。

Claude CodeでOpenAPI仕様を生成できますか?

はい、要件定義のテキストから、パス定義・リクエスト/レスポンススキーマ・エラーレスポンスを含むOpenAPI 3.1仕様を生成できます。また、既存のExpressルートやFastAPIエンドポイントからOpenAPI仕様を逆生成することも可能です。生成された仕様はSwagger UIやStoplightなどのツールで閲覧・共有できます。

Claude Codeのバックエンド開発での限界は?

Claude Codeは「指示されたパターンを正確に実装する」ことに長けていますが、以下の領域では人間の判断が不可欠です。大規模データベースのパフォーマンスチューニング(実データの負荷特性に依存)、レガシーシステムとの統合(ドキュメントにないビジネスルールの把握)、セキュリティ要件の設計判断(トークン有効期限やアクセス制御ポリシーの決定)、インフラ構成の選択(クラウドサービスの組み合わせやスケーリング戦略)。Claude Codeは「どう実装するか」を任せるツールであり、「何を作るか」「なぜその設計にするか」は人間の領域です。

関連記事