api-designer-agent
API Designer Agent
A systematic, comprehensive API design methodology that replicates the capabilities of a senior API architect. This agent provides guidance on RESTful design principles, OpenAPI specification, versioning strategies, error handling, authentication, rate limiting, and documentation best practices.
Activation Triggers
Invoke this agent when:
- Designing new REST APIs
- Reviewing existing API contracts
- Creating OpenAPI/Swagger specifications
- Implementing API versioning
- Designing error handling patterns
- Establishing API standards for a team
- Keywords: API design, REST, OpenAPI, Swagger, versioning, endpoints, HTTP methods, API documentation
Agent Methodology
Phase 1: API Requirements Analysis
Before designing any API, gather comprehensive requirements:
## API Requirements Checklist
### Consumer Analysis
- [ ] Who are the API consumers? (internal, partners, public)
- [ ] What languages/frameworks will clients use?
- [ ] What are the client constraints? (mobile, IoT, browser)
- [ ] What authentication methods are feasible?
- [ ] What is the expected client expertise level?
### Functional Requirements
- [ ] Core resources and operations
- [ ] Data relationships
- [ ] Search and filtering needs
- [ ] Sorting and pagination requirements
- [ ] Bulk operation needs
### Non-Functional Requirements
- [ ] Expected request volume (RPS)
- [ ] Latency requirements (P50, P99)
- [ ] Availability requirements (SLA)
- [ ] Rate limiting needs
- [ ] Geographic distribution
### Compatibility Requirements
- [ ] Backward compatibility guarantees
- [ ] Versioning requirements
- [ ] Deprecation policy
- [ ] Migration support needs
Phase 2: Resource Design
RESTful Resource Modeling
## Resource Design Principles
### Resource Identification
Resources should be:
- Nouns, not verbs
- Plural (collections)
- Hierarchical where relationships exist
- Consistent in naming convention
### Good Resource URIs
/users # User collection /users/{id} # Specific user /users/{id}/orders # User's orders /users/{id}/orders/{orderId} # Specific order /orders # All orders (alternate access) /products # Product catalog /products/{id}/reviews # Product reviews
### Avoid These Patterns
/getUsers # Verb in URI /user # Singular for collection /users/create # Action in URI (use POST /users) /users/{id}/getOrders # Verb in URI /getUserById/{id} # Verb and redundant
### Resource Hierarchy Guidelines
- Maximum 3 levels of nesting
- Beyond 3 levels, use query parameters or separate endpoints
- Consider if nested resources need independent access
Good: Clear hierarchy
/organizations/{orgId}/teams/{teamId}/members
Consider separate endpoint for deep nesting
/members?teamId={teamId}
Instead of
/organizations/{orgId}/teams/{teamId}/projects/{projectId}/tasks/{taskId}/comments
HTTP Methods Usage
## HTTP Method Reference
### GET - Retrieve Resources
```http
GET /users # List users
GET /users/123 # Get specific user
GET /users?status=active&limit=20 # Filtered list
- MUST be safe (no side effects)
- MUST be idempotent
- Cacheable
- No request body
POST - Create Resources
POST /users
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com"
}
Response: 201 Created
Location: /users/123
- Creates new resource
- NOT idempotent
- Returns created resource or reference
- Use for actions that aren't CRUD (send-email, process-payment)
PUT - Replace Resources
PUT /users/123
Content-Type: application/json
{
"name": "John Doe Updated",
"email": "john.new@example.com",
"status": "active"
}
Response: 200 OK
- Full resource replacement
- MUST be idempotent
- Client provides complete representation
- Creates if not exists (optional, often 404 instead)
PATCH - Partial Update
PATCH /users/123
Content-Type: application/json
{
"email": "john.updated@example.com"
}
Response: 200 OK
- Partial modification
- Only changed fields sent
- Use JSON Patch (RFC 6902) or JSON Merge Patch (RFC 7396)
DELETE - Remove Resources
DELETE /users/123
Response: 204 No Content
- MUST be idempotent
- Return 204 (no body) or 200 (with confirmation)
- Subsequent calls: 204 (idempotent) or 404 (already deleted)
OPTIONS - Describe Capabilities
OPTIONS /users
Response: 200 OK
Allow: GET, POST, OPTIONS
- Returns allowed methods
- Used for CORS preflight
HEAD - Metadata Only
HEAD /users/123
Response: 200 OK
Content-Length: 1234
Last-Modified: Wed, 15 Jan 2024 10:00:00 GMT
- Same as GET but no body
- Useful for checking existence, cache validation
### Phase 3: Request/Response Design
#### Request Design
```yaml
# OpenAPI Request Examples
# Query Parameters (filtering, sorting, pagination)
/users:
get:
parameters:
- name: status
in: query
schema:
type: string
enum: [active, inactive, pending]
- name: sort
in: query
schema:
type: string
example: created_at:desc
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: cursor
in: query
description: Cursor for pagination
schema:
type: string
# Path Parameters (resource identification)
/users/{userId}/orders/{orderId}:
get:
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
- name: orderId
in: path
required: true
schema:
type: string
# Request Body (create/update)
/users:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
example:
name: "John Doe"
email: "john@example.com"
role: "user"
Response Design
# Consistent Response Envelope (Optional but Common)
components:
schemas:
ApiResponse:
type: object
properties:
data:
description: Response payload
meta:
type: object
properties:
request_id:
type: string
timestamp:
type: string
format: date-time
pagination:
$ref: '#/components/schemas/PaginationMeta'
PaginationMeta:
type: object
properties:
total:
type: integer
limit:
type: integer
offset:
type: integer
next_cursor:
type: string
has_more:
type: boolean
# Collection Response
/users:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/PaginationMeta'
# Single Resource Response
/users/{id}:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/User'
Field Naming Conventions
## Naming Conventions
### Preferred: snake_case
```json
{
"user_id": "123",
"first_name": "John",
"created_at": "2024-01-15T10:30:00Z",
"is_active": true
}
Alternative: camelCase (JavaScript ecosystems)
{
"userId": "123",
"firstName": "John",
"createdAt": "2024-01-15T10:30:00Z",
"isActive": true
}
Consistency Rules
- Choose ONE convention and use everywhere
- Document the convention
- Include in style guide
- Enforce with linting
Date/Time Format
Always use ISO 8601 with timezone:
{
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T14:45:30+00:00"
}
Boolean Fields
Use is_, has_, can_ prefixes:
{
"is_active": true,
"has_orders": true,
"can_edit": false
}
IDs
Use string type for IDs (even if numeric internally):
{
"id": "123", // Not: 123
"user_id": "456"
}
### Phase 4: Error Handling
```markdown
## Error Response Design
### Standard Error Format
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid data",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Email must be a valid email address"
},
{
"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_ERROR"
}
}
HTTP Status Code Usage
# Success Codes
200 OK: # Successful GET, PUT, PATCH, DELETE (with body)
201 Created: # Successful POST creating resource
202 Accepted: # Request accepted, processing async
204 No Content: # Successful DELETE (no body)
# Client Error Codes
400 Bad Request: # Invalid syntax, malformed request
401 Unauthorized: # Authentication required
403 Forbidden: # Authenticated but not authorized
404 Not Found: # Resource doesn't exist
405 Method Not Allowed: # HTTP method not supported
409 Conflict: # Resource conflict (duplicate, state conflict)
410 Gone: # Resource permanently deleted
422 Unprocessable Entity: # Valid syntax but semantic errors
429 Too Many Requests: # Rate limit exceeded
# Server Error Codes
500 Internal Server Error: # Unexpected server error
502 Bad Gateway: # Upstream service error
503 Service Unavailable: # Server temporarily unavailable
504 Gateway Timeout: # Upstream timeout
Error Code Catalog
// Define application error codes
enum ErrorCode {
// Validation errors (400, 422)
VALIDATION_ERROR = 'VALIDATION_ERROR',
INVALID_FORMAT = 'INVALID_FORMAT',
REQUIRED_FIELD = 'REQUIRED_FIELD',
OUT_OF_RANGE = 'OUT_OF_RANGE',
// Authentication errors (401)
AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED',
INVALID_CREDENTIALS = 'INVALID_CREDENTIALS',
TOKEN_EXPIRED = 'TOKEN_EXPIRED',
// Authorization errors (403)
PERMISSION_DENIED = 'PERMISSION_DENIED',
INSUFFICIENT_SCOPE = 'INSUFFICIENT_SCOPE',
// Resource errors (404, 409, 410)
RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',
RESOURCE_ALREADY_EXISTS = 'RESOURCE_ALREADY_EXISTS',
RESOURCE_DELETED = 'RESOURCE_DELETED',
STATE_CONFLICT = 'STATE_CONFLICT',
// Rate limiting (429)
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
// Server errors (500)
INTERNAL_ERROR = 'INTERNAL_ERROR',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE'
}
Error Response Headers
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"retry_after": 60
}
}
### Phase 5: Versioning Strategies
```markdown
## API Versioning Approaches
### URI Versioning (Recommended for Public APIs)
GET /v1/users GET /v2/users
Pros:
- Clear and explicit
- Easy to understand
- Simple to implement
- Cache-friendly
Cons:
- Pollutes URI space
- Requires routing logic
### Header Versioning
```http
GET /users
Accept: application/vnd.example.v1+json
Or custom header:
GET /users
X-API-Version: 1
Pros:
- Clean URIs
- RESTful purists prefer
Cons:
- Less discoverable
- Harder to test (can't just change URL)
- Caching complications
Query Parameter Versioning
GET /users?version=1
Pros:
- Easy to test
- Optional (can default)
Cons:
- Considered less clean
- Caching challenges
Recommended: URI Versioning with Semantic Versioning
# Version only major versions in URI
/v1/users # Major version 1.x.x
/v2/users # Major version 2.x.x
# Use headers for minor version selection (optional)
X-API-Minor-Version: 3 # Use v1.3.x features
# Version changelog
versions:
v1:
current: 1.5.2
status: stable
sunset: null
v2:
current: 2.0.0
status: beta
v0:
current: 0.9.0
status: deprecated
sunset: "2024-06-01"
Breaking vs Non-Breaking Changes
## Non-Breaking (Minor Version)
- Adding new optional fields
- Adding new endpoints
- Adding new optional query parameters
- Extending enums (if clients handle unknown values)
- Performance improvements
- Bug fixes
## Breaking (Major Version)
- Removing fields
- Renaming fields
- Changing field types
- Removing endpoints
- Making optional fields required
- Changing authentication methods
- Changing error formats
- Removing enum values
Deprecation Process
# Deprecation headers
GET /v1/users/123
Deprecation: Sun, 01 Dec 2024 00:00:00 GMT
Sunset: Sun, 01 Mar 2025 00:00:00 GMT
Link: </v2/users/123>; rel="successor-version"
{
"id": "123",
"name": "John",
"_deprecated": {
"warning": "v1 API is deprecated. Migrate to v2 by March 2025",
"migration_guide": "https://api.example.com/docs/v1-to-v2-migration"
}
}
### Phase 6: Authentication & Authorization
```markdown
## Authentication Patterns
### API Key Authentication
```http
# Header approach (recommended)
GET /users
X-API-Key: sk_live_abc123xyz
# Query parameter (less secure, avoid for sensitive operations)
GET /users?api_key=sk_live_abc123xyz
Best for:
- Server-to-server communication
- Internal APIs
- Simple integrations
OAuth 2.0 / JWT
# Bearer token
GET /users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# OAuth 2.0 flows
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read:users: Read user data
write:users: Create and update users
admin: Full administrative access
clientCredentials:
tokenUrl: https://auth.example.com/token
scopes:
api:access: Basic API access
JWT Structure
// Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-123"
}
// Payload
{
"sub": "user_123", // Subject (user ID)
"iss": "https://auth.example.com", // Issuer
"aud": ["api.example.com"], // Audience
"exp": 1705312800, // Expiration
"iat": 1705309200, // Issued at
"nbf": 1705309200, // Not before
"jti": "token_abc123", // JWT ID (unique)
"scope": "read:users write:users", // Permissions
"org_id": "org_456" // Custom claims
}
Scopes and Permissions
# Define granular scopes
scopes:
# Read scopes
read:users: View user profiles
read:orders: View order history
read:products: View product catalog
# Write scopes
write:users: Create and update users
write:orders: Create and modify orders
# Admin scopes
admin:users: Full user management
admin:billing: Billing administration
# Apply to endpoints
paths:
/users:
get:
security:
- oauth2: [read:users]
post:
security:
- oauth2: [write:users]
/admin/users:
get:
security:
- oauth2: [admin:users]
### Phase 7: Rate Limiting
```markdown
## Rate Limiting Design
### Rate Limit Headers
```http
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1705312800
X-RateLimit-Window: 3600
Rate Limit Strategies
# Per-endpoint limits
/users:
rate_limit:
requests: 100
window: 60s # 100 requests per minute
/search:
rate_limit:
requests: 20
window: 60s # More expensive operation
/bulk/import:
rate_limit:
requests: 5
window: 3600s # 5 per hour
# Per-tier limits
tiers:
free:
requests_per_minute: 60
requests_per_day: 1000
pro:
requests_per_minute: 600
requests_per_day: 50000
enterprise:
requests_per_minute: 6000
requests_per_day: unlimited
Retry-After Response
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 45
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"limit": 100,
"remaining": 0,
"reset_at": "2024-01-15T10:35:00Z",
"retry_after_seconds": 45
}
}
### Phase 8: OpenAPI Specification
```yaml
# Complete OpenAPI 3.1 Example
openapi: 3.1.0
info:
title: Example API
version: 1.0.0
description: |
Example API demonstrating best practices.
## Authentication
This API uses OAuth 2.0 Bearer tokens.
## Rate Limiting
- Free tier: 60 requests/minute
- Pro tier: 600 requests/minute
contact:
name: API Support
email: api-support@example.com
license:
name: MIT
servers:
- url: https://api.example.com/v1
description: Production
- url: https://api.staging.example.com/v1
description: Staging
tags:
- name: Users
description: User management operations
- name: Orders
description: Order operations
security:
- bearerAuth: []
paths:
/users:
get:
tags: [Users]
summary: List users
description: Retrieve a paginated list of users
operationId: listUsers
parameters:
- $ref: '#/components/parameters/LimitParam'
- $ref: '#/components/parameters/CursorParam'
- name: status
in: query
schema:
type: string
enum: [active, inactive, pending]
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
post:
tags: [Users]
summary: Create user
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: User created
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
$ref: '#/components/responses/BadRequest'
'409':
$ref: '#/components/responses/Conflict'
/users/{id}:
parameters:
- $ref: '#/components/parameters/UserIdParam'
get:
tags: [Users]
summary: Get user
operationId: getUser
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [Users]
summary: Update user
operationId: updateUser
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: User updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
delete:
tags: [Users]
summary: Delete user
operationId: deleteUser
responses:
'204':
description: User deleted
'404':
$ref: '#/components/responses/NotFound'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
UserIdParam:
name: id
in: path
required: true
schema:
type: string
format: uuid
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
CursorParam:
name: cursor
in: query
schema:
type: string
schemas:
User:
type: object
required:
- id
- email
- created_at
properties:
id:
type: string
format: uuid
readOnly: true
email:
type: string
format: email
name:
type: string
maxLength: 100
status:
type: string
enum: [active, inactive, pending]
default: pending
created_at:
type: string
format: date-time
readOnly: true
updated_at:
type: string
format: date-time
readOnly: true
CreateUserRequest:
type: object
required:
- email
properties:
email:
type: string
format: email
name:
type: string
maxLength: 100
UpdateUserRequest:
type: object
properties:
name:
type: string
maxLength: 100
status:
type: string
enum: [active, inactive]
Pagination:
type: object
properties:
total:
type: integer
limit:
type: integer
has_more:
type: boolean
next_cursor:
type: string
nullable: true
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
code:
type: string
message:
type: string
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Conflict:
description: Resource conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Rate limit exceeded
headers:
Retry-After:
schema:
type: integer
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
X-RateLimit-Reset:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
API Design Checklist
## Pre-Release API Checklist
### Design
- [ ] Resources are nouns, not verbs
- [ ] Consistent naming convention
- [ ] Logical resource hierarchy
- [ ] Appropriate HTTP methods used
- [ ] Idempotency where expected
### Requests
- [ ] Input validation defined
- [ ] Required vs optional clear
- [ ] Reasonable defaults set
- [ ] Size limits specified
- [ ] Content-Type handled
### Responses
- [ ] Consistent response format
- [ ] Appropriate status codes
- [ ] Error format standardized
- [ ] Pagination implemented
- [ ] Links/HATEOAS considered
### Security
- [ ] Authentication required
- [ ] Authorization enforced
- [ ] Rate limiting configured
- [ ] Input sanitized
- [ ] CORS configured
### Documentation
- [ ] OpenAPI spec complete
- [ ] Examples provided
- [ ] Error codes documented
- [ ] Changelog maintained
- [ ] SDK/client examples
### Operations
- [ ] Versioning strategy defined
- [ ] Deprecation policy documented
- [ ] Monitoring in place
- [ ] Health endpoints
- [ ] Logging configured
Best Practices
- Be Consistent - Same patterns everywhere
- Be Predictable - Follow REST conventions
- Be Explicit - Clear naming and documentation
- Be Secure - Authentication and authorization from day one
- Be Robust - Handle errors gracefully
- Be Efficient - Pagination, filtering, caching
- Be Evolvable - Plan for versioning
- Be Documented - OpenAPI, examples, guides
- Be Observable - Logging, metrics, tracing
- Be Developer-Friendly - Good DX is good UX
Notes
- API design is an iterative process
- Get feedback from consumers early
- Consider generating SDKs from OpenAPI
- Monitor usage patterns to inform evolution
- Security is not optional
More from housegarofalo/claude-code-base
mqtt-iot
Configure MQTT brokers (Mosquitto, EMQX) for IoT messaging, device communication, and smart home integration. Manage topics, QoS levels, authentication, and bridging. Use when setting up IoT messaging, smart home communication, or device-to-cloud connectivity. (project)
22devops-engineer-agent
Infrastructure and DevOps specialist. Manages Docker, Kubernetes, CI/CD pipelines, and cloud deployments. Expert in GitHub Actions, Azure DevOps, Terraform, and container orchestration. Use for deployment automation, infrastructure setup, or CI/CD optimization.
6postgresql
Design, optimize, and manage PostgreSQL databases. Covers indexing, pgvector for AI embeddings, JSON operations, full-text search, and query optimization. Use when working with PostgreSQL, database design, or building data-intensive applications.
6home-assistant
Ultimate Home Assistant skill - complete administration, wireless protocols (Zigbee/ZHA/Z2M, Z-Wave JS, Thread, Matter), ESPHome device building, advanced troubleshooting, performance optimization, security hardening, custom integration development, and professional dashboard design. Covers configuration, REST API, automation debugging, database optimization, SSL/TLS, Jinja2 templating, and HACS custom cards. Use for any HA task.
6testing
Comprehensive testing skill covering unit, integration, and E2E testing with pytest, Jest, Cypress, and Playwright. Use for writing tests, improving coverage, debugging test failures, and setting up testing infrastructure.
5react-typescript
Build modern React applications with TypeScript. Covers React 18+ patterns, hooks, component architecture, state management (Zustand, Redux Toolkit), server components, and best practices. Use for React development, TypeScript integration, component design, and frontend architecture.
5