patterns-api-contracts
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-modelingfirst - 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 | - |
| string | ||
| 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