API定義のコードレビューチェックリスト

# はじめに

OpenAPI YAML定義のレビューチェックリストを試行します。
このチェックリストを使用することで、OpenAPI YAMLドキュメントの品質と完全性を確保することを目的とします。

# チェックリスト

## 1. 基本構造と情報

### 1.1 YAML構文
- [ ] インデントが一貫しているか（通常2スペース）
- [ ] コロン(:)の後にスペースがあるか
- [ ] リストアイテムのダッシュ(-)の後にスペースがあるか
- [ ] 複数行の文字列が適切に処理されているか（`>` や `|` の使用）

例：
```yaml
openapi: 3.0.0
info:
  title: Sample API
  description: |
    This is a sample API
    with a multi-line description.
  version: 1.0.0
```

### 1.2 OpenAPIバージョン
- [ ] 適切なOpenAPIバージョンが使用されているか（例：3.0.0, 3.1.0）
- [ ] 選択したバージョンと互換性のある機能のみが使用されているか

### 1.3 info セクション
- [ ] `title`: 簡潔で説明的なAPIの名前か
- [ ] `description`: APIの目的、主な機能、使用方法が明確に説明されているか
- [ ] `version`: セマンティックバージョニング（例：1.0.0）を使用しているか
- [ ] `contact`: 
  - [ ] 名前、メールアドレス、URLが提供されているか
  - [ ] 連絡先情報が最新かつ正確か
- [ ] `license`: 
  - [ ] 適切なライセンス（例：MIT、Apache 2.0）が指定されているか
  - [ ] ライセンスのURLが提供されているか

例：
```yaml
info:
  title: Bookstore API
  description: API for managing a bookstore's inventory and orders
  version: 1.2.3
  contact:
    name: API Support Team
    email: api-support@example.com
    url: https://example.com/support
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
```

## 2. サーバー情報

### 2.1 servers セクション
- [ ] 開発、ステージング、本番環境など、すべての関連環境が定義されているか
- [ ] 各サーバーのURLが正確か
- [ ] 変数を使用して柔軟性を持たせているか（該当する場合）

例：
```yaml
servers:
  - url: https://api.example.com/v1
    description: Production server
  - url: https://staging-api.example.com/v1
    description: Staging server
  - url: https://dev-api.example.com/v1
    description: Development server
  # パラメータ化されたサーバーURL
  - url: https://{environment}.api.example.com/{version}
    description: Parameterized server
    variables:
      # 環境変数: api, api-dev, api-stagingを選択可能
      environment:
        default: api
        enum:
          - api
          - api-dev
          - api-staging
      # バージョン変数: v1, v2を選択可能
      version:
        default: v1
        enum:
          - v1
          - v2
```

## 3. パス（Paths）

### 3.1 エンドポイント定義
- [ ] すべての主要なエンドポイントが定義されているか
- [ ] RESTful原則に従っているか（リソース指向、適切なHTTPメソッド）
- [ ] パスの命名が直感的で一貫しているか
  - 複数形の名詞を使用（例：`/users`、`/books`）
  - 階層構造を適切に表現（例：`/users/{userId}/orders`）

### 3.2 HTTPメソッド
- [ ] GET: リソースの取得に使用（例：`GET /users/{userId}`）
- [ ] POST: 新規リソースの作成に使用（例：`POST /users`）
- [ ] PUT: リソース全体の更新に使用（例：`PUT /users/{userId}`）
- [ ] PATCH: リソースの部分更新に使用（例：`PATCH /users/{userId}`）
- [ ] DELETE: リソースの削除に使用（例：`DELETE /users/{userId}`）

### 3.3 パスパラメータ
- [ ] パラメータ名が明確か（例：`userId`、`orderId`）
- [ ] データ型が指定されているか（例：`integer`、`string`）
- [ ] 必須パラメータが`required: true`とマークされているか
- [ ] パラメータの説明が提供されているか

