527 lines
13 KiB
Markdown
527 lines
13 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```markdown
|
|
# 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:
|
|
|
|
```markdown
|
|
## 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
|
|
```markdown
|
|
**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
|
|
- `format` (string, required): Export file format
|
|
- Allowed values: `csv`, `json`
|
|
- `date_range` (object, optional): Filter data by date range
|
|
- `start` (string, ISO8601 format)
|
|
- `end` (string, ISO8601 format)
|
|
|
|
### Response
|
|
|
|
**Status: 201 Created**
|
|
```json
|
|
{
|
|
"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**
|
|
```json
|
|
{
|
|
"error": "invalid_request",
|
|
"message": "data_types must include at least one type",
|
|
"code": "VALIDATION_ERROR"
|
|
}
|
|
```
|
|
|
|
**Status: 401 Unauthorized**
|
|
```json
|
|
{
|
|
"error": "unauthorized",
|
|
"message": "Invalid or missing authorization token",
|
|
"code": "AUTH_FAILED"
|
|
}
|
|
```
|
|
|
|
**Status: 429 Too Many Requests**
|
|
```json
|
|
{
|
|
"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-*` headers
|
|
- `X-RateLimit-Limit: 10`
|
|
- `X-RateLimit-Remaining: 5`
|
|
- `X-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**
|
|
```json
|
|
{
|
|
"error": "not_found",
|
|
"message": "Export not found",
|
|
"code": "EXPORT_NOT_FOUND"
|
|
}
|
|
```
|
|
|
|
### Export Status Values
|
|
- `queued` - Job is waiting to be processed
|
|
- `processing` - Job is currently running
|
|
- `completed` - Export is ready for download
|
|
- `failed` - Export failed (see error field)
|
|
- `cancelled` - User cancelled the export
|
|
|
|
### Error Field (when status: failed)
|
|
```json
|
|
{
|
|
"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)
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```markdown
|
|
## 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:
|
|
|
|
```markdown
|
|
## 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
|
|
```json
|
|
{
|
|
"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
|
|
```bash
|
|
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:
|
|
|
|
1. **Design**: Are endpoints intuitive and consistent?
|
|
- Consistent URL structure?
|
|
- Correct HTTP methods?
|
|
- Good naming?
|
|
|
|
2. **Data**: What fields are needed in requests/responses?
|
|
- Required vs. optional?
|
|
- Proper data types?
|
|
- Necessary for clients or redundant?
|
|
|
|
3. **Errors**: What can go wrong?
|
|
- Common error cases?
|
|
- Clear error messages?
|
|
- Actionable feedback for developers?
|
|
|
|
4. **Performance**: Are there efficiency considerations?
|
|
- Pagination for large result sets?
|
|
- Filtering/search capabilities?
|
|
- Rate limiting strategy?
|
|
|
|
5. **Evolution**: How will this API change?
|
|
- Versioning strategy?
|
|
- Backwards compatibility?
|
|
- Deprecation timeline?
|
|
|
|
## Next Steps
|
|
|
|
1. **Create the spec**: `scripts/generate-spec.sh api-contract api-XXX-slug`
|
|
2. **Research**: Find related data models and technical requirements
|
|
3. **Design endpoints**: Sketch out URL structure and HTTP methods
|
|
4. **Fill in details** for each endpoint using this guide
|
|
5. **Validate**: `scripts/validate-spec.sh docs/specs/api-contract/api-XXX-slug.md`
|
|
6. **Get review** from backend and frontend teams
|
|
7. **Share with implementation teams** for development
|