目次

現代の API 開発において、**OpenAPI 仕様(旧 Swagger 仕様)**は事実上の標準となっている。API の設計、ドキュメント作成、クライアント/サーバーコードの生成、テスト自動化——これらを一貫して行うための強力なツールだ。本記事では、OpenAPI 仕様の基本概念から、実用的な定義の書き方、ドキュメント自動化、コード生成、API ファースト開発のプラクティスまでを体系的に解説する。

OpenAPI 仕様とは

**OpenAPI 仕様(OpenAPI Specification, OAS)**は、RESTful API の構造を機械可読な形式で記述するための標準仕様だ。

【OpenAPI 仕様のメリット】

1. 単一の信頼できる情報源(Single Source of Truth)
   - API 設計、ドキュメント、実装が一貫
   - 仕様と実装の乖離を防止

2. 自動ドキュメント生成
   - 人間が読むためのインタラクティブな docs
   - 常に最新の状態を維持

3. コード生成
   - クライアント SDK(TypeScript, Python, Java など)
   - サーバーサイドのスタブコード
   - モックサーバー

4. ツールエコシステム
   - Swagger UI、Redoc、Stoplight
   - Postman、Insomnia でのインポート
   - 自動テスト生成

歴史とバージョン

【OpenAPI 仕様の歴史】

2010 年:Swagger 仕様 1.0(Wordnik が開発)
2014 年:Swagger 2.0(大幅な改善)
2015 年:SmartBear Software が Swagger 仕様をオープンソース化
2015 年:Linux Foundation 傘下の OpenAPI Initiative 発足
2016 年:OpenAPI 3.0 公開(Swagger から OpenAPI へ改名)
2021 年:OpenAPI 3.1 公開(JSON Schema 2020-12 に完全準拠)

【バージョン比較】

| 機能 | Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 |
|------|------------|-------------|-------------|
| **JSON Schema** | 一部準拠 | 一部準拠 | 完全準拠 |
| **コンポーネント** | definitions | components | components |
| **サーバー定義** | host + basePath | servers(URL 配列) | servers(変数対応) |
| **リクエストボディ** | 1 つのみ | 複数(media type 別) | 複数 |
| **Webhooks** | 非対応 | 非対応 | 対応 |
| **null 型** | x-nullable | nullable: true | type: "null" |

OpenAPI ドキュメントの基本構造

OpenAPI ドキュメントは YAML または JSON 形式で記述する。YAML の方が可読性が高く一般的だ。

最小限の構造

openapi: "3.1.0"
info:
  title: "サンプル API"
  version: "1.0.0"
  description: "これはサンプル API のドキュメントです"

paths:
  /users:
    get:
      summary: "ユーザー一覧を取得"
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/User"

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "山田太郎"
        email:
          type: string
          format: email
          example: "taro@example.com"

主要セクション

【OpenAPI ドキュメントの構成要素】

openapi: "3.1.0"              # 使用する OpenAPI 仕様のバージョン

info:                          # API のメタ情報
  title: "API 名"
  version: "1.0.0"
  description: "説明"
  contact:                     # 連絡先
    name: "サポートチーム"
    email: "support@example.com"
  license:                     # ライセンス
    name: "MIT"
    url: "https://opensource.org/licenses/MIT"

servers:                       # サーバーエンドポイント
  - url: "https://api.example.com/v1"
    description: "本番環境"
  - url: "https://staging-api.example.com/v1"
    description: "ステージング環境"

paths:                         # エンドポイント定義
  /users:
    get: ...
    post: ...
  /users/{id}:
    get: ...
    put: ...
    delete: ...

components:                    # 再利用可能なコンポーネント
  schemas:                     # データモデル
  responses:                   # レスポンス定義
  parameters:                  # パラメータ定義
  requestBodies:               # リクエストボディ定義
  headers:                     # ヘッダー定義
  securitySchemes:             # 認証スキーム

security:                      # 全局セキュリティ設定
tags:                          # 操作のグルーピング用タグ
externalDocs:                  # 外部ドキュメントへのリンク

パスの定義——エンドポイントの設計

HTTP メソッドと操作

