# 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