matteocervelli

api-designer

16
1
# Install this skill:
npx skills add matteocervelli/llms --skill "api-designer"

Install specific skill from multi-skill repository

# Description

Design REST APIs or function contracts with clear request/response specifications,

# SKILL.md


name: api-designer
description: Design REST APIs or function contracts with clear request/response specifications,
error handling patterns, authentication strategies, and comprehensive documentation.
allowed-tools: Read, Write, Edit


Purpose

The api-designer skill provides comprehensive guidance for designing robust, RESTful APIs and function contracts that serve as clear interfaces for feature implementations. This skill helps the Architecture Designer agent create well-structured, documented, and maintainable API designs that follow industry best practices.

This skill emphasizes:
- REST Principles: Proper resource design, HTTP method usage, and status codes
- Clear Contracts: Well-defined request/response schemas
- Error Handling: Consistent error response formats
- Authentication: Security patterns and authorization strategies
- Documentation: Comprehensive API documentation for consumers

The api-designer skill ensures that APIs are intuitive, consistent, and provide excellent developer experience for both internal and external consumers.

When to Use

This skill auto-activates when the agent describes:
- "Design API endpoints for..."
- "Create REST API for..."
- "Define function contract for..."
- "Specify request/response schemas..."
- "Design authentication for..."
- "Plan API structure with..."
- "Define error responses for..."
- "Create API documentation for..."

Provided Capabilities

1. REST API Endpoint Design

What it provides:
- Resource identification and naming
- HTTP method selection (GET, POST, PUT, PATCH, DELETE)
- URL structure and path parameters
- Query parameter design
- Status code selection
- Idempotency considerations

REST Principles:
- Resources as nouns, not verbs
- HTTP methods for actions
- Stateless design
- Standard status codes
- HATEOAS (optional)

Example:

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

# ==================== RESOURCE: Users ====================

class UserCreate(BaseModel):
    """Request schema for creating user."""
    username: str = Field(..., min_length=3, max_length=50)
    email: str = Field(...)
    full_name: str = Field(..., min_length=1, max_length=200)

class UserResponse(BaseModel):
    """Response schema for user."""
    id: int
    username: str
    email: str
    full_name: str
    is_active: bool
    created_at: datetime

class UserUpdate(BaseModel):
    """Request schema for updating user (all optional)."""
    email: Optional[str] = None
    full_name: Optional[str] = None
    is_active: Optional[bool] = None

class UserList(BaseModel):
    """Response schema for user list with pagination."""
    items: List[UserResponse]
    total: int
    page: int
    page_size: int
    total_pages: int

# API Endpoints
"""
POST   /api/v1/users              Create new user
GET    /api/v1/users              List users (with pagination)
GET    /api/v1/users/{user_id}    Get user by ID
PUT    /api/v1/users/{user_id}    Update user (full replace)
PATCH  /api/v1/users/{user_id}    Update user (partial)
DELETE /api/v1/users/{user_id}    Delete user

Query Parameters for GET /api/v1/users:
- page: int = 1          (pagination)
- page_size: int = 20    (items per page)
- search: str = None     (search filter)
- is_active: bool = None (status filter)
- sort_by: str = "created_at"
- sort_order: str = "desc"

Status Codes:
- 200 OK: Successful GET, PUT, PATCH
- 201 Created: Successful POST
- 204 No Content: Successful DELETE
- 400 Bad Request: Invalid input
- 401 Unauthorized: Authentication required
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Resource not found
- 409 Conflict: Resource conflict (duplicate)
- 422 Unprocessable Entity: Validation error
- 500 Internal Server Error: Server error
"""

2. Request/Response Schema Design

What it provides:
- Input validation schemas
- Output serialization schemas
- Partial update schemas
- List/pagination schemas
- Error response schemas

Schema Patterns:

Create Request (POST):

class ResourceCreate(BaseModel):
    """All fields required for creation."""
    name: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=1000)
    category: str = Field(...)

Update Request (PUT - Full Replace):

class ResourceUpdate(BaseModel):
    """All fields required for full update."""
    name: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=1000)
    category: str = Field(...)

Partial Update Request (PATCH):

class ResourcePatch(BaseModel):
    """All fields optional for partial update."""
    name: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=1000)
    category: Optional[str] = None

Response Schema:

class ResourceResponse(BaseModel):
    """Response includes ID and audit fields."""
    id: int
    name: str
    description: Optional[str]
    category: str
    created_at: datetime
    updated_at: Optional[datetime]

    class Config:
        orm_mode = True  # Enable ORM integration

List Response with Pagination:

class PaginatedResponse(BaseModel):
    """Generic paginated response."""
    items: List[ResourceResponse]
    total: int = Field(..., description="Total number of items")
    page: int = Field(..., description="Current page number", ge=1)
    page_size: int = Field(..., description="Items per page", ge=1, le=100)
    total_pages: int = Field(..., description="Total number of pages")

    @property
    def has_next(self) -> bool:
        """Check if there's a next page."""
        return self.page < self.total_pages

    @property
    def has_previous(self) -> bool:
        """Check if there's a previous page."""
        return self.page > 1

3. Error Response Formats

What it provides:
- Consistent error structure
- Error codes and types
- Detailed validation errors
- User-friendly messages
- Debug information (optional)

Standard Error Response:

from typing import Optional, List, Dict, Any

class ValidationError(BaseModel):
    """Individual validation error."""
    field: str = Field(..., description="Field name with error")
    message: str = Field(..., description="Error message")
    code: str = Field(..., description="Error code")

class ErrorResponse(BaseModel):
    """Standard error response."""
    error: str = Field(..., description="Error type (e.g., 'validation_error')")
    message: str = Field(..., description="Human-readable error message")
    details: Optional[List[ValidationError]] = Field(None, description="Validation errors")
    request_id: Optional[str] = Field(None, description="Request ID for tracking")
    timestamp: datetime = Field(default_factory=datetime.utcnow)

    class Config:
        schema_extra = {
            "example": {
                "error": "validation_error",
                "message": "Request validation failed",
                "details": [
                    {
                        "field": "email",
                        "message": "Invalid email format",
                        "code": "invalid_format"
                    }
                ],
                "request_id": "req_abc123",
                "timestamp": "2025-10-29T10:00:00Z"
            }
        }

# Error Types
"""
validation_error: Request validation failed (400)
authentication_error: Authentication failed (401)
authorization_error: Insufficient permissions (403)
not_found_error: Resource not found (404)
conflict_error: Resource conflict (409)
rate_limit_error: Rate limit exceeded (429)
internal_error: Internal server error (500)
"""

4. Authentication and Authorization

What it provides:
- Authentication patterns (JWT, OAuth2, API Key)
- Authorization strategies (RBAC, ABAC)
- Token validation
- Permission checking
- Security headers

JWT Authentication Example:

from pydantic import BaseModel, Field
from typing import Optional, List

class LoginRequest(BaseModel):
    """Login request schema."""
    username: str = Field(..., min_length=1)
    password: str = Field(..., min_length=1)

class TokenResponse(BaseModel):
    """Token response schema."""
    access_token: str = Field(..., description="JWT access token")
    token_type: str = Field(default="bearer", description="Token type")
    expires_in: int = Field(..., description="Token expiration in seconds")
    refresh_token: Optional[str] = Field(None, description="Refresh token")

class TokenPayload(BaseModel):
    """JWT token payload."""
    sub: int = Field(..., description="User ID (subject)")
    username: str = Field(..., description="Username")
    roles: List[str] = Field(default_factory=list, description="User roles")
    exp: int = Field(..., description="Expiration timestamp")

# API Endpoints
"""
POST /api/v1/auth/login          Login and get token
POST /api/v1/auth/refresh        Refresh access token
POST /api/v1/auth/logout         Logout (invalidate token)

Authentication Header:
Authorization: Bearer <access_token>

Example:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
"""

Role-Based Access Control (RBAC):

from enum import Enum

class UserRole(str, Enum):
    """User roles for RBAC."""
    ADMIN = "admin"
    MANAGER = "manager"
    USER = "user"
    GUEST = "guest"

class Permission(str, Enum):
    """Permissions for resources."""
    CREATE = "create"
    READ = "read"
    UPDATE = "update"
    DELETE = "delete"

# Permission Matrix
"""
Resource: Users
- ADMIN: create, read, update, delete
- MANAGER: read, update
- USER: read (own profile only)
- GUEST: read (public profiles only)

Endpoint Protection:
POST   /api/v1/users              Requires: admin
GET    /api/v1/users              Requires: admin, manager
GET    /api/v1/users/{user_id}    Requires: authenticated
PUT    /api/v1/users/{user_id}    Requires: admin OR owner
DELETE /api/v1/users/{user_id}    Requires: admin
"""