paths:
  /users:
    # コレクション操作
    get:
      tags: ["users"]
      summary: "ユーザー一覧を取得"
      description: " pagination をサポート"
      operationId: "listUsers"
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/User"
                  total:
                    type: integer
                    example: 100
                  limit:
                    type: integer
                  offset:
                    type: integer

    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/User"
        "400":
          description: "バリデーションエラー"
          content:
            application/json:
              schema:
                $ref: "#/components/responses/BadRequest"

  /users/{id}:
    # 単一リソース操作
    get:
      tags: ["users"]
      summary: "ユーザーを取得"
      operationId: "getUserById"
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "404":
          description: "ユーザーが見つからない"

    put:
      tags: ["users"]
      summary: "ユーザーを更新(全体)"
      operationId: "replaceUser"
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateUserRequest"
      responses:
        "200":
          description: "更新成功"

    patch:
      tags: ["users"]
      summary: "ユーザーを部分更新"
      operationId: "updateUser"
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PartialUpdateUserRequest"
      responses:
        "200":
          description: "部分更新成功"

    delete:
      tags: ["users"]
      summary: "ユーザーを削除"
      operationId: "deleteUser"
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "204":
          description: "削除成功(ボディなし)"

パスパラメータの書式

paths:
  # シンプルな ID
  /users/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer

  # 複合キー
  /organizations/{orgId}/users/{userId}:
    parameters:
      - name: orgId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: userId
        in: path
        required: true
        schema:
          type: string
          format: uuid

  # パスパターン(OpenAPI 3.1)
  /files/{path}:
    parameters:
      - name: path
        in: path
        required: true
        schema:
          type: string
        style: simple
        explode: false

スキーマ定義——データモデルの設計

基本型の定義

components:
  schemas:
    # 基本型の直接使用
    UserId:
      type: integer
      minimum: 1
      example: 1

    Email:
      type: string
      format: email
      example: "user@example.com"

    Timestamp:
      type: string
      format: date-time
      example: "2025-08-15T10:30:00Z"

    # オブジェクト型
    User:
      type: object
      description: "ユーザー情報"
      required:
        - id
        - email
        - created_at
      properties:
        id:
          type: integer
          description: "ユーザー ID"
          example: 1
          readOnly: true
        email:
          type: string
          format: email
          description: "メールアドレス(ログインに使用)"
          example: "taro@example.com"
        name:
          type: string
          description: "表示名"
          example: "山田太郎"
          minLength: 1
          maxLength: 50
        role:
          type: string
          description: "ロール"
          enum:
            - admin
            - editor
            - viewer
          default: "viewer"
        profile:
          $ref: "#/components/schemas/UserProfile"
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true

    UserProfile:
      type: object
      properties:
        bio:
          type: string
          maxLength: 500
          example: "エンジニアとして働いています"
        avatar_url:
          type: string
          format: uri
          nullable: true
        social_links:
          type: object
          properties:
            twitter:
              type: string
              format: uri
            github:
              type: string
              format: uri
            linkedin:
              type: string
              format: uri

配列と組み合わせ

components:
  schemas:
    # 配列
    UserList:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/User"
        pagination:
          $ref: "#/components/schemas/PaginationInfo"

    PaginationInfo:
      type: object
      properties:
        total:
          type: integer
          example: 100
        limit:
          type: integer
          example: 20
        offset:
          type: integer
          example: 0
        has_more:
          type: boolean
          example: true

    # 組み合わせ(allOf, anyOf, oneOf)
    # allOf: すべての条件を満たす(継承パターン)
    DetailedUser:
      allOf:
        - $ref: "#/components/schemas/User"
        - type: object
          properties:
            department:
              type: string
              example: "エンジニアリング部"
            manager_id:
              type: integer
              nullable: true

    # anyOf: いずれか一つ以上を満たす
    SearchTarget:
      anyOf:
        - $ref: "#/components/schemas/User"
        - $ref: "#/components/schemas/Team"
        - $ref: "#/components/schemas/Project"

    # oneOf: ちょうど一つを満たす(排他的)
    PaymentMethod:
      oneOf:
        - $ref: "#/components/schemas/CreditCardPayment"
        - $ref: "#/components/schemas/BankTransferPayment"
        - $ref: "#/components/schemas/CryptoPayment"
      discriminator:
        propertyName: "type"
        mapping:
          credit_card: "#/components/schemas/CreditCardPayment"
          bank_transfer: "#/components/schemas/BankTransferPayment"
          crypto: "#/components/schemas/CryptoPayment"

列挙型と定数

components:
  schemas:
    # 列挙型
    UserRole:
      type: string
      enum:
        - admin
        - editor
        - viewer
      x-enum-varnames:
        - ADMIN
        - EDITOR
        - VIEWER

    UserStatus:
      type: string
      enum:
        - active
        - inactive
        - suspended
        - deleted

    # 定数
    ApiVersion:
      type: string
      const: "v1"

    # 数値の列挙
    HttpStatusCode:
      type: integer
      enum:
        - 200
        - 201
        - 204
        - 400
        - 401
        - 403
        - 404
        - 500

