designing-apis
Designing APIs
Design well-structured, scalable APIs using REST, GraphQL, or event-driven patterns. Focus on resource design, versioning, error handling, pagination, rate limiting, and security.
When to Use This Skill
Use when:
- Designing a new REST, GraphQL, or event-driven API
- Establishing API design standards for a team or organization
- Choosing between REST, GraphQL, WebSockets, or message queues
- Planning API versioning and breaking change management
- Defining error response formats and HTTP status code usage
- Implementing pagination, filtering, and rate limiting patterns
- Designing OAuth2 flows or API key authentication
- Creating OpenAPI or AsyncAPI specifications
Do NOT use for:
- Implementation code (use
api-patternsskill for Express, FastAPI code) - Authentication implementation (use
auth-securityskill for JWT, sessions) - API testing strategies (use
testing-strategiesskill) - API deployment and infrastructure (use
deploying-applicationsskill)
Core Design Principles
Resource-Oriented Design (REST)
Use nouns for resources, not verbs in URLs:
✓ GET /users List users
✓ GET /users/123 Get user 123
✓ POST /users Create user
✓ PATCH /users/123 Update user 123
✓ DELETE /users/123 Delete user 123
✗ GET /getUsers
✗ POST /createUser
Nest resources for relationships (limit depth to 2-3 levels):
✓ GET /users/123/posts
✓ GET /users/123/posts/456/comments
✗ GET /users/123/posts/456/comments/789/replies (too deep)
For complete REST patterns, see references/rest-design.md
HTTP Method Semantics
| Method | Idempotent | Safe | Use For | Success Status |
|---|---|---|---|---|
| GET | Yes | Yes | Read resource | 200 OK |
| POST | No | No | Create resource | 201 Created |
| PUT | Yes | No | Replace entire resource | 200 OK, 204 No Content |
| PATCH | No | No | Update specific fields | 200 OK, 204 No Content |
| DELETE | Yes | No | Remove resource | 204 No Content, 200 OK |
Idempotent means multiple identical requests have the same effect as one request.
HTTP Status Codes
Success (2xx):
- 200 OK, 201 Created, 204 No Content
Client Errors (4xx):
- 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
- 409 Conflict, 422 Unprocessable Entity, 429 Too Many Requests
Server Errors (5xx):
- 500 Internal Server Error, 503 Service Unavailable
For complete status code guide, see references/rest-design.md
API Style Selection
Decision Matrix
| Factor | REST | GraphQL | WebSocket | Message Queue |
|---|---|---|---|---|
| Public API | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐ |
| Complex Data | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
| Caching | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐ | ⭐ |
| Real-time | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Simplicity | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
Quick Selection
- Public API, CRUD operations → REST
- Complex data, flexible queries → GraphQL
- Real-time, bidirectional → WebSockets
- Event-driven, microservices → Message Queue
For detailed protocol selection, see references/protocol-selection.md
API Versioning
URL Path Versioning (Recommended)
https://api.example.com/v1/users
https://api.example.com/v2/users
Pros: Explicit, easy to implement and test Cons: Maintenance overhead
Alternative Strategies
- Header-Based:
Accept-Version: v1 - Media Type:
Accept: application/vnd.example.v1+json - Query Parameter:
?version=1(not recommended)
Breaking Change Management
Timeline:
- Month 0: Announce deprecation
- Months 1-3: Migration period
- Months 4-6: Deprecation warnings
- Month 6: Sunset (return 410 Gone)
Include deprecation headers:
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Link: </api/v2/users>; rel="successor-version"
For complete versioning guide, see references/versioning-strategies.md
Error Response Standards
RFC 7807 Problem Details (Recommended)
{
"type": "https://api.example.com/errors/validation",
"title": "Validation Error",
"status": 400,
"detail": "One or more fields failed validation",
"errors": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "INVALID_EMAIL"
}
]
}
Content-Type: application/problem+json
For complete error patterns, see references/error-handling.md
Pagination Patterns
Strategy Selection
| Scenario | Strategy | Why |
|---|---|---|
| Small datasets (<1000) | Offset-based | Simple, page numbers |
| Large datasets (>10K) | Cursor-based | Efficient, handles writes |
| Sorted data | Keyset | Consistent results |
| Real-time feeds | Cursor-based | Handles new items |
Offset-Based (Simple)
GET /users?limit=20&offset=40
Response includes: limit, offset, total, currentPage
Cursor-Based (Scalable)
GET /users?limit=20&cursor=eyJpZCI6MTIzfQ==
Cursor is base64-encoded JSON with position information.
Response includes: nextCursor, hasNext
For implementation details, see references/pagination-patterns.md
Rate Limiting
Token Bucket Algorithm
- Each user has bucket with tokens
- Each request consumes 1 token
- Tokens refill at constant rate
- Empty bucket rejects request
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1672531200
When exceeded (429):
Retry-After: 3600
Strategies
- Per User: 100 requests/hour
- Per API Key: 1000 requests/hour
- Per IP: 50 requests/hour (unauthenticated)
- Tiered: Free (100/hr), Pro (1000/hr), Enterprise (10000/hr)
For implementation patterns, see references/rate-limiting.md
API Security Design
OAuth 2.0 Flows
Authorization Code Flow (Web Apps):
- Redirect user to authorization server
- User grants permission
- Exchange code for access token
- Use token for API requests
Client Credentials Flow (Service-to-Service):
- Authenticate with client ID and secret
- Receive access token
- Use token for API requests
Scope-Based Authorization
Define granular permissions:
read:users - Read user data
write:users - Create/update users
delete:users - Delete users
admin:* - Full admin access
API Key Management
Use header-based keys:
X-API-Key: sk_live_abc123xyz456
Best practices:
- Prefix with environment:
sk_live_*,sk_test_* - Store hashed keys only
- Support key rotation
- Track last-used timestamp
For complete security patterns, see references/authentication.md
OpenAPI Specification
Basic Structure
openapi: 3.1.0
info:
title: User Management API
version: 2.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: limit
in: query
schema:
type: integer
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
OpenAPI enables:
- Code generation (server stubs, client SDKs)
- Validation (request/response checking)
- Mock servers (testing against spec)
- Documentation (interactive docs)
For complete OpenAPI examples, see examples/openapi/
AsyncAPI Specification
Event-Driven APIs
AsyncAPI defines message-based APIs (WebSockets, Kafka, MQTT):
asyncapi: 3.0.0
info:
title: Order Events API
channels:
orders/created:
address: orders.created
messages:
orderCreated:
payload:
type: object
properties:
orderId:
type: string
For AsyncAPI examples, see examples/asyncapi/
GraphQL Design
Schema Structure
type User {
id: ID!
username: String!
posts(limit: Int): [Post!]!
}
type Query {
user(id: ID!): User
users(limit: Int): [User!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
}
N+1 Problem Solution
Use DataLoader to batch requests:
const userLoader = new DataLoader(async (userIds) => {
// Single query for all users
const users = await db.users.findByIds(userIds);
return userIds.map(id => users.find(u => u.id === id));
});
For GraphQL patterns, see references/graphql-design.md
Quick Reference Tables
Pagination Strategy Selection
| Scenario | Strategy |
|---|---|
| Small datasets | Offset-based |
| Large datasets | Cursor-based |
| Sorted data | Keyset |
| Real-time feeds | Cursor-based |
Versioning Strategy Selection
| Factor | URL Path | Header | Media Type |
|---|---|---|---|
| Visibility | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
| Simplicity | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| Best For | Most APIs | Internal APIs | Content negotiation |
Integration with Other Skills
- api-patterns: Implement API designs in Express, FastAPI, Go
- auth-security: Implement OAuth2, JWT, session management
- database-design: Design database schemas for API resources
- testing-strategies: API testing (integration, contract, load)
- deploying-applications: Deploy and scale APIs
- observability: Monitor API performance and errors
Additional Resources
Detailed guidance:
- references/rest-design.md - RESTful patterns and best practices
- references/graphql-design.md - GraphQL schema and resolver patterns
- references/versioning-strategies.md - Comprehensive versioning guide
- references/error-handling.md - RFC 7807 implementation details
- references/pagination-patterns.md - Pagination implementation patterns
- references/rate-limiting.md - Rate limiting algorithms and strategies
- references/authentication.md - OAuth2, API keys, scopes
- references/protocol-selection.md - Choosing the right API style
Working examples:
- examples/openapi/ - Complete OpenAPI 3.1 specifications
- examples/asyncapi/ - Event-driven API specifications
- examples/graphql/ - GraphQL schemas and patterns
Validation and tooling:
- scripts/validate-openapi.sh - Validate OpenAPI specifications