例：
```yaml
paths:
  # ユーザー関連のエンドポイント
  /users/{userId}:
    get:
      summary: Get a user by ID
      parameters:
        # パスパラメータの定義
        - in: path
          name: userId
          required: true  # このパラメータは必須
          schema:
            type: integer  # userIdは整数型
          description: The unique identifier of the user
```

## 4. オペレーション

### 4.1 オペレーション概要
- [ ] 各オペレーションに適切な`summary`があるか（短く、動詞で始まる）
- [ ] 詳細な`description`が提供されているか
- [ ] `operationId`が一意で分かりやすいか（例：`getUserById`、`createOrder`）

### 4.2 リクエストパラメータ
- [ ] クエリパラメータ、ヘッダー、クッキーが適切に定義されているか
- [ ] 各パラメータにデータ型、説明、例が提供されているか
- [ ] 必須パラメータと任意パラメータが明確に区別されているか

### 4.3 リクエストボディ
- [ ] `content-type`が指定されているか（例：`application/json`）
- [ ] スキーマが正確に定義されているか
- [ ] 必須フィールドが明記されているか
- [ ] 例が提供されているか

### 4.4 レスポンス
- [ ] 成功レスポンス（200, 201など）が定義されているか
- [ ] エラーレスポンス（400, 401, 403, 404, 500など）が定義されているか
- [ ] 各レスポンスに適切な説明があるか
- [ ] レスポンススキーマが正確に定義されているか
- [ ] 例が提供されているか

例：
```yaml
paths:
  /users:
    post:
      summary: Create a new user
      operationId: createUser  # 一意の操作ID
      description: Creates a new user account with the provided information.
      requestBody:
        required: true  # リクエストボディは必須
        content:
          application/json:  # JSONフォーマットのみ受け付ける
            schema:
              $ref: '#/components/schemas/UserInput'  # UserInputスキーマを参照
            example:  # リクエストの例
              username: johndoe
              email: john@example.com
              password: securePassword123
      responses:
        '201':  # 成功時のレスポンス
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'  # 作成されたユーザー情報のスキーマ
        '400':  # エラー時のレスポンス
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'  # エラー情報のスキーマ
```

## 5. コンポーネント（Components）

### 5.1 スキーマ
- [ ] 再利用可能なスキーマが`components/schemas`に定義されているか
- [ ] スキーマ名がPascalCaseで適切か（例：`User`、`Order`）
- [ ] 各プロパティに適切な説明があるか
- [ ] 必須プロパティが`required`配列に明記されているか
- [ ] 適切なデータ型と制約が設定されているか

例：
```yaml
components:
  schemas:
    User:
      type: object
      required:  # これらのフィールドは必須
        - id
        - username
        - email
      properties:
        id:
          type: integer
          description: The unique identifier for the user
        username:
          type: string
          description: The user's chosen username
        email:
          type: string
          format: email  # 電子メールフォーマットを指定
          description: The user's email address
        createdAt:
          type: string
          format: date-time  # ISO 8601フォーマットの日時を指定
          description: The timestamp when the user account was created
```

### 5.2 セキュリティスキーム
- [ ] 適切なセキュリティスキーム（API key、OAuth2、JWT）が定義されているか
- [ ] OAuth2フローが正しく設定されているか（該当する場合）

例：
```yaml
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT  # JSON Web Token形式を使用
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:  # 認可コードフロー
          authorizationUrl: https://example.com/oauth/authorize  # 認可エンドポイント
          tokenUrl: https://example.com/oauth/token  # トークン発行エンドポイント
          scopes:  # 利用可能なスコープ
            read:users: Read user information
            write:users: Modify user information
```

## 6. セキュリティ

### 6.1 グローバルセキュリティ
- [ ] APIレベルのデフォルトセキュリティ要件が定義されているか

### 6.2 オペレーションレベルのセキュリティ
- [ ] 各エンドポイントに適切なセキュリティ要件が設定されているか
- [ ] 公開エンドポイントが明示的に指定されているか（`security: []`）

