Designing API Contracts
Overview
Design RESTful API contracts that map user actions to endpoints with complete schema definitions and comprehensive error handling. Every user action becomes an endpoint; every endpoint has request/response schemas and error handling.
When to Use
-
Designing new API endpoints for a feature
-
Mapping user actions to HTTP methods and paths
-
Creating OpenAPI specifications from requirements
-
Defining request/response schemas for endpoints
-
Documenting error responses for an API
-
Integrating with existing API patterns (brownfield)
-
Creating contracts/ directory artifacts
When NOT to Use
-
GraphQL API design - Different paradigm, not RESTful
-
WebSocket or real-time streaming - Use specialized patterns
-
Internal microservice communication - When external contracts aren't needed
-
Entity modeling - Use humaninloop:patterns-entity-modeling first
-
Technical architecture decisions - Use humaninloop:patterns-technical-decisions
Endpoint Mapping
User Action to Endpoint Mapping
User Action HTTP Method Endpoint Pattern
Create resource POST /resources
List resources GET /resources
Get single resource GET /resources/{id}
Update resource PUT/PATCH /resources/{id}
Delete resource DELETE /resources/{id}
Perform action POST /resources/{id}/{action}
Get nested resource GET /resources/{id}/children
Method Selection
Scenario Method Idempotent?
Create new resource POST No
Full replacement PUT Yes
Partial update PATCH No
Read resource GET Yes
Remove resource DELETE Yes
Trigger action POST Usually No
Resource Naming Conventions
-
Use plural nouns: /users , not /user
-
Use kebab-case for multi-word: /user-profiles
-
Use path params for IDs: /users/{userId}
-
Use query params for filtering: /users?role=admin
-
Use nested paths for relationships: /users/{userId}/tasks
Endpoint Documentation Format
Document each endpoint with description, source requirements, request/response schemas, and error cases:
POST /api/auth/login
Description: Authenticate user with email and password
Source Requirements: FR-001, US#1
Request
{JSON request body example}
Response (200 OK)
{JSON response body example}
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_INPUT | Missing or malformed fields |
| 401 | INVALID_CREDENTIALS | Wrong email or password |
Schema Definition
Request Schema Format
LoginRequest: type: object required: - email - password properties: email: type: string format: email description: User's email address password: type: string minLength: 8 description: User's password
Type Mapping from Data Model
Data Model Type OpenAPI Type Format
UUID string uuid
Text string
Email string email
URL string uri
Integer integer int32/int64
Decimal number float/double
Boolean boolean
Timestamp string date-time
Date string date
Enum[a,b,c] string enum: [a,b,c]
Error Response Design
Use standard error format with machine-readable codes and human-readable messages.
See ERROR-PATTERNS.md for complete HTTP status codes, error code conventions, and response formats.
Quick Reference
Status When to Use
400 Invalid input format
401 Missing/invalid auth
403 No permission
404 Resource missing
409 State conflict
422 Business rule violation
429 Rate limit exceeded
500 Server error
List Endpoints
For endpoints returning collections, implement pagination, filtering, and sorting.
See PAGINATION-PATTERNS.md for offset vs cursor pagination, filtering operators, and sorting patterns.
Quick Reference
GET /api/users?page=1&limit=20&role=admin&sort=-createdAt
Brownfield Considerations
When existing API patterns are detected, align new endpoints:
Aspect Check For
Base path /api/v1 , /api , etc.
Auth pattern Bearer, API key, session
Error format Existing error structure
Pagination page/limit, cursor, offset
Handle endpoint collisions:
-
REUSE existing endpoints when possible
-
RENAME to match existing patterns
-
NEW only when no existing endpoint fits
OpenAPI Structure
See OPENAPI-TEMPLATE.yaml for a complete, copy-ready template with all sections.
Minimal Structure
openapi: 3.0.3 info: title: {Feature Name} API version: 1.0.0
servers:
- url: /api
paths: /resource: get: ... post: ...
components: schemas: ... securitySchemes: bearerAuth: type: http scheme: bearer
security:
- bearerAuth: []
Traceability
Track endpoint to requirement mapping:
Endpoint Method FR US Description
/auth/login POST FR-001 US#1 User login
/users/me GET FR-004 US#4 Get current user
Validation
Validate OpenAPI specifications using the validation script:
python scripts/validate-openapi.py path/to/openapi.yaml
Checks: OpenAPI syntax, REST conventions, error responses, request bodies, operation IDs, security schemes, examples, and descriptions.
Quality Checklist
Before finalizing API contracts:
-
Every user action has an endpoint
-
All endpoints have request schema (if applicable)
-
All endpoints have success response schema
-
All endpoints have error responses defined
-
Naming follows REST conventions
-
Authentication requirements documented
-
Brownfield patterns matched (if applicable)
-
OpenAPI spec is valid
-
Traceability to requirements complete
Common Mistakes
Verbs in URLs
❌ /getUsers , /createUser , /deleteUser
✅ /users with appropriate HTTP methods (GET, POST, DELETE)
GET for State-Changing Actions
❌ GET /users/{id}/delete
✅ DELETE /users/{id} or POST /users/{id}/archive
Missing Error Responses
❌ Only documenting 200 OK response ✅ Define all error cases: 400, 401, 403, 404, 409, 422, 500
Inconsistent Naming
❌ Mixing /user-profiles , /userSettings , /user_preferences
✅ Pick one style consistently: /user-profiles , /user-settings , /user-preferences
Generic Error Codes
❌ Just returning 400 or 500 for all errors ✅ Specific codes: INVALID_EMAIL , USER_NOT_FOUND , RATE_LIMIT_EXCEEDED
Missing Examples
❌ Schema definitions without realistic example values ✅ Include example: fields showing real-world data
Skipping Brownfield Check
❌ Creating new patterns when existing API conventions exist ✅ Always check existing API style (auth, error format, pagination) first