api designer
npx skills add https://github.com/daffy0208/ai-dev-standards --skill API Designer
Skill 文档
API Designer
Design robust, scalable, and developer-friendly APIs.
Core Principles
1. Developer Experience First
- Clear, predictable naming conventions
- Comprehensive documentation
- Helpful error messages
- Consistent patterns across endpoints
2. Design for Evolution
- Versioning strategy from day one
- Backward compatibility
- Deprecation process
- Migration guides for breaking changes
3. Security by Default
- Authentication and authorization
- Rate limiting and throttling
- Input validation and sanitization
- HTTPS only, no exceptions
4. Performance Matters
- Efficient queries and indexing
- Caching strategies
- Pagination for large datasets
- Compression (gzip, brotli)
REST API Design
Resource Naming Conventions
â
Good (Nouns, plural, hierarchical):
GET /users # List all users
GET /users/123 # Get specific user
POST /users # Create user
PUT /users/123 # Replace user
PATCH /users/123 # Update user
DELETE /users/123 # Delete user
GET /users/123/posts # User's posts (nested)
GET /users/123/posts/456 # Specific post
â Bad (Verbs, inconsistent, unclear):
GET /getUsers
POST /createUser
GET /user-list
GET /UserData?id=123
HTTP Methods & Semantics
| Method | Purpose | Idempotent | Safe | Request Body | Response Body |
|---|---|---|---|---|---|
| GET | Retrieve data | Yes | Yes | No | Yes |
| POST | Create resource | No | No | Yes | Yes (created) |
| PUT | Replace resource | Yes | No | Yes | Yes (optional) |
| PATCH | Partial update | No | No | Yes | Yes (optional) |
| DELETE | Remove resource | Yes | No | No | No (204) or Yes |
Idempotent: Multiple identical requests have same effect as single request Safe: Request doesn’t modify server state
HTTP Status Codes
Success (2xx):
200 OK– Successful GET, PUT, PATCH, DELETE201 Created– Successful POST, includesLocationheader204 No Content– Successful request, no response body (often DELETE)
Client Errors (4xx):
400 Bad Request– Invalid syntax, validation error401 Unauthorized– Authentication required or failed403 Forbidden– Authenticated but lacks permission404 Not Found– Resource doesn’t exist409 Conflict– Request conflicts with current state422 Unprocessable Entity– Validation error (semantic)429 Too Many Requests– Rate limit exceeded
Server Errors (5xx):
500 Internal Server Error– Generic server error502 Bad Gateway– Upstream service error503 Service Unavailable– Temporary unavailability504 Gateway Timeout– Upstream timeout
Response Format Standards
Success Response:
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "John Doe",
"email": "john@example.com",
"created_at": "2025-01-15T10:30:00Z"
}
}
}
Error Response:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"code": "REQUIRED",
"message": "Email is required"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "Age must be between 18 and 120"
}
],
"request_id": "req_abc123",
"documentation_url": "https://api.example.com/docs/errors/validation"
}
}
List Response with Pagination:
{
"data": [...],
"pagination": {
"cursor": "eyJpZCI6MTIzfQ==",
"has_more": true,
"total_count": 1000
},
"links": {
"next": "/users?cursor=eyJpZCI6MTIzfQ==&limit=20",
"prev": "/users?cursor=eyJpZCI6MTAwfQ==&limit=20"
}
}
Pagination Strategies
Cursor-based (Recommended):
GET /users?cursor=abc123&limit=20
Pros: Consistent results, efficient, handles real-time data
Cons: Can't jump to arbitrary page
Use when: Large datasets, real-time data, performance critical
Offset-based:
GET /users?page=1&per_page=20
GET /users?offset=0&limit=20
Pros: Simple, can jump to any page
Cons: Inconsistent with concurrent writes, inefficient at scale
Use when: Small datasets, admin interfaces, simple use cases
Filtering, Sorting, and Search
Filtering:
GET /users?status=active&role=admin&created_after=2025-01-01
Sorting:
GET /users?sort=-created_at,name # Descending created_at, then ascending name
Search:
GET /users?q=john&fields=name,email # Search across specified fields
Authentication & Authorization
JWT Bearer Token (Recommended for SPAs):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Pros: Stateless, includes user claims, works across domains
Cons: Can't revoke until expiry, larger payload
API Keys (for service-to-service):
X-API-Key: sk_live_abc123...
Pros: Simple, easy to rotate, per-service keys
Cons: No user context, must be kept secret
OAuth 2.0 (for third-party access):
Authorization: Bearer access_token
Pros: Delegated auth, scoped permissions, industry standard
Cons: Complex setup, requires OAuth server
Basic Auth (only for internal/admin tools):
Authorization: Basic base64(username:password)
Pros: Simple, built-in to HTTP
Cons: Credentials in every request, must use HTTPS
Rate Limiting
Standard Headers:
X-RateLimit-Limit: 1000 # Max requests per window
X-RateLimit-Remaining: 999 # Requests left
X-RateLimit-Reset: 1640995200 # Unix timestamp when limit resets
Retry-After: 60 # Seconds to wait (on 429)
Common Strategies:
- Fixed window: 1000 requests per hour
- Sliding window: 1000 requests per rolling hour
- Token bucket: Burst allowance with refill rate
- Per-user, per-IP, or per-API-key limits
Versioning Strategies
URL Versioning (Recommended):
/v1/users
/v2/users
Pros: Explicit, easy to route, clear in logs
Cons: URL pollution, harder to evolve incrementally
Header Versioning:
Accept: application/vnd.myapp.v2+json
API-Version: 2
Pros: Clean URLs, follows REST principles
Cons: Less visible, harder to test in browser
Best Practices:
- Start with v1, not v0
- Only increment for breaking changes
- Support N and N-1 versions simultaneously
- Provide migration guides
- Announce deprecation 6-12 months ahead
GraphQL API Design
Schema Design
type User {
id: ID!
name: String!
email: String!
posts(first: Int, after: String): PostConnection!
createdAt: DateTime!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
node: Post!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
endCursor: String
}
type Query {
user(id: ID!): User
users(first: Int, after: String): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}
input CreateUserInput {
name: String!
email: String!
}
type CreateUserPayload {
user: User
errors: [Error!]
}
GraphQL Best Practices
1. Use Relay Connection Pattern for Pagination:
query {
users(first: 10, after: "cursor") {
edges {
node {
id
name
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
2. Input Types for Mutations:
# â
Good: Input type + payload
mutation {
createUser(input: { name: "John", email: "john@example.com" }) {
user {
id
name
}
errors {
field
message
}
}
}
# â Bad: Flat arguments
mutation {
createUser(name: "John", email: "john@example.com") {
id
name
}
}
3. Error Handling:
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
type CreateUserPayload {
user: User # Null if errors
errors: [Error!] # Field-level errors
}
type Error {
field: String!
code: String!
message: String!
}
REST vs GraphQL Decision
Use REST when:
- Simple CRUD operations
- Caching is critical (HTTP caching)
- Public API for third-parties
- File uploads/downloads
- Team unfamiliar with GraphQL
Use GraphQL when:
- Clients need flexible queries
- Reducing over-fetching/under-fetching
- Rapid frontend iteration
- Complex nested data relationships
- Strong typing and schema benefits
API Documentation
OpenAPI/Swagger Specification
openapi: 3.0.0
info:
title: User Management API
version: 1.0.0
description: API for managing users and posts
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: per_page
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
'401':
$ref: '#/components/responses/Unauthorized'
post:
summary: Create user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserInput'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
format: email
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
Documentation Best Practices
- â Include request/response examples
- â Document all error codes
- â Provide authentication guides
- â Interactive API playground (Swagger UI, GraphQL Playground)
- â Code examples in multiple languages
- â Rate limit information
- â Changelog for API updates
Security Checklist
- HTTPS only (redirect HTTP â HTTPS)
- Authentication required for protected endpoints
- Authorization checks (user can only access own data)
- Input validation (schema validation, sanitization)
- Rate limiting per user/IP
- CORS configuration (whitelist origins)
- SQL injection prevention (parameterized queries)
- No sensitive data in URLs (use headers/body)
- Audit logging for sensitive operations
- API keys rotatable and revocable
Related Resources
Related Skills:
frontend-builder– For consuming APIs from frontenddeployment-advisor– For API hosting decisionsperformance-optimizer– For API performance tuning
Related Patterns:
META/DECISION-FRAMEWORK.md– REST vs GraphQL decisionsSTANDARDS/architecture-patterns/api-gateway-pattern.md– API gateway architecture (when created)
Related Playbooks:
PLAYBOOKS/deploy-api.md– API deployment procedure (when created)PLAYBOOKS/version-api.md– API versioning workflow (when created)