レスポンスの定義

ステータスコード別レスポンス

paths:
  /users/{id}:
    get:
      summary: "ユーザーを取得"
      responses:
        # 成功
        "200":
          description: "成功"
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: "1 時間のリクエスト上限"
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: "残リクエスト数"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

        # クライアントエラー
        "400":
          description: "不正なリクエスト"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error:
                  code: "INVALID_REQUEST"
                  message: "リクエストパラメータが不正です"
                  details:
                    - field: "id"
                      message: "整数値を指定してください"

        "401":
          description: "認証が必要"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error:
                  code: "UNAUTHORIZED"
                  message: "認証トークンが無効です"

        "403":
          description: "アクセス権限がありません"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error:
                  code: "FORBIDDEN"
                  message: "このリソースへのアクセス権限がありません"

        "404":
          description: "リソースが見つかりません"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error:
                  code: "NOT_FOUND"
                  message: "ユーザーが見つかりません"

        "429":
          description: "レート制限超過"
          headers:
            Retry-After:
              schema:
                type: integer
              description: "再試行可能なまでの秒数"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

        # サーバーエラー
        "500":
          description: "内部サーバーエラー"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

        "503":
          description: "サービス利用不可"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

エラーレスポンスの共通化

components:
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: "エラーコード(プログラムで処理可能)"
              example: "VALIDATION_ERROR"
            message:
              type: string
              description: "人間向けのエラーメッセージ"
              example: "入力値の検証に失敗しました"
            details:
              type: array
              description: "エラー詳細(バリデーションエラー等)"
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: "問題のあるフィールド"
                  message:
                    type: string
                    description: "フィールド固有のエラーメッセージ"
                  code:
                    type: string
                    description: "フィールド固有のエラーコード"
            trace_id:
              type: string
              description: "ログ追跡用の ID"
              example: "req_abc123xyz"

  responses:
    BadRequest:
      description: "不正なリクエスト"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

    Unauthorized:
      description: "認証が必要"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

    Forbidden:
      description: "アクセス権限がありません"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

    NotFound:
      description: "リソースが見つかりません"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

    InternalServerError:
      description: "内部サーバーエラー"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

認証の定義

セキュリティスキーム

components:
  securitySchemes:
    # Bearer トークン(JWT など)
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "JWT アクセストークン"

    # API キー(ヘッダー)
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: "ヘッダーで API キーを送信"

    # API キー(クエリパラメータ)
    apiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: "クエリパラメータで API キーを送信"

    # OAuth 2.0
    oauth2:
      type: oauth2
      description: "OAuth 2.0 認証"
      flows:
        authorizationCode:
          authorizationUrl: "https://auth.example.com/oauth2/authorize"
          tokenUrl: "https://auth.example.com/oauth2/token"
          refreshUrl: "https://auth.example.com/oauth2/refresh"
          scopes:
            read: "読み取り専用アクセス"
            write: "書き込みアクセス"
            admin: "管理者アクセス"

        clientCredentials:
          tokenUrl: "https://auth.example.com/oauth2/token"
          scopes:
            read: "読み取り専用アクセス"
            write: "書き込みアクセス"

        implicit:
          authorizationUrl: "https://auth.example.com/oauth2/authorize"
          scopes:
            read: "読み取り専用アクセス"

        password:
          tokenUrl: "https://auth.example.com/oauth2/token"
          scopes:
            read: "読み取り専用アクセス"
            write: "書き込みアクセス"

    # Basic 認証
    basicAuth:
      type: http
      scheme: basic
      description: "HTTP Basic 認証"

# 全局セキュリティ(デフォルト)
security:
  - bearerAuth: []

# またはパスごとにセキュリティをオーバーライド
paths:
  /public/health:
    get:
      summary: "ヘルスチェック(認証不要)"
      security: []  # 認証不要
      responses:
        "200":
          description: "正常"

  /users:
    get:
      summary: "ユーザー一覧(読み取りスコープ必要)"
      security:
        - oauth2:
            - read
        - bearerAuth: []
      responses:
        "200":
          description: "成功"

    post:
      summary: "ユーザー作成(書き込みスコープ必要)"
      security:
        - oauth2:
            - write
        - bearerAuth: []
      responses:
        "201":
          description: "作成成功"

コード生成——自動実装の活用

OpenAPI Generator

OpenAPI Generatorは、OpenAPI 仕様から様々な言語のコードを生成するツールだ。

