📄
概念 📚 beginner-stepup

REST API 仕様書の書き方(Month 2 Week 7)

エンドポイント一覧・リクエスト/レスポンススキーマ・ステータスコード設計を OpenAPI 形式と Markdown 形式で書く方法

ER 図でデータ構造が決まったら、次は フロントとバックの契約 である API 仕様書を書きます。これが Month 3-4 の実装のベースになります。


なぜ API 仕様書を先に書くのか

Month 3(フロント)と Month 4(バック)を並行して進められるようにするためです。仕様書があれば:

  • フロント側は仕様書を見てモック API を組み、UI を実装できる
  • バック側は仕様書を見てエンドポイントを実装できる
  • 両者が結合する時に「あれ、リクエスト形式が違う」という事故が減る

小規模プロジェクトでも 30 分で API 仕様書を書く習慣 は必ず報われます。


最小限の仕様書フォーマット(Markdown)

OpenAPI を書き始める前に、まず Markdown で以下の 5 項目を埋めます。

1. エンドポイント一覧

MethodPath用途認証
GET/posts投稿一覧不要
GET/posts/:id投稿詳細不要
POST/posts投稿作成必要
DELETE/posts/:id投稿削除必要(作成者のみ)
POST/auth/registerユーザー登録不要
POST/auth/loginログイン不要

2. エンドポイントごとの詳細

各エンドポイントを以下のテンプレで書きます。

## POST /posts

投稿を作成する。

### 認証
Bearer token 必須

### Request body
{
  "content": string (1〜280 文字)
}

### Response (201 Created)
{
  "id": string (UUID),
  "content": string,
  "authorId": string (UUID),
  "createdAt": string (ISO 8601)
}

### Error
- 400: バリデーション失敗(文字数違反)
- 401: 未認証

3. ステータスコードの方針

コード使う場面
200GET 成功
201POST で新規作成成功
204DELETE / PUT で成功(ボディなし)
400バリデーション失敗(クライアント入力が悪い)
401認証が必要 or トークンが無効
403認証は通ったが権限がない
404リソースが存在しない
409競合(重複登録など)
500サーバー内部エラー

よくある迷い: 「無効な投稿 ID を渡された」→ 400 ではなく 404 を返す。ID の形式自体がおかしいなら 400、形式は正しいが存在しないなら 404。

4. 共通レスポンス形式

エラーレスポンスは形を統一します。

{
  "error": "VALIDATION_FAILED",
  "message": "content must be between 1 and 280 characters",
  "details": {
    "field": "content",
    "value": ""
  }
}
  • error: 固定のエラーコード(フロント側で分岐に使う)
  • message: 英語の人間向け説明(ログに残す)
  • details: 任意の追加情報

5. 認証方式

Bearer token(JWT)を Authorization ヘッダで送る:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...

詳細は b07-auth-patterns 参照。


OpenAPI 形式で書く(上級)

Markdown で書き慣れたら、OpenAPI(Swagger)形式に昇格させると自動テスト・モック生成・クライアント SDK 生成の恩恵を受けられます。

openapi: 3.0.3
info:
  title: SNS clone API
  version: 1.0.0
servers:
  - url: http://localhost:3001
    description: ローカル開発
  - url: https://api.example.cloudfront.net
    description: 本番

paths:
  /posts:
    get:
      summary: 投稿一覧を取得
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Post'
    post:
      summary: 投稿を作成
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content:
                  type: string
                  minLength: 1
                  maxLength: 280
      responses:
        '201':
          description: 作成成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Post'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'

components:
  schemas:
    Post:
      type: object
      required: [id, content, authorId, createdAt]
      properties:
        id:
          type: string
          format: uuid
        content:
          type: string
        authorId:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

