mcpField
A
api-docs-generator

api-docs-generator

github.com/patricio0312rev開発63398 回インストール41 週間前に更新
リポジトリ

api-docs-generator について

API 開発者向けに、ルートやデータモデルを OpenAPI で記述し、インタラクティブなドキュメントを作成するスキルです。仕様の検証や、任意の SDK 生成も扱います。

主な機能

  1. 01OpenAPI 3.x 仕様の作成
  2. 02エンドポイント、パラメーター、レスポンスの記述
  3. 03リクエストとレスポンスのモデル定義
  4. 04Swagger UI または Redoc の設定
  5. 05仕様の検証と SDK 生成

活用シーン

  1. 01既存 API のドキュメント作成
  2. 02リクエストとレスポンスのスキーマや例の定義
  3. 03インタラクティブな API ドキュメントの公開
  4. 04仕様の確認とクライアント SDK 生成の設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/patricio0312rev/skills --skill api-docs-generator

インストール後、Claude Code で/api-docs-generatorを入力して読み込まれたか確認します。

詳細

API ドキュメントジェネレーター

OpenAPI 仕様とインタラクティブなドキュメントを使って、包括的な API ドキュメントを作成します。

基本的なワークフロー

  1. API エンドポイントを分析する:ルート、メソッド、パラメーターを確認します
  2. OpenAPI 仕様を定義する:YAML/JSON で仕様を作成します
  3. スキーマを追加する:リクエスト/レスポンスのモデルを定義します
  4. 例を含める:実際に即した値の例を追加します
  5. ドキュメントを生成する:インタラクティブなドキュメントをデプロイします
  6. SDK を作成する:必要に応じてクライアントライブラリを生成します

OpenAPI 仕様の構造

# openapi.yaml
openapi: 3.1.0

info:
  title: My API
  version: 1.0.0
  description: |
    API description with **Markdown** support.

    ## Authentication
    All endpoints require Bearer token authentication.
  contact:
    name: API Support
    email: [email protected]
    url: https://docs.example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: https://staging-api.example.com/v1
    description: Staging
  - url: http://localhost:3000/v1
    description: Development

tags:
  - name: Users
    description: User management endpoints
  - name: Products
    description: Product catalog endpoints
  - name: Orders
    description: Order processing endpoints

paths:
  # Endpoints defined here

components:
  # Reusable schemas, security, etc.

パス定義

基本的な CRUD エンドポイント
paths:
  /users:
    get:
      tags:
        - Users
      summary: List all users
      description: Retrieve a paginated list of users
      operationId: listUsers
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
        - name: role
          in: query
          description: Filter by user role
          schema:
            type: string
            enum: [admin, user, guest]
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
              example:
                data:
                  - id: "usr_123"
                    email: "[email protected]"
                    name: "John Doe"
                    role: "admin"
                    createdAt: "2024-01-15T10:30:00Z"
                pagination:
                  page: 1
                  limit: 20
                  total: 150
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

    post:
      tags:
        - Users
      summary: Create a new user
      description: Create a new user account
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
            example:
              email: "[email protected]"
              name: "New User"
              password: "securePassword123"
              role: "user"
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: User already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                code: "USER_EXISTS"
                message: "A user with this email already exists"
        '422':
          $ref: '#/components/responses/ValidationError'

  /users/{userId}:
    parameters:
      - $ref: '#/components/parameters/UserId'

    get:
      tags:
        - Users
      summary: Get user by ID
      description: Retrieve a specific user by their ID
      operationId: getUserById
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Users
      summary: Update user
      description: Update an existing user's information
      operationId: updateUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserRequest'
      responses:
        '200':
          description: User updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Users
      summary: Delete user
      description: Permanently delete a user
      operationId: deleteUser
      responses:
        '204':
          description: User deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'

コンポーネントスキーマ