# CLI インストール
npm install -g @openapitools/openapi-generator-cli

# クライアント SDK 生成(TypeScript)
openapi-generator generate \
  -i openapi.yaml \
  -g typescript-axios \
  -o ./generated-client \
  --additional-properties=supportsES6=true,npmName=my-api-client,npmVersion=1.0.0

# サーバーサイドスタブ生成(Node.js/Express)
openapi-generator generate \
  -i openapi.yaml \
  -g nodejs-express-server \
  -o ./generated-server

# Python クライアント
openapi-generator generate \
  -i openapi.yaml \
  -g python \
  -o ./generated-python-client \
  --additional-properties=packageName=my_api_client

# Java(Spring Boot)
openapi-generator generate \
  -i openapi.yaml \
  -g spring \
  -o ./generated-java-server \
  --additional-properties=interfaceOnly=true

Swagger Codegen

# Swagger Codegen CLI
java -jar swagger-codegen-cli.jar generate \
  -i openapi.yaml \
  -l typescript-angular \
  -o ./generated-client

生成されるコードの例(TypeScript)

// 自動生成された API クライアント
import { Configuration, UsersApi } from './generated-client';

const config = new Configuration({
  basePath: 'https://api.example.com/v1',
  accessToken: 'your-jwt-token'
});

const usersApi = new UsersApi(config);

// 型安全な API コール
async function fetchUsers() {
  const response = await usersApi.listUsers(20, 0);
  // response.data: UserList
  console.log(response.data.data);
  console.log(response.data.pagination.total);
}

async function createUser(email: string, name: string) {
  const response = await usersApi.createUser({
    email,
    name
  });
  // response.data: User
  console.log(`Created user ${response.data.id}`);
}

ドキュメント自動化——Swagger UI と Redoc

Swagger UI

Swagger UIは、OpenAPI 仕様からインタラクティブな API ドキュメントを生成する。

# docker-compose.yml
version: '3.8'
services:
  swagger-ui:
    image: swaggerapi/swagger-ui:latest
    ports:
      - "8080:8080"
    volumes:
      - ./openapi.yaml:/usr/share/nginx/html/openapi.yaml
    environment:
      SWAGGER_JSON: /usr/share/nginx/html/openapi.yaml

アクセス:http://localhost:8080/?url=openapi.yaml

Redoc

Redocは、よりモダンで読みやすいドキュメントを生成する。

<!DOCTYPE html>
<html>
  <head>
    <title>API Documentation</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
    <style>
      body { margin: 0; padding: 0; }
    </style>
  </head>
  <body>
    <redoc spec-url="openapi.yaml"></redoc>
    <script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
  </body>
</html>

Stoplight Elements

Stoplight Elementsは、3 カラムレイアウトのモダンなドキュメントを生成する。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>API Documentation</title>
    <link rel="stylesheet" href="https://unpkg.com/elements-gui/dist/elements.min.css">
  </head>
  <body>
    <elements-api
      apiDescriptionUrl="openapi.yaml"
      router="hash"
      layout="sidebar"
    ></elements-api>
    <script src="https://unpkg.com/elements-gui/dist/elements.min.js"></script>
  </body>
</html>

API ファースト開発

API ファーストは、実装よりも先に API 設計(OpenAPI 仕様)を作成するアプローチだ。

【API ファースト開発のフロー】

1. 要件定義
   ↓
2. API 設計(OpenAPI 仕様)
   ↓
3. レビュー・承認
   ↓
4. コード生成(スタブ・クライアント)
   ↓
5. 実装
   ↓
6. テスト
   ↓
7. ドキュメント公開

モックサーバー

実装前にモックサーバーを使って早期にクライアント開発を始められる。

# Prism(Stoplight)を使ったモックサーバー
npm install -g @stoplight/prism-cli

# モックサーバー起動
prism mock openapi.yaml

# 自動生成されたエンドポイントにリクエスト
curl http://localhost:4010/users
# → スキーマに基づくモックレスポンスが返る

バリデーション

# リクエスト/レスポンスのバリデーション
prism proxy openapi.yaml https://backend.example.com

# 実際のレスポンスが仕様を満たしているか検証
curl http://localhost:4010/users

CI/CD への統合

# .github/workflows/api-validation.yml
name: API Validation

on:
  push:
    paths:
      - 'openapi.yaml'
  pull_request:
    paths:
      - 'openapi.yaml'

jobs:
  validate:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Validate OpenAPI
      uses: swaggerexpert/swagger-editor-validate@v1
      with:
        definition-file: openapi.yaml

    - name: Lint OpenAPI
      run: |
        npm install -g @redocly/cli
        redocly lint openapi.yaml

    - name: Generate Client
      run: |
        openapi-generator generate \
          -i openapi.yaml \
          -g typescript-axios \
          -o ./generated-client \
          --additional-properties=supportsES6=true

    - name: Generate Docs
      run: |
        npx @redocly/cli build-docs openapi.yaml -o ./docs/index.html

    - name: Upload Docs
      uses: actions/upload-pages-artifact@v3
      with:
        path: ./docs

バージョニング戦略

URL パスによるバージョニング

servers:
  - url: "https://api.example.com/v1"
    description: "API v1"
  - url: "https://api.example.com/v2"
    description: "API v2"

# v1 と v2 の仕様を別ファイルで管理
# openapi.v1.yaml
# openapi.v2.yaml

バージョン移行のガイド

info:
  title: "Example API"
  version: "2.0.0"
  description: |
    ## バージョン移行ガイド

    ### v1.0 → v2.0 の変更点

    #### 削除されたエンドポイント
    - `GET /users/search` → `GET /users` に統合(query パラメータ使用)

    #### 変更されたレスポンス形式
    ```json
    // v1.0
    { "users": [...], "count": 10 }

    // v2.0
    {
      "data": [...],
      "pagination": {
        "total": 10,
        "limit": 20,
        "offset": 0
      }
    }
    ```

    #### 新しく必須になったパラメータ
    - `POST /users` で `email` が必須に

    #### 非推奨(deprecation)
    - `X-API-Key` ヘッダー → Bearer トークンへ移行(2025-12-31 まで)

下位互換性の維持

paths:
  /users:
    get:
      summary: "ユーザー一覧を取得"
      deprecated: false
      parameters:
        # 旧パラメータ(非推奨)
        - name: count
          in: query
          deprecated: true
          schema:
            type: integer
            default: 20
          description: "非推奨:代わりに limit を使用してください"

        # 新パラメータ
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100

      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                oneOf:
                  # v1 形式(下位互換)
                  - $ref: "#/components/schemas/UserListV1"
                  # v2 形式(新規推奨)
                  - $ref: "#/components/schemas/UserListV2"

ベストプラクティス

命名規則

# リソース名は複数形
paths:
  /users: {}      # ✅ 良い
  /user: {}       # ❌ 避ける

# スネークケースまたはケバブケース
components:
  schemas:
    User: {}              # スキーマ名はパスカルケース
    UserProfile: {}
    CreateUserRequest: {}

# HTTP メソッドの意味を正しく使う
paths:
  /users:
    get: {}    # 取得(一覧)
    post: {}   # 作成
  /users/{id}:
    get: {}    # 取得(単一)
    put: {}    # 置換(全体更新)
    patch: {}  # 部分更新
    delete: {} # 削除

エラーハンドリング

# 一貫したエラーレスポンス形式
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string          # プログラムで処理可能なエラーコード
            message:
              type: string          # 人間向けのメッセージ
            details:                # 追加情報(任意)
              type: array
              items:
                type: object

# 適切なステータスコードを使用
responses:
  "400":  # バリデーションエラー
  "401":  # 認証エラー
  "403":  # 権限エラー
  "404":  # NotFound
  "409":  # 競合(重複等)
  "422":  # 意味論的エラー(バリデーション)
  "429":  # レート制限
  "500":  # サーバーエラー
  "503":  # サービス利用不可

ページネーション

paths:
  /users:
    get:
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
        - name: sort
          in: query
          schema:
            type: string
            enum:
              - created_at
              - name
              - email
            default: "created_at"
        - name: order
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
            default: "desc"

      responses:
        "200":
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/User"
                  pagination:
                    type: object
                    properties:
                      total:
                        type: integer
                      limit:
                        type: integer
                      offset:
                        type: integer
                      has_more:
                        type: boolean

まとめ

OpenAPI 仕様は、現代の API 開発において不可欠なツールだ。

  1. 単一の信頼できる情報源: 仕様、ドキュメント、実装の一貫性を保つ
  2. 自動ドキュメント生成: Swagger UI、Redoc でインタラクティブな docs
  3. コード生成: クライアント SDK、サーバーサイドスタブ、モックサーバー
  4. API ファースト開発: 設計先行で品質向上、早期クライアント開発
  5. エコシステム: 豊富なツール、CI/CD 統合、バリデーション

適切に設計された OpenAPI 仕様は、開発者の生産性を高め、API の品質を向上させ、ドキュメントのメンテナンスコストを削減する。


参考資料

免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。