API Design
Scope: Always appliedRule ID:
hatch3r-api-design
Defines API design patterns for REST, GraphQL, and gRPC including authentication, pagination, rate limiting, and contract documentation standards.
REST API Patterns
Request/Response Schemas
- Use consistent request/response schemas across all endpoints
- Document in OpenAPI spec files (see OpenAPI 3.1)
- Version all endpoints via URL prefix (
/api/v1/) orAccept-Versionheader - Only additive changes allowed: add fields, never rename or remove without migration
Error Response Format
Idempotency
- Mutation endpoints (POST, PUT, PATCH, DELETE) accept
Idempotency-Keyheader - Server tracks keys and rejects duplicate requests with 409 Conflict
- Keys expire after 24 hours
Request Validation
- Validate and sanitize at the boundary before processing
- Use runtime schema validators (zod, valibot, joi)
- Return 400 with field-level error details on validation failure
List Endpoints
List endpoints return envelopes, never raw arrays:Rate Limiting
- Enforce server-side rate limits per authenticated identity or IP
- Return 429 Too Many Requests with
Retry-Afterheader when exceeded - Use standard rate limit headers (see Rate Limit Headers)
Authentication & Authorization
JWT Validation
Validate JWT on every request:Token Lifetimes
| Token Type | Lifetime | Storage |
|---|---|---|
| Access token | 15–60 minutes | Memory, short-lived |
| Refresh token | 7–30 days | Opaque, rotated, revocable |
| API key | Until rotated | Server-side encrypted |
OAuth 2.0
- Use Authorization Code flow with PKCE for SPAs and mobile clients
- Never use implicit flow (deprecated in OAuth 2.1)
- API keys identify applications, not users — scope keys to specific services
Authorization Middleware
Fail Closed
- Default deny for authorization
- Fail closed on missing claims or expired tokens
- Never bypass auth checks on error
Token Storage
- Prefer
HttpOnly,Secure,SameSite=Strictcookies - Avoid
localStoragefor tokens (XSS vulnerable) - Mobile apps: use platform-specific secure storage (Keychain, Keystore)
CORS Policy
- Never use
Access-Control-Allow-Origin: *in production - Set
credentials: trueonly for origins that require cookie-based auth - Restrict methods and headers to what endpoints actually support
- Reject requests from non-allowlisted origins at the gateway
Security Headers
Apply via centralized middleware:Pagination Standards
Cursor-Based Pagination (Recommended)
- Ordered data with high write frequency
- Deep traversal (> 1000 records)
- Real-time feeds
- Cursors are opaque — clients must not construct them
- Enforce max page size server-side (e.g., 100 items)
- Return
nextCursor: nullwhen no more pages
Offset-Based Pagination
- Small, stable datasets
- Total count is cheap to compute
- Page number navigation required
- Reject deep offset pagination beyond threshold (e.g., offset > 10,000)
- Total count is optional — use
hasMoreboolean if count is expensive
Rate Limit Headers
Follow IETF draft standard:Rate Limit Tiers
| Endpoint Type | Rate Limit |
|---|---|
| Auth endpoints | 100/min per IP |
| Read endpoints | 1000/min per user |
| Write endpoints | 500/min per user |
| Search endpoints | 100/min per user |
OpenAPI 3.1
Use OpenAPI 3.1 for all REST API documentation.Key Features
- Full JSON Schema alignment (draft 2020-12)
- Use
type: ["string", "null"]instead ofnullable: true - Webhooks as top-level objects
$idand$anchorfor schema references
Example Spec
CI Integration
Type Generation
GraphQL API Design
Schema-First
Define schema (SDL) before implementing resolvers:Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Types | PascalCase | User, PostConnection |
| Fields | camelCase | firstName, createdAt |
| Arguments | camelCase | first, after |
| Enum values | SCREAMING_SNAKE_CASE | PUBLISHED, DRAFT |
Pagination
Implement Relay Connection specification:Error Handling
N+1 Prevention
Use DataLoader for batching:Security
- Enforce query depth limits (max 10)
- Enforce query complexity limits
- Disable introspection in production
- Apply field-level authorization in every resolver
gRPC API Design
Protobuf Schema
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Services | PascalCase | UserService |
| RPCs | PascalCase | GetUser, ListUsers |
| Messages | PascalCase | GetUserRequest |
| Fields | snake_case | user_id, created_at |
| Enums | SCREAMING_SNAKE_CASE | STATUS_UNSPECIFIED, STATUS_ACTIVE |
Backward Compatibility
- Never reuse field numbers — use
reservedfor removed fields - Only add fields (never remove or rename)
- Use
optionalfor new fields that older clients may not send
Error Codes
Use standard gRPC status codes:| Code | When to Use |
|---|---|
OK | Success |
INVALID_ARGUMENT | Client sent bad input |
NOT_FOUND | Resource does not exist |
ALREADY_EXISTS | Create conflict |
PERMISSION_DENIED | Authenticated but not authorized |
UNAUTHENTICATED | Missing or invalid credentials |
RESOURCE_EXHAUSTED | Rate limit exceeded |
INTERNAL | Unexpected server error |
UNAVAILABLE | Transient failure, retry |
Enforcement
CI gates:- OpenAPI spec validation (blocks merge on lint errors)
- Generated types up-to-date
- Security headers present in responses
- API versioned (URL or header)
- Request validation at boundary
- Error responses use standard format
- Pagination uses envelope format
- Rate limiting enforced
- Security headers applied
Related Rules
- Security Patterns — Input validation, auth enforcement
- Error Handling — Error response structure
- Observability — API tracing and metrics