例：
```yaml
security:
  - BearerAuth: []  # グローバルセキュリティ設定：デフォルトでBearer認証を要求

paths:
  /users:
    get:
      summary: List all users
      security:
        - OAuth2: [read:users]  # このエンドポイントはOAuth2認証とread:usersスコープを要求
  /public-info:
    get:
      summary: Get public information
      security: []  # 認証不要のパブリックエンドポイント
```

## 7. データ型とフォーマット

### 7.1 プロパティのデータ型
- [ ] 適切なデータ型が使用されているか（string、number、integer、boolean、array、object）
- [ ] 文字列の特殊フォーマットが指定されているか（例：date-time、email、uuid）

### 7.2 制約
- [ ] 数値の`minimum`、`maximum`、`multipleOf`などの制約が設定されているか
- [ ] 文字列の`minLength`、`maxLength`、`pattern`などの制約が設定されているか
- [ ] 配列の`minItems`、`maxItems`、`uniqueItems`が指定されているか

### 7.3 列挙型
- [ ] 適切な場所で`enum`が使用されているか

例：
```yaml
components:
  schemas:
    Product:
      type: object
      properties:
        id:
          type: integer
          minimum: 1  # IDは1以上の正の整数
        name:
          type: string
          minLength: 1  # 空の文字列は許可しない
          maxLength: 100  # 名前は最大100文字まで
        price:
          type: number
          minimum: 0
          exclusiveMinimum: true  # 価格は0より大きい必要がある（0は含まない）
        category:
          type: string
          enum: [Electronics, Books, Clothing]  # カテゴリーは指定された3つのみ
        tags:
          type: array
          items:
            type: string
          minItems: 1  # 少なくとも1つのタグが必要
          maxItems: 5  # 最大5つまでのタグを許可
          uniqueItems: true  # 重複するタグは許可しない
```

## 8. エラーハンドリング

### 8.1 エラーレスポンス
- [ ] 一般的なHTTPステータスコードのエラーレスポンスが定義されているか
- [ ] エラーレスポンスの構造が一貫しているか

### 8.2 バリデーションエラー
- [ ] 入力バリデーションエラーの扱いが明確か
- [ ] 詳細なエラーメッセージが提供されているか

例：
```yaml
components:
  schemas:
    Error:
      type: object
      required:
        - code
        - message  # codeとmessageは必須フィールド
      properties:
        code:
          type: string  # エラーを識別するための一意のコード
        message:
          type: string  # ユーザーフレンドリーなエラーメッセージ
        details:
          type: array  # 詳細なエラー情報の配列（オプション）
          items:
            type: object
            properties:
              field:
                type: string  # エラーが発生したフィールド名
              reason:
                type: string  # そのフィールドでエラーが発生した理由

paths:
  /users:
    post:
      # ... other operation details ...
      responses:
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'  # 上で定義したErrorスキーマを参照
              example:
                code: VALIDATION_ERROR
                message: Invalid input
                details:
                  - field: email
                    reason: Must be a valid email address
```

## 9. ドキュメンテーション

### 9.1 説明
- [ ] 各エンドポイント、パラメータ、スキーマに十分な説明があるか
- [ ] 技術的でない人でも理解できる言葉で書かれているか

### 9.2 例
- [ ] リクエスト/レスポンスの例が`examples`セクションで提供されているか
- [ ] 複数のシナリオをカバーする例が提供されているか

### 9.3 拡張ドキュメント
- [ ] 複雑な概念や流れが`x-`拡張フィールドで説明されているか

