スキル一覧に戻る
ils15

api-design-patterns

by ils15

GitHub Copilot agents and instructions for reuse across projects

0🍴 0📅 2026年1月23日
GitHubで見るManusで実行

SKILL.md


name: api-design-patterns description: Design RESTful APIs with proper HTTP methods, status codes, pagination, filtering, error responses, and OpenAPI documentation. Follows FastAPI best practices with Pydantic validation.

API Design Patterns Skill

When to Use

Use this skill when:

  • Designing new API endpoints
  • Reviewing API consistency
  • Implementing pagination and filtering
  • Creating error response formats
  • Writing OpenAPI documentation
  • Validating HTTP status codes
  • Building request/response schemas

RESTful Design Principles

1. HTTP Methods

GET    /users          - List users
GET    /users/{id}     - Get single user
POST   /users          - Create user
PUT    /users/{id}     - Full update
PATCH  /users/{id}     - Partial update
DELETE /users/{id}     - Delete user

2. Status Codes

2xx Success:
- 200 OK              - Successful GET, PUT, PATCH
- 201 Created         - Successful POST
- 204 No Content      - Successful DELETE

4xx Client Errors:
- 400 Bad Request     - Invalid input
- 401 Unauthorized    - Not authenticated
- 403 Forbidden       - Not authorized
- 404 Not Found       - Resource not found
- 409 Conflict        - Duplicate resource
- 422 Unprocessable   - Validation error

5xx Server Errors:
- 500 Internal Error  - Unexpected error
- 503 Service Unavail - Maintenance

3. Pagination Pattern

from pydantic import BaseModel
from typing import Generic, TypeVar, List

T = TypeVar('T')

class PaginatedResponse(BaseModel, Generic[T]):
    items: List[T]
    total: int
    page: int
    size: int
    pages: int
    
    class Config:
        from_attributes = True

# Endpoint
@router.get("/users", response_model=PaginatedResponse[UserResponse])
async def list_users(
    page: int = Query(1, ge=1),
    size: int = Query(20, ge=1, le=100),
):
    total = await user_service.count()
    items = await user_service.get_page(page, size)
    return PaginatedResponse(
        items=items,
        total=total,
        page=page,
        size=size,
        pages=(total + size - 1) // size
    )

4. Filtering Pattern

from typing import Optional
from fastapi import Query

@router.get("/products")
async def list_products(
    # Search
    q: Optional[str] = Query(None, min_length=2, max_length=100),
    
    # Filters
    category: Optional[str] = None,
    min_price: Optional[float] = Query(None, ge=0),
    max_price: Optional[float] = Query(None, ge=0),
    in_stock: Optional[bool] = None,
    
    # Sorting
    sort_by: str = Query("created_at", regex="^(name|price|created_at)$"),
    order: str = Query("desc", regex="^(asc|desc)$"),
    
    # Pagination
    page: int = Query(1, ge=1),
    size: int = Query(20, ge=1, le=100),
):
    return await product_service.search(
        q=q, category=category, 
        min_price=min_price, max_price=max_price,
        in_stock=in_stock,
        sort_by=sort_by, order=order,
        page=page, size=size
    )

5. Error Response Format

from pydantic import BaseModel
from typing import Optional, List

class ErrorDetail(BaseModel):
    loc: List[str]
    msg: str
    type: str

class ErrorResponse(BaseModel):
    error: str
    message: str
    details: Optional[List[ErrorDetail]] = None
    request_id: Optional[str] = None

# Usage
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content=ErrorResponse(
            error=exc.detail,
            message=str(exc.detail),
            request_id=request.state.request_id
        ).model_dump()
    )

6. Request/Response Schemas

from pydantic import BaseModel, EmailStr, Field
from datetime import datetime
from typing import Optional

# Create (input)
class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(..., min_length=2, max_length=100)
    password: str = Field(..., min_length=8)

# Update (partial)
class UserUpdate(BaseModel):
    email: Optional[EmailStr] = None
    name: Optional[str] = Field(None, min_length=2, max_length=100)

# Response (output)
class UserResponse(BaseModel):
    id: int
    email: str
    name: str
    created_at: datetime
    
    class Config:
        from_attributes = True

# List response
class UserListResponse(BaseModel):
    id: int
    name: str  # Minimal fields for list

7. OpenAPI Documentation

@router.post(
    "/users",
    response_model=UserResponse,
    status_code=201,
    summary="Create a new user",
    description="Register a new user account with email and password.",
    responses={
        201: {"description": "User created successfully"},
        400: {"description": "Invalid input data"},
        409: {"description": "Email already exists"},
    },
    tags=["users"],
)
async def create_user(user: UserCreate):
    """
    Create a new user with the following information:
    
    - **email**: valid email address (unique)
    - **name**: user display name (2-100 chars)
    - **password**: secure password (min 8 chars)
    """
    return await user_service.create(user)

Output Format

## API Design Review

### Endpoints Analyzed
- GET /users - ✅ Correct
- POST /users - ⚠️ Missing 409 response
- DELETE /users/{id} - ❌ Returns 200 (should be 204)

### Issues Found
1. [Endpoint] - [Issue] - [Fix]

### Recommendations
1. Add pagination to list endpoints
2. Standardize error response format
3. Add request_id to all responses

Example Usage

@backend Design CRUD endpoints for products resource
@backend Review API consistency across all endpoints
@backend Add pagination to the orders list endpoint
@backend Create error response schema for the API

スコア

総合スコア

40/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です