5. Rate Limiting

What it provides:
- Rate limit strategies
- Rate limit headers
- Error responses for exceeded limits
- Quota management

Rate Limit Design:

class RateLimitInfo(BaseModel):
    """Rate limit information."""
    limit: int = Field(..., description="Requests allowed per window")
    remaining: int = Field(..., description="Requests remaining")
    reset: int = Field(..., description="Unix timestamp when limit resets")
    window: int = Field(..., description="Time window in seconds")

# Rate Limit Headers
"""
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1730203200
X-RateLimit-Window: 3600

Rate Limit Tiers:
- Anonymous: 10 requests/hour
- Authenticated: 100 requests/hour
- Premium: 1000 requests/hour
- Admin: Unlimited

Status Code: 429 Too Many Requests
Response:
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Try again in 3600 seconds.",
  "limit": 100,
  "window": 3600,
  "reset": 1730203200
}
"""

6. API Versioning

What it provides:
- Versioning strategies
- Version migration paths
- Backward compatibility
- Deprecation notices

Versioning Strategies:

URL Path Versioning (Recommended):

/api/v1/users
/api/v2/users

Pros: Clear, explicit, easy to route
Cons: URLs change between versions

Header Versioning:

GET /api/users
Accept-Version: v1

GET /api/users
Accept-Version: v2

Pros: Clean URLs
Cons: Less visible, harder to test in browser

Query Parameter Versioning:

/api/users?version=1
/api/users?version=2

Pros: Flexible
Cons: Easy to forget, pollutes query params

Deprecation Example:

class DeprecationWarning(BaseModel):
    """Deprecation warning in response header."""
    deprecated: bool = True
    sunset_date: str = "2026-01-01"
    replacement_url: str = "/api/v2/users"
    documentation: str = "https://api.example.com/docs/migration/v1-to-v2"

# Response Headers for Deprecated Endpoint
"""
X-API-Deprecated: true
X-API-Sunset: 2026-01-01
X-API-Replacement: /api/v2/users
Link: <https://api.example.com/docs/migration/v1-to-v2>; rel="deprecation"
"""

Usage Guide

Step 1: Identify Resources

Requirements β†’ Identify nouns β†’ Define resources β†’ Name endpoints

Step 2: Design Endpoints

Resources β†’ HTTP methods β†’ URL structure β†’ Path/query params

Step 3: Define Schemas

Create schemas β†’ Update schemas β†’ Response schemas β†’ Error schemas

Step 4: Plan Authentication

Identify auth needs β†’ Choose strategy β†’ Define tokens β†’ Permission model

Step 5: Error Handling

Identify error cases β†’ Standard format β†’ Status codes β†’ Error messages

Step 6: Rate Limiting

Define tiers β†’ Set limits β†’ Response headers β†’ Exceeded handling

Step 7: Documentation

OpenAPI spec β†’ Examples β†’ Authentication guide β†’ Error reference

Step 8: Versioning Strategy

Choose approach β†’ Migration plan β†’ Deprecation policy β†’ Documentation

Best Practices

  1. Use Proper HTTP Methods
  2. GET: Retrieve resources (idempotent, safe)
  3. POST: Create resources (non-idempotent)
  4. PUT: Full replace (idempotent)
  5. PATCH: Partial update (idempotent)
  6. DELETE: Remove resource (idempotent)

  7. Consistent Naming

  8. Use plural nouns: /users, /posts
  9. Use kebab-case: /user-profiles
  10. Avoid verbs: /users not /getUsers

  11. Status Codes

  12. 2xx: Success
  13. 4xx: Client errors
  14. 5xx: Server errors
  15. Be specific: 201 for created, 204 for no content

  16. Pagination

  17. Always paginate lists
  18. Provide total count
  19. Include next/previous links (HATEOAS)

  20. Filtering and Sorting

  21. Use query params: ?status=active&sort=created_at
  22. Document available filters
  23. Provide defaults

  24. Security

  25. Always use HTTPS
  26. Validate all input
  27. Rate limit requests
  28. Use proper authentication

Resources

api-design-guide.md

Comprehensive API design guide including:
- REST principles and best practices
- GraphQL patterns (if applicable)
- Request/response schema design
- Error response formats
- Authentication/authorization patterns
- Rate limiting strategies
- API versioning approaches
- Documentation standards

