13 KiB
How to Create an API Contract Specification
API Contracts document the complete specification of REST/GraphQL endpoints, including request/response formats, error handling, and authentication. They serve as the contract between frontend and backend teams.
Quick Start
# 1. Create a new API contract
scripts/generate-spec.sh api-contract api-001-descriptive-slug
# 2. Open and fill in the file
# (The file will be created at: docs/specs/api-contract/api-001-descriptive-slug.md)
# 3. Fill in endpoints and specifications, then validate:
scripts/validate-spec.sh docs/specs/api-contract/api-001-descriptive-slug.md
# 4. Fix issues and check completeness:
scripts/check-completeness.sh docs/specs/api-contract/api-001-descriptive-slug.md
When to Write an API Contract
Use an API Contract when you need to:
- Define REST API endpoints and their behavior
- Document request/response schemas in detail
- Specify error handling and status codes
- Clarify authentication and authorization
- Enable parallel frontend/backend development
- Create living documentation of your API
Research Phase
1. Research Related Specifications
Find what this API needs to support:
# Find technical requirements this fulfills
grep -r "prd\|technical" docs/specs/ --include="*.md"
# Find data models this API exposes
grep -r "data\|model" docs/specs/ --include="*.md"
# Find existing APIs in the codebase
grep -r "api\|endpoint" docs/specs/ --include="*.md"
2. Research API Design Standards
Understand best practices and conventions:
- REST conventions: HTTP methods, status codes, URL structure
- Pagination: How to handle large result sets?
- Error handling: Standard error format for your org?
- Versioning: How do you version APIs?
- Naming conventions: camelCase vs. snake_case?
Research your tech stack's conventions if needed.
3. Review Existing APIs
- How are existing APIs in your codebase designed?
- What patterns does your team follow?
- Any shared infrastructure (API gateway, auth)?
- Error response format standards?
4. Understand Data Models
- What entities are exposed?
- Which fields are required vs. optional?
- See [DATA-001] or similar specs for schema details
Structure & Content Guide
Title & Metadata
- Title: "User Export API" or similar
- Include context about what endpoints are included
- Version number if this is an update to an existing API
Overview Section
Provide context for the API:
# User Export API
This API provides endpoints for initiating, tracking, and downloading user data exports.
Supports bulk export of user information in multiple formats (CSV, JSON).
Authenticated requests only.
**Base URL**: `https://api.example.com/v1`
**Authentication**: Bearer token (JWT)
Authentication & Authorization Section
Describe how authentication works:
## Authentication
**Method**: Bearer Token (JWT)
**Header**: `Authorization: Bearer {token}`
**Token Source**: Obtained from `/auth/login` endpoint
### Authorization
**Required**: All endpoints require valid JWT token
**Scopes** (if using OAuth/scope-based):
- `exports:read` - View export status
- `exports:create` - Create new exports
- `exports:download` - Download export files
**User Data**: Users can only access their own exports (enforced server-side)
Endpoints Section
Document each endpoint thoroughly:
Endpoint: Create Export
**POST /exports**
Creates a new export job for the authenticated user.
### Request
**Headers**
- `Authorization: Bearer {token}` (required)
- `Content-Type: application/json`
**Body**
```json
{
"data_types": ["users", "transactions"],
"format": "csv",
"date_range": {
"start": "2024-01-01",
"end": "2024-01-31"
}
}
Parameters
data_types(array, required): Types of data to include- Allowed values:
users,transactions,settings - At least one required
- Allowed values:
format(string, required): Export file format- Allowed values:
csv,json
- Allowed values:
date_range(object, optional): Filter data by date rangestart(string, ISO8601 format)end(string, ISO8601 format)
Response
Status: 201 Created
{
"id": "exp_1234567890",
"user_id": "usr_9876543210",
"status": "queued",
"format": "csv",
"data_types": ["users", "transactions"],
"created_at": "2024-01-15T10:30:00Z",
"estimated_completion": "2024-01-15T10:35:00Z"
}
Status: 400 Bad Request
{
"error": "invalid_request",
"message": "data_types must include at least one type",
"code": "VALIDATION_ERROR"
}
Status: 401 Unauthorized
{
"error": "unauthorized",
"message": "Invalid or missing authorization token",
"code": "AUTH_FAILED"
}
Status: 429 Too Many Requests
{
"error": "rate_limited",
"message": "Too many requests. Try again after 60 seconds.",
"retry_after": 60
}
Details
Rate Limiting
- 10 exports per hour per user
- Returns
X-RateLimit-*headersX-RateLimit-Limit: 10X-RateLimit-Remaining: 5X-RateLimit-Reset: 1705319400
Notes
- Exports larger than 100MB are automatically gzipped
- User receives email notification when export is ready
- Export files retained for 7 days
#### Endpoint: Get Export Status
```markdown
**GET /exports/{export_id}**
Retrieve the status of a specific export.
### Path Parameters
- `export_id` (string, required): Export ID (e.g., `exp_1234567890`)
### Response
**Status: 200 OK**
```json
{
"id": "exp_1234567890",
"user_id": "usr_9876543210",
"status": "completed",
"format": "csv",
"data_types": ["users", "transactions"],
"created_at": "2024-01-15T10:30:00Z",
"completed_at": "2024-01-15T10:35:00Z",
"file_size_bytes": 2048576,
"download_url": "https://exports.example.com/exp_1234567890.csv.gz",
"download_expires_at": "2024-01-22T10:35:00Z"
}
Status: 404 Not Found
{
"error": "not_found",
"message": "Export not found",
"code": "EXPORT_NOT_FOUND"
}
Export Status Values
queued- Job is waiting to be processedprocessing- Job is currently runningcompleted- Export is ready for downloadfailed- Export failed (see error field)cancelled- User cancelled the export
Error Field (when status: failed)
{
"error": "export_failed",
"message": "Database connection lost during export"
}
#### Endpoint: Download Export
```markdown
**GET /exports/{export_id}/download**
Download the export file.
### Path Parameters
- `export_id` (string, required): Export ID
### Response
**Status: 200 OK**
- Returns binary file content
- Content-Type: `application/csv` or `application/json`
- Headers include:
- `Content-Disposition: attachment; filename=export.csv`
- `Content-Length: 2048576`
**Status: 410 Gone**
```json
{
"error": "gone",
"message": "Export file expired (retention: 7 days)",
"code": "FILE_EXPIRED"
}
### Response Formats Section
Define common response formats used across endpoints:
```markdown
## Common Response Formats
### Error Response
All errors follow this format:
```json
{
"error": "error_code",
"message": "Human-readable error message",
"code": "ERROR_CODE",
"request_id": "req_abc123" // For support/debugging
}
Pagination (for list endpoints)
{
"data": [ /* array of items */ ],
"pagination": {
"total": 150,
"limit": 20,
"offset": 0,
"next": "https://api.example.com/v1/exports?limit=20&offset=20"
}
}
### Error Handling Section
Document error scenarios and status codes:
```markdown
## Error Handling
### HTTP Status Codes
- **200 OK**: Request succeeded
- **201 Created**: Resource created successfully
- **400 Bad Request**: Invalid request format or parameters
- **401 Unauthorized**: Missing or invalid authentication
- **403 Forbidden**: Authenticated but not authorized (e.g., trying to access another user's export)
- **404 Not Found**: Resource doesn't exist
- **409 Conflict**: Request conflicts with current state (e.g., cancelling completed export)
- **429 Too Many Requests**: Rate limit exceeded
- **500 Internal Server Error**: Server error
- **503 Service Unavailable**: Service temporarily unavailable
### Error Codes
- `VALIDATION_ERROR` - Invalid input parameters
- `AUTH_FAILED` - Authentication failed
- `NOT_AUTHORIZED` - Insufficient permissions
- `NOT_FOUND` - Resource doesn't exist
- `CONFLICT` - Conflicting request state
- `RATE_LIMITED` - Rate limit exceeded
- `INTERNAL_ERROR` - Server error (retryable)
- `SERVICE_UNAVAILABLE` - Service temporarily down (retryable)
### Retry Strategy
**Retryable errors** (5xx, 429):
- Implement exponential backoff: 1s, 2s, 4s, 8s...
- Maximum 3 retries
**Non-retryable errors** (4xx except 429):
- Return error immediately to client
Rate Limiting Section
## Rate Limiting
### Limits per User
- Export creation: 10 per hour
- API calls: 1000 per hour
### Headers
All responses include rate limit information:
- `X-RateLimit-Limit`: Request quota
- `X-RateLimit-Remaining`: Requests remaining
- `X-RateLimit-Reset`: Unix timestamp when quota resets
### Handling Rate Limits
- If rate limited (429), client receives `Retry-After` header
- Retry after specified seconds
- Implement exponential backoff to avoid overwhelming API
Data Types Section
If your API works with multiple data models, document them:
## Data Types
### Export Object
```json
{
"id": "string (export ID)",
"user_id": "string (user ID)",
"status": "string (queued|processing|completed|failed|cancelled)",
"format": "string (csv|json)",
"data_types": "string[] (users|transactions|settings)",
"created_at": "string (ISO8601)",
"completed_at": "string (ISO8601, null if not completed)",
"file_size_bytes": "number (null if not completed)",
"download_url": "string (null if not completed)",
"download_expires_at": "string (ISO8601, null if expired)"
}
User Object
{
"id": "string",
"email": "string",
"created_at": "string (ISO8601)"
}
### Versioning Section
```markdown
## API Versioning
**Current Version**: v1
### Versioning Strategy
- New major versions for breaking changes (v1, v2, etc.)
- Minor versions for additive changes (backwards compatible)
- Versions specified in URL path: `/v1/exports`
### Migration Timeline
- Old version support: Minimum 12 months after new version release
- Deprecation notice: 3 months before shutdown
### Breaking Changes
Examples of breaking changes requiring new version:
- Removing endpoints or fields
- Changing response format fundamentally
- Changing HTTP method of endpoint
Writing Tips
Be Specific About Request/Response
- Show actual JSON examples
- Document all fields (required vs. optional)
- Include data types and valid values
- Specify date/time formats (ISO8601)
Document Error Scenarios
- List common error cases for each endpoint
- Show exact error response format
- Explain how client should handle each error
- Include HTTP status codes
Think About Developer Experience
- Are endpoints intuitive?
- Is pagination consistent across endpoints?
- Are error messages helpful?
- Can a developer implement against this without asking questions?
Link to Related Specs
- Reference data models:
[DATA-001] - Reference technical requirements:
[PRD-001] - Reference design docs:
[DES-001]
Version Your API
- Document versioning strategy
- Make it easy for clients to upgrade
- Provide migration path from old to new versions
Validation & Fixing Issues
Run the Validator
scripts/validate-spec.sh docs/specs/api-contract/api-001-your-spec.md
Common Issues & Fixes
Issue: "Missing endpoint specifications"
- Fix: Document all endpoints with request/response examples
Issue: "Error handling not documented"
- Fix: Add status codes and error response formats
Issue: "No authentication section"
- Fix: Clearly document authentication method and authorization rules
Issue: "Incomplete endpoint details"
- Fix: Add request parameters, response examples, and error cases
Decision-Making Framework
As you write the API spec, consider:
-
Design: Are endpoints intuitive and consistent?
- Consistent URL structure?
- Correct HTTP methods?
- Good naming?
-
Data: What fields are needed in requests/responses?
- Required vs. optional?
- Proper data types?
- Necessary for clients or redundant?
-
Errors: What can go wrong?
- Common error cases?
- Clear error messages?
- Actionable feedback for developers?
-
Performance: Are there efficiency considerations?
- Pagination for large result sets?
- Filtering/search capabilities?
- Rate limiting strategy?
-
Evolution: How will this API change?
- Versioning strategy?
- Backwards compatibility?
- Deprecation timeline?
Next Steps
- Create the spec:
scripts/generate-spec.sh api-contract api-XXX-slug - Research: Find related data models and technical requirements
- Design endpoints: Sketch out URL structure and HTTP methods
- Fill in details for each endpoint using this guide
- Validate:
scripts/validate-spec.sh docs/specs/api-contract/api-XXX-slug.md - Get review from backend and frontend teams
- Share with implementation teams for development