データモデル
components:
  schemas:
    # Base User Schema
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique user identifier
          example: "usr_123abc"
          readOnly: true
        email:
          type: string
          format: email
          description: User's email address
          example: "[email protected]"
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: User's full name
          example: "John Doe"
        role:
          $ref: '#/components/schemas/UserRole'
        avatar:
          type: string
          format: uri
          nullable: true
          description: URL to user's avatar image
          example: "https://cdn.example.com/avatars/123.jpg"
        createdAt:
          type: string
          format: date-time
          description: Account creation timestamp
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          description: Last update timestamp
          readOnly: true
      required:
        - id
        - email
        - name
        - role
        - createdAt

    UserRole:
      type: string
      enum:
        - admin
        - user
        - guest
      description: User's role in the system
      example: "user"

    # Request Schemas
    CreateUserRequest:
      type: object
      properties:
        email:
          type: string
          format: email
        name:
          type: string
          minLength: 1
          maxLength: 100
        password:
          type: string
          format: password
          minLength: 8
          description: Must contain at least one uppercase, one lowercase, and one number
        role:
          $ref: '#/components/schemas/UserRole'
      required:
        - email
        - name
        - password

    UpdateUserRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        role:
          $ref: '#/components/schemas/UserRole'
        avatar:
          type: string
          format: uri
          nullable: true
      minProperties: 1

    # List Response
    UserList:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/User'
        pagination:
          $ref: '#/components/schemas/Pagination'

    Pagination:
      type: object
      properties:
        page:
          type: integer
          minimum: 1
          example: 1
        limit:
          type: integer
          minimum: 1
          maximum: 100
          example: 20
        total:
          type: integer
          minimum: 0
          example: 150
        hasMore:
          type: boolean
          example: true

    # Error Schemas
    Error:
      type: object
      properties:
        code:
          type: string
          description: Machine-readable error code
          example: "VALIDATION_ERROR"
        message:
          type: string
          description: Human-readable error message
          example: "The request body is invalid"
        details:
          type: array
          items:
            $ref: '#/components/schemas/ErrorDetail'
      required:
        - code
        - message

    ErrorDetail:
      type: object
      properties:
        field:
          type: string
          description: The field that caused the error
          example: "email"
        message:
          type: string
          description: Description of the validation error
          example: "Must be a valid email address"

パラメーターとレスポンス

components:
  parameters:
    UserId:
      name: userId
      in: path
      required: true
      description: Unique user identifier
      schema:
        type: string
        format: uuid
      example: "usr_123abc"

    PageParam:
      name: page
      in: query
      description: Page number for pagination
      schema:
        type: integer
        minimum: 1
        default: 1
      example: 1

    LimitParam:
      name: limit
      in: query
      description: Number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      example: 20

    SortParam:
      name: sort
      in: query
      description: Sort field and direction
      schema:
        type: string
        pattern: '^[a-zA-Z]+:(asc|desc)$'
      example: "createdAt:desc"

  responses:
    BadRequest:
      description: Bad request - invalid input
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "BAD_REQUEST"
            message: "Invalid request format"

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "UNAUTHORIZED"
            message: "Authentication token is missing or invalid"

    Forbidden:
      description: Permission denied
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "FORBIDDEN"
            message: "You don't have permission to access this resource"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "NOT_FOUND"
            message: "The requested resource was not found"

    ValidationError:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "VALIDATION_ERROR"
            message: "Request validation failed"
            details:
              - field: "email"
                message: "Must be a valid email address"
              - field: "password"
                message: "Must be at least 8 characters"

    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: "INTERNAL_ERROR"
            message: "An unexpected error occurred"

セキュリティ定義

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT token obtained from the /auth/login endpoint.

        Example: `Authorization: Bearer eyJhbGciOiJIUzI1...`

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for server-to-server communication

    OAuth2:
      type: oauth2
      description: OAuth 2.0 authentication
      flows:
        authorizationCode:
          authorizationUrl: https://auth.example.com/oauth/authorize
          tokenUrl: https://auth.example.com/oauth/token
          scopes:
            read:users: Read user information
            write:users: Create and modify users
            admin: Full administrative access

# Apply security globally
security:
  - BearerAuth: []

# Or per-endpoint
paths:
  /public/health:
    get:
      security: []  # No auth required
      summary: Health check
      responses:
        '200':
          description: Service is healthy

Express/Node.js との統合

express-openapi でコードから生成する
// src/docs/openapi.ts
import { OpenAPIV3_1 } from 'openapi-types';