function-design-patterns.md

Function contract design patterns:
- Function signature design
- Parameter patterns (required, optional, defaults)
- Return type patterns
- Error handling in functions
- Async function patterns
- Type hints for functions
- Docstring standards

Example Usage

Input (from Architecture Designer agent):

"Design REST API for a task management system with tasks, projects, users, and comments."

Output (api-designer skill provides):

# Complete API design with endpoints and schemas

from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
from enum import Enum

# ==================== ENUMS ====================

class TaskStatus(str, Enum):
    """Task status options."""
    TODO = "todo"
    IN_PROGRESS = "in_progress"
    DONE = "done"

class TaskPriority(str, Enum):
    """Task priority levels."""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"

# ==================== REQUEST SCHEMAS ====================

class TaskCreate(BaseModel):
    """Create task request."""
    title: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)
    project_id: int = Field(..., gt=0)
    assignee_id: Optional[int] = Field(None, gt=0)
    priority: TaskPriority = TaskPriority.MEDIUM
    due_date: Optional[datetime] = None

class TaskUpdate(BaseModel):
    """Update task request (partial)."""
    title: Optional[str] = Field(None, min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)
    assignee_id: Optional[int] = Field(None, gt=0)
    status: Optional[TaskStatus] = None
    priority: Optional[TaskPriority] = None
    due_date: Optional[datetime] = None

class CommentCreate(BaseModel):
    """Create comment request."""
    content: str = Field(..., min_length=1, max_length=1000)

# ==================== RESPONSE SCHEMAS ====================

class TaskResponse(BaseModel):
    """Task response schema."""
    id: int
    title: str
    description: Optional[str]
    project_id: int
    assignee_id: Optional[int]
    status: TaskStatus
    priority: TaskPriority
    due_date: Optional[datetime]
    created_at: datetime
    updated_at: Optional[datetime]
    created_by: int

    class Config:
        orm_mode = True

class TaskListResponse(BaseModel):
    """Paginated task list response."""
    items: List[TaskResponse]
    total: int
    page: int
    page_size: int
    total_pages: int

# ==================== API ENDPOINTS ====================
"""
Base URL: /api/v1

Authentication: Bearer token
Rate Limit: 100 requests/hour per user

# Tasks
POST   /tasks                      Create new task
GET    /tasks                      List tasks (paginated, filtered)
GET    /tasks/{task_id}            Get task by ID
PATCH  /tasks/{task_id}            Update task
DELETE /tasks/{task_id}            Delete task

# Comments on Tasks
POST   /tasks/{task_id}/comments   Add comment to task
GET    /tasks/{task_id}/comments   List task comments
DELETE /comments/{comment_id}      Delete comment

# Query Parameters for GET /tasks:
- page: int = 1
- page_size: int = 20
- project_id: int (filter by project)
- assignee_id: int (filter by assignee)
- status: TaskStatus (filter by status)
- priority: TaskPriority (filter by priority)
- search: str (search in title/description)
- sort_by: str = "created_at" (sort field)
- sort_order: str = "desc" (asc or desc)

# Status Codes:
- 200 OK: Successful GET, PATCH
- 201 Created: Successful POST
- 204 No Content: Successful DELETE
- 400 Bad Request: Invalid input
- 401 Unauthorized: Not authenticated
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Task not found
- 422 Unprocessable Entity: Validation error
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server error

# Permissions:
- Create task: Authenticated user
- List tasks: Authenticated user (filtered by access)
- Get task: Task assignee, project member, or admin
- Update task: Task assignee, project owner, or admin
- Delete task: Task creator, project owner, or admin
"""

Integration

Used By:

  • @architecture-designer (Primary) - Phase 2 sub-agent for architecture design

Integrates With:

  • architecture-planner skill - API contracts defined after component structure
  • data-modeler skill - Uses data models for request/response schemas

Workflow Position:

  1. Analysis Specialist completes requirements analysis
  2. Architecture Designer receives analysis
  3. architecture-planner skill designs component structure (Step 3)
  4. data-modeler skill designs data models (Step 4)
  5. api-designer skill designs API contracts (Step 5)
  6. Results synthesized into PRP

Version: 2.0.0
Auto-Activation: Yes
Phase: 2 - Design & Planning
Created: 2025-10-29

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.