例：
```yaml
paths:
  /orders:
    post:
      summary: Create a new order
      description: |
        Use this endpoint to create a new order in the system. 
        The order will be initially created with a status of 'pending'.
      x-business-rules:  # カスタム拡張フィールドでビジネスロジックを文書化
        - Orders over $1000 require manager approval
        - International shipping is not available for certain product categories
      requestBody:
        content:
          application/json:  # JSONフォーマットのリクエストボディを期待
            schema:
              $ref: '#/components/schemas/OrderInput'  # 注文入力のスキーマを参照
            examples:  # リクエストボディの例を複数提供
              simpleOrder:
                summary: A simple order with one item
                value:
                  customerId: 123  # 顧客ID
                  items:
                    - productId: 456  # 商品ID
                      quantity: 1  # 数量
              complexOrder:
                summary: A complex order with multiple items and shipping details
                value:
                  customerId: 789
                  items:  # 複数の商品を含む注文
                    - productId: 101
                      quantity: 2
                    - productId: 202
                      quantity: 1
                  shippingAddress:  # 配送先住所情報
                    street: 123 Main St
                    city: Anytown
                    country: US
```

## 10. 一貫性

### 10.1 命名規則
- [ ] パス: kebab-case（例：`/user-profiles`）
- [ ] パラメータ: camelCase（例：`userId`）
- [ ] スキーマ: PascalCase（例：`UserProfile`）
- [ ] プロパティ: camelCase（例：`firstName`）

### 10.2 バージョニング
- [ ] APIのバージョニング方針が明確か
- [ ] 以下のいずれかの方法で一貫してバージョニングされているか：
  - URLパス（例：`/v1/users`）
  - クエリパラメータ（例：`/users?version=1`）
  - カスタムヘッダー（例：`X-API-Version: 1`）

例：
```yaml
openapi: 3.0.0  # OpenAPI仕様のバージョン
info:
  version: 1.0.0  # APIのバージョン
servers:
  - url: https://api.example.com/v1  # APIのベースURL。バージョンがパスに含まれていることに注意

paths:
  /user-profiles:  # ユーザープロファイル関連のエンドポイント
    get:
      summary: List user profiles
      parameters:
        - name: pageSize  # ページネーションのためのクエリパラメータ
          in: query
          schema:
            type: integer
      responses:
        '200':  # 成功時のレスポンス
          description: Successful response
          content:
            application/json:    
              schema:
                $ref: '#/components/schemas/UserProfileList'  # レスポンスボディのスキーマを参照

components:
  schemas:
    UserProfile:  # ユーザープロファイルの構造を定義
      type: object
      properties:
        userId:
          type: integer
        firstName:
          type: string
        lastName:
          type: string
```

## 11. パフォーマンスと拡張性

### 11.1 ページネーション
- [ ] リスト取得エンドポイントにページネーションが実装されているか
- [ ] `limit`と`offset`、または`cursor`ベースのページネーションが使用されているか
- [ ] ページネーションのメタデータ（総件数、次ページのURL等）が提供されているか

### 11.2 部分的レスポンス
- [ ] フィールドの選択がサポートされているか（例：`fields`クエリパラメータ）

### 11.3 バルクオペレーション
- [ ] 一括作成、更新、削除操作が提供されているか（該当する場合）

### 11.4 レート制限
- [ ] レート制限の情報がドキュメントに含まれているか
- [ ] レート制限のヘッダー（X-RateLimit-Limit, X-RateLimit-Remaining等）が定義されているか

例：
```yaml
paths:
  /users:
    get:
      summary: List users
      # このエンドポイントは登録ユーザーの一覧を取得するために使用されます
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
          # 1回のリクエストで取得するユーザー数を制限します
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
          # ページネーションのために使用されます
        - name: fields
          in: query
          schema:
            type: string
            description: Comma-separated list of fields to include in the response
          # レスポンスに含めるフィールドをカスタマイズできます
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              # APIの利用制限の合計回数
            X-RateLimit-Remaining:
              schema:
                type: integer
              # 残りのAPI呼び出し回数
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                    # ユーザーオブジェクトの配列
                  meta:
                    type: object
                    properties:
                      totalCount:
                        type: integer
                      # 利用可能な全ユーザー数
                      nextPage:
                        type: string
                        format: uri
                      # 次のページのURIを提供し、ページネーションを容易にします
```

## 12. ベストプラクティス

### 12.1 HATEOAS
- [ ] リソース間のリンクが提供されているか（該当する場合）
- [ ] リンクの関係（rel）が明確に定義されているか