OpenAPI を書くメリット

  • Swagger UI で仕様書が自動 HTML 化される(https://editor.swagger.io/ に貼ると即プレビュー)
  • Zod schema を自動生成できる(openapi-typescript などのツール)
  • モックサーバーが立つ(prism などで実 API なしにフロント開発)

Month 2 では Markdown で十分、Month 3 以降に必要を感じたら OpenAPI に昇格で OK です。


設計の原則

RESTful な URL 設計

  • 名詞で書く(動詞は HTTP メソッドが担う)
  • 複数形(リソースは集合として捉える)
  • 階層は浅く(深くても 2 階層まで)
良い例悪い例
GET /posts/:idGET /getPostById?id=xxx
POST /postsPOST /createPost
GET /users/:id/postsGET /posts_of_user?userId=xxx
DELETE /posts/:id/reactionsPOST /removeReaction

べき等性(idempotent)

同じリクエストを何度送っても結果が変わらない操作は PUT / DELETE / GET。変わるのは POST のみ。


Week 7 のアウトプット

  • ☐ エンドポイント一覧表が埋まっている
  • ☐ 各エンドポイントに Request body / Response body / エラーコードが書かれている
  • ☐ 共通エラーレスポンス形式が決まっている
  • ☐ 認証方式が書かれている
  • docs/api-spec.md として PR 提出

よくある失敗

  • 同じような意味で違う表記: 「userId」と「user_id」が混在、「postId」と「post_id」が混在。最初にルール化(本カリキュラムは camelCase 推奨)
  • エラー時のレスポンスが未定義: 成功時だけ仕様書に書いて、エラー時を書かないとフロントで分岐できません
  • 実装と仕様のズレを放置: 実装が変わったら仕様書も更新。仕様書が古くなると誰も見なくなります

参考

生きているコード

本ドキュメントで扱ったパターンの完全な動作コードは、メンター側リポジトリの参照ブランチで確認できます。

  • 対応 Week: W7
  • 参照ブランチ:
  • W7: reference/week-7
  • 対応 checklist 項目: (直接対応なし)

ブランチの作り方・見方は b00-curriculum-map を参照してください。

  1. 1. 📄環境構築の段階的導入(macOS / Windows)
  2. 2. 📄SNSアプリの最終インフラ構成図
  3. 3. 📄SNSクローンの全体設計(Month 1 ゴール)
  4. 4. 📄カリキュラム全体マップ(Week × 教材 × 参照ブランチ × 要求チェックリスト)
  5. 5. 📄このカリキュラムの使い方(SQL・Python・Dify経験者向け)
  6. 6. 📄シェル・ターミナル基礎
  7. 7. 📄Windows で完全にゼロから始める開発環境構築(Week 1)
  8. 8. 📄Git基礎
  9. 9. 📄GitHubワークフロー
  10. 10. 📄パッケージ管理(pnpm workspace)
  11. 11. 📄Webアプリアーキテクチャ全体像
  12. 12. 📄要求ヒアリングとユーザーストーリー(Month 2 Week 5)
  13. 13. 📄画面ワイヤーフレームと画面遷移図(Month 2 Week 6)
  14. 14. 📄HTTP・REST API基礎
  15. 15. 📄ER 図の描き方(Month 2 Week 7)
  16. 16. 📄認証・認可のパターン
  17. 17. 📄REST API 仕様書の書き方(Month 2 Week 7)
  18. 18. 📄HTML/CSS基礎とレイアウト
  19. 19. 📄JavaScript基礎(Pythonとの対比)
  20. 20. 📄TypeScript基礎(型システムとPythonとの対比)
  21. 21. 📄Reactコンポーネント設計の基礎
  22. 22. 📄状態管理の概念
  23. 23. 📄フォーム検証(React Hook Form + Zod)(Month 3 Week 11)
  24. 24. 📄バックエンドAPI設計(Hono)
  25. 25. 📄ルーティング(React Router v7)
  26. 26. 📄Hono のエラーハンドリング(Month 4 Week 13)
  27. 27. 📄データベース設計・SQL→Drizzle ORM対応
  28. 28. 📄マイグレーションの考え方
  29. 29. 📄AWSインフラ基礎
  30. 30. 📄AWS Budget Alert の設定(Month 5 Week 17)
  31. 31. 📄環境変数管理
  32. 32. 📄Bastion EC2 と SSH ProxyJump(Month 5 Week 18)
  33. 33. 📄CI/CD基礎
  34. 34. 📄ECR への Docker イメージ push と App EC2 デプロイ(Month 5 Week 19)
  35. 35. 📄テスト設計の基本
  36. 36. 📄CloudFront + S3 + ALB で公開する(Month 5 Week 20)
  37. 37. 📄CLAUDE.md・プロジェクト設定
  38. 38. 📄PR レビュー 5 観点ルーブリック(全 Week 共通)
  39. 39. 📄タスク分解・仕様の書き方
  40. 40. 📄Playwright で E2E テスト(Month 6 Week 22)
  41. 41. 📄生成コードのレビュー・デバッグの勘所
  42. 42. 📄Trivy で脆弱性スキャン(Month 6 Week 23)
  43. 43. 📄CloudWatch Logs の読み方と運用(Month 6 Week 23)
  44. 44. 📄PDF ポートフォリオの自動生成(Month 6 Week 24)