LESSON 25分

ストーリー

高橋アーキテクト
API設計を紙やSlackで共有していたら、どうなると思う?
高橋アーキテクト
このAPI、レスポンスの形式変わった?」「仕様書どこ?
あなた
混乱しますね…
高橋アーキテクト
そうだ。APIの契約は、機械が読める形式で定義する必要がある。それが OpenAPI Specification だ。以前は Swagger と呼ばれていた
あなた
機械が読めるということは、自動でドキュメントやコードを生成できるんですか?
高橋アーキテクト
その通り。OpenAPIの真の力はそこにある

OpenAPI Specification とは

概要

# OpenAPI は YAML または JSON で書くAPI仕様書
# 現在の最新バージョンは 3.1(2021年リリース)

# OpenAPIでできること:
# 1. APIの仕様を正確に記述する
# 2. APIドキュメントを自動生成する(Swagger UI, Redoc)
# 3. クライアントコードを自動生成する
# 4. サーバースタブを自動生成する
# 5. リクエスト/レスポンスのバリデーション
# 6. テストの自動生成

基本構造

# openapi.yaml
openapi: "3.1.0"                    # OpenAPIのバージョン
info:                                # API全体の情報
  title: "TaskFlow API"
  description: "タスク管理アプリケーションのAPI"
  version: "1.0.0"
  contact:
    name: "API Support"
    email: "api-support@example.com"
  license:
    name: "MIT"

servers:                             # APIサーバーの情報
  - url: "https://api.taskflow.example.com/v1"
    description: "本番環境"
  - url: "https://staging-api.taskflow.example.com/v1"
    description: "ステージング環境"
  - url: "http://localhost:3000/v1"
    description: "ローカル開発環境"

paths:                               # エンドポイントの定義
  /users:
    get:
      summary: "ユーザー一覧取得"
      # ... 詳細は後述

components:                          # 再利用可能なスキーマ定義
  schemas:
    User:
      # ... 詳細は後述
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

tags:                                # APIのカテゴリ分け
  - name: "users"
    description: "ユーザー関連のAPI"
  - name: "tasks"
    description: "タスク関連のAPI"

パスとオペレーションの定義

基本的なCRUD

paths:
  /users:
    get:
      tags: ["users"]
      summary: "ユーザー一覧取得"
      description: "登録されているユーザーの一覧を取得します"
      operationId: "listUsers"
      parameters:
        - name: page
          in: query
          description: "ページ番号"
          required: false
          schema:
            type: integer
            default: 1
            minimum: 1
        - name: perPage
          in: query
          description: "1ページあたりの件数"
          required: false
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

    post:
      tags: ["users"]
      summary: "ユーザー作成"
      operationId: "createUser"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateUserRequest"
      responses:
        "201":
          description: "作成成功"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserResponse"
        "422":
          $ref: "#/components/responses/ValidationError"

  /users/{userId}:
    get:
      tags: ["users"]
      summary: "ユーザー詳細取得"
      operationId: "getUser"
      parameters:
        - name: userId
          in: path
          required: true
          description: "ユーザーID"
          schema:
            type: string
            example: "usr_123"
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserResponse"
        "404":
          $ref: "#/components/responses/NotFound"

コンポーネントの定義

スキーマ(データモデル)

components:
  schemas:
    User:
      type: object
      required: [id, name, email, createdAt]
      properties:
        id:
          type: string
          description: "ユーザーID"
          example: "usr_123"
        name:
          type: string
          description: "ユーザー名"
          example: "田中太郎"
        email:
          type: string
          format: email
          description: "メールアドレス"
          example: "tanaka@example.com"
        role:
          type: string
          enum: [admin, member, viewer]
          description: "ロール"
          example: "member"
        createdAt:
          type: string
          format: date-time
          description: "作成日時"
          example: "2025-01-15T09:00:00Z"

    CreateUserRequest:
      type: object
      required: [name, email, password]
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8

    UserResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/User"

    UserListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/User"
        meta:
          $ref: "#/components/schemas/PaginationMeta"

    PaginationMeta:
      type: object
      properties:
        totalCount:
          type: integer
          example: 150
        currentPage:
          type: integer
          example: 1
        perPage:
          type: integer
          example: 20
        totalPages:
          type: integer
          example: 8

セキュリティの定義

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "JWT Bearer Token"

    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: "APIキー"

# グローバルに適用
security:
  - bearerAuth: []

# 特定のエンドポイントだけ認証不要にする
paths:
  /auth/login:
    post:
      security: []  # 認証不要
      # ...

まとめ

ポイント内容
OpenAPIAPIの仕様を機械可読な形式(YAML/JSON)で記述する標準規格
基本構造info, servers, paths, components, security
パス定義HTTPメソッドごとにparameters, requestBody, responsesを記述
コンポーネント$ref で再利用可能なスキーマを定義
メリットドキュメント自動生成、コード生成、バリデーション

チェックリスト

  • OpenAPI Specificationの目的と基本構造を理解した
  • パスとオペレーションの定義方法を把握した
  • $ref によるスキーマの再利用を理解した
  • セキュリティスキームの定義方法を把握した

次のステップへ

OpenAPI仕様の基礎を学びました。

次のセクションでは、スキーマ定義とバリデーションについてさらに深く学びます。 型の制約、必須フィールド、列挙型など、より実践的なスキーマ設計を習得しましょう。


推定読了時間: 25分