export const openApiDocument: OpenAPIV3_1.Document = {
  openapi: '3.1.0',
  info: {
    title: 'My API',
    version: '1.0.0',
    description: 'API documentation',
  },
  servers: [
    { url: 'http://localhost:3000', description: 'Development' },
  ],
  paths: {},
  components: {
    schemas: {},
    securitySchemes: {
      BearerAuth: {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
      },
    },
  },
};
Swagger UI Express
// src/docs/swagger.ts
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
import path from 'path';
import { Express } from 'express';

export function setupSwagger(app: Express) {
  const swaggerDocument = YAML.load(
    path.join(__dirname, '../../openapi.yaml')
  );

  const options: swaggerUi.SwaggerUiOptions = {
    explorer: true,
    customSiteTitle: 'API Documentation',
    customCss: '.swagger-ui .topbar { display: none }',
    swaggerOptions: {
      persistAuthorization: true,
      displayRequestDuration: true,
      filter: true,
      showExtensions: true,
    },
  };

  app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
  app.get('/openapi.json', (req, res) => res.json(swaggerDocument));
}
Zod から OpenAPI への変換
// src/schemas/user.ts
import { z } from 'zod';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';

extendZodWithOpenApi(z);

export const UserSchema = z.object({
  id: z.string().uuid().openapi({ example: 'usr_123abc' }),
  email: z.string().email().openapi({ example: '[email protected]' }),
  name: z.string().min(1).max(100).openapi({ example: 'John Doe' }),
  role: z.enum(['admin', 'user', 'guest']).openapi({ example: 'user' }),
  createdAt: z.string().datetime(),
}).openapi('User');

export const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
  password: z.string().min(8),
  role: z.enum(['admin', 'user', 'guest']).optional().default('user'),
}).openapi('CreateUserRequest');
// src/docs/generator.ts
import {
  OpenAPIRegistry,
  OpenApiGeneratorV31,
} from '@asteasolutions/zod-to-openapi';
import { UserSchema, CreateUserSchema } from '../schemas/user';

const registry = new OpenAPIRegistry();

// Register schemas
registry.register('User', UserSchema);
registry.register('CreateUserRequest', CreateUserSchema);

// Register endpoints
registry.registerPath({
  method: 'get',
  path: '/users',
  tags: ['Users'],
  summary: 'List all users',
  responses: {
    200: {
      description: 'List of users',
      content: {
        'application/json': {
          schema: z.array(UserSchema),
        },
      },
    },
  },
});

registry.registerPath({
  method: 'post',
  path: '/users',
  tags: ['Users'],
  summary: 'Create a user',
  request: {
    body: {
      content: {
        'application/json': {
          schema: CreateUserSchema,
        },
      },
    },
  },
  responses: {
    201: {
      description: 'User created',
      content: {
        'application/json': {
          schema: UserSchema,
        },
      },
    },
  },
});

// Generate OpenAPI document
const generator = new OpenApiGeneratorV31(registry.definitions);
export const openApiDocument = generator.generateDocument({
  openapi: '3.1.0',
  info: {
    title: 'My API',
    version: '1.0.0',
  },
});

FastAPI との統合

# main.py
from fastapi import FastAPI, HTTPException, Query
from fastapi.openapi.utils import get_openapi
from pydantic import BaseModel, EmailStr, Field
from typing import Optional
from datetime import datetime
from enum import Enum

app = FastAPI(
    title="My API",
    description="API documentation with FastAPI",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
)


class UserRole(str, Enum):
    admin = "admin"
    user = "user"
    guest = "guest"


class UserBase(BaseModel):
    email: EmailStr = Field(..., example="[email protected]")
    name: str = Field(..., min_length=1, max_length=100, example="John Doe")
    role: UserRole = Field(default=UserRole.user, example="user")


class UserCreate(UserBase):
    password: str = Field(..., min_length=8, example="securePassword123")


class User(UserBase):
    id: str = Field(..., example="usr_123abc")
    created_at: datetime
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class UserList(BaseModel):
    data: list[User]
    total: int
    page: int
    limit: int


@app.get(
    "/users",
    response_model=UserList,
    tags=["Users"],
    summary="List all users",
    description="Retrieve a paginated list of users",
)
async def list_users(
    page: int = Query(1, ge=1, description="Page number"),
    limit: int = Query(20, ge=1, le=100, description="Items per page"),
    role: Optional[UserRole] = Query(None, description="Filter by role"),
):
    # Implementation
    pass


@app.post(
    "/users",
    response_model=User,
    status_code=201,
    tags=["Users"],
    summary="Create a new user",
    responses={
        409: {"description": "User already exists"},
        422: {"description": "Validation error"},
    },
)
async def create_user(user: UserCreate):
    # Implementation
    pass


# Custom OpenAPI schema
def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema

    openapi_schema = get_openapi(
        title="My API",
        version="1.0.0",
        description="API documentation",
        routes=app.routes,
    )

    # Add security scheme
    openapi_schema["components"]["securitySchemes"] = {
        "BearerAuth": {
            "type": "http",
            "scheme": "bearer",
            "bearerFormat": "JWT",
        }
    }
    openapi_schema["security"] = [{"BearerAuth": []}]

    app.openapi_schema = openapi_schema
    return app.openapi_schema


app.openapi = custom_openapi

ドキュメントジェネレーター

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' expand-responses="200,201"></redoc>
    <script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
  </body>
</html>
Stoplight Elements
<!DOCTYPE html>
<html>
  <head>
    <title>API Documentation</title>
    <script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
  </head>
  <body>
    <elements-api
      apiDescriptionUrl="/openapi.yaml"
      router="hash"
      layout="sidebar"
    />
  </body>
</html>

SDK の生成

OpenAPI Generator
# Install OpenAPI Generator
npm install -g @openapitools/openapi-generator-cli

# Generate TypeScript client
openapi-generator-cli generate \
  -i openapi.yaml \
  -g typescript-fetch \
  -o ./sdk/typescript \
  --additional-properties=supportsES6=true,npmName=@myorg/api-client

# Generate Python client
openapi-generator-cli generate \
  -i openapi.yaml \
  -g python \
  -o ./sdk/python \
  --additional-properties=packageName=myapi_client
設定
# openapitools.json
{
  "$schema": "https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator-gradle-plugin/src/main/resources/openapitools.json",
  "spaces": 2,
  "generator-cli": {
    "version": "7.0.0",
    "generators": {
      "typescript-client": {
        "generatorName": "typescript-fetch",
        "inputSpec": "./openapi.yaml",
        "output": "./sdk/typescript",
        "additionalProperties": {
          "supportsES6": true,
          "npmName": "@myorg/api-client",
          "npmVersion": "1.0.0"
        }
      }
    }
  }
}

検証

Spectral によるリンティング
# .spectral.yaml
extends: ["spectral:oas", "spectral:asyncapi"]

rules:
  operation-operationId: error
  operation-description: warn
  operation-tags: error
  info-contact: warn
  info-license: warn
  oas3-schema: error
  oas3-valid-media-example: warn

  # Custom rules
  path-must-have-tag:
    given: "$.paths[*][*]"
    severity: error
    then:
      field: tags
      function: truthy
# Run linting
npx @stoplight/spectral-cli lint openapi.yaml

ベストプラクティス

  1. 再利用には $ref を使用する:スキーマを一度定義し、あらゆる場所から参照します
  2. 例を含める:すべてのスキーマに実際に即した例を追加します
  3. エラーを文書化する:考えられるすべてのエラーレスポンスを説明します
  4. API をバージョン管理する:URL またはヘッダーによるバージョン管理を使用します
  5. タグでグループ化する:エンドポイントを論理的に整理します
  6. 説明を追加する:すべてのパラメーターとフィールドを説明します
  7. セキュリティスキームを使用する:認証について明確に文書化します
  8. 仕様を検証する:Spectral などのツールを使用します
  9. SDK を生成する:クライアントライブラリの作成を自動化します
  10. 仕様を最新の状態に保つ:コードから生成するか、コードとの整合性を検証します

出力チェックリスト

すべての API ドキュメントには、次の項目を含める必要があります。

  • 完全な OpenAPI 3.x 仕様
  • すべてのエンドポイントを例とともに文書化
  • 型を含むリクエスト/レスポンスのスキーマ
  • エラーレスポンスの文書化
  • 認証スキームの定義
  • 例を含むパラメーターの説明
  • インタラクティブなドキュメントのデプロイ(Swagger UI/Redoc)
  • リンターによる仕様の検証
  • SDK 生成の設定
  • バージョン管理戦略の文書化

コメント