### 12.2 べき等性
- [ ] PUT、DELETEオペレーションがべき等に設計されているか
- [ ] べき等性を保証するためのメカニズム（例：ETags）が実装されているか

### 12.3 検索とフィルタリング
- [ ] 検索エンドポイントが適切に設計されているか
- [ ] フィルタリングパラメータが明確に定義されているか

### 12.4 ステータスコードの使用
- [ ] 適切なHTTPステータスコードが使用されているか
- [ ] カスタムステータスコードを避け、標準的なものを使用しているか

例：
```yaml
paths:
/articles:
  get:
    summary: Search articles
    # このエンドポイントは記事を検索し、フィルタリングするために使用されます
    parameters:
      - name: q
        in: query
        description: Search query
        schema:
          type: string
        # 記事の内容やタイトルなどを検索するためのクエリ文字列
      - name: category
        in: query
        description: Filter by category
        schema:
          type: string
        # 特定のカテゴリーに属する記事のみをフィルタリング
      - name: tags
        in: query
        description: Filter by tags (comma-separated)
        schema:
          type: string
        # 複数のタグでフィルタリングする場合、カンマ区切りで指定
    responses:
      '200':
        description: Successful response
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: array
                  items:
                    $ref: '#/components/schemas/Article'
                  # 検索結果の記事オブジェクトの配列
                links:
                  type: object
                  properties:
                    self:
                      type: string
                      format: uri
                      # 現在のページのURI
                    next:
                      type: string
                      format: uri
                      # 次のページのURI（ページネーション用）
```

## 13. その他

### 13.1 外部ドキュメント
- [ ] `externalDocs`セクションが提供されているか
- [ ] 外部ドキュメントへのリンクが有効で最新か

### 13.2 非推奨の機能
- [ ] 非推奨のフィールドや機能が`deprecated: true`でマークされているか
- [ ] 非推奨となった理由と代替手段が説明されているか

### 13.3 カスタム拡張
- [ ] カスタム拡張（`x-`プレフィックス）が適切に使用されているか
- [ ] カスタム拡張の目的と使用方法が文書化されているか

### 13.4 ファイルアップロード
- [ ] ファイルアップロード操作が正しく定義されているか（該当する場合）
- [ ] 許可されるファイル形式、サイズ制限などが明記されているか

例：
```yaml
paths:
  /users/{userId}/avatar:
    put:
      summary: Upload user avatar
      deprecated: true
      # このエンドポイントは非推奨であり、将来的に削除されます
      description: |
        This endpoint is deprecated and will be removed in the next major version.
        Please use the new `/users/{userId}/profile-image` endpoint instead.
      # 開発者に新しいエンドポイントへの移行を促します
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
          # ユーザーを一意に識別するためのID
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                avatar:
                  type: string
                  format: binary
                  # アップロードする画像ファイル。multipart/form-dataを使用
      responses:
        '200':
          description: Avatar uploaded successfully
          # アバターのアップロードが成功した場合のレスポンス

# API全体に関する追加情報
externalDocs:
  description: API Documentation
  url: https://docs.example.com/api
  # 詳細なAPI文書へのリンク

# Postmanコレクションへの参照
x-postman-collection:
  url: https://www.getpostman.com/collections/123456789
  # APIのテストや探索に使用できるPostmanコレクション
```

## 最終チェック

- [ ] すべてのエンドポイントが必要な認証とアクセス制御を持っているか
- [ ] センシティブなデータ（個人情報、認証情報など）が適切に扱われているか
- [ ] クロスオリジンリソース共有（CORS）の設定が適切か（該当する場合）
- [ ] 全体的な一貫性と読みやすさが確保されているか
- [ ] OpenAPI仕様のバリデーターでエラーや警告がないことを確認したか

# おわりに

このチェックリストを使用することで、OpenAPI YAMLドキュメントの品質と完全性を確保できます。プロジェクトの要件や特性に応じて、このリストをカスタマイズしたり、項目を追加したりすることをお勧めします。