Initial commit
This commit is contained in:
526
skills/spec-author/guides/api-contract.md
Normal file
526
skills/spec-author/guides/api-contract.md
Normal file
@@ -0,0 +1,526 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user