api-contract-design · diff
git:20251226.d375719 to git:20260221.26d502d
105 added, 500 removed. Audit A to A.
---
name: api-contract-design
- description: REST and GraphQL API design patterns, OpenAPI/Swagger specifications, versioning strategies, and authentication patterns. Use when designing APIs, reviewing API contracts, evaluating API technologies, or implementing API endpoints. Covers contract-first design, resource modeling, error handling, pagination, and security.
+ description: REST and GraphQL API design patterns, OpenAPI/Swagger specifications, versioning strategies, and authentication patterns. Use when designing APIs, reviewing API contracts, evaluating API technologies, or implementing API endpoints.
---
- # API Design Patterns
-
- A comprehensive skill for designing, documenting, and implementing APIs that developers love to use. Covers REST, GraphQL, and hybrid approaches with emphasis on consistency, discoverability, and maintainability.
-
- ## When to Use
-
- - Designing new REST or GraphQL APIs from scratch
- - Reviewing existing API contracts for consistency and best practices
- - Evaluating API technologies and frameworks
- - Implementing API versioning strategies
- - Designing authentication and authorization flows
- - Creating OpenAPI/Swagger specifications
- - Building developer-friendly API documentation
-
- ## Core Principles
-
- ### 1. Contract-First Design
-
- Define the API contract before implementation. This enables parallel development, clearer communication, and better documentation.
-
- ```
- DESIGN SEQUENCE:
- 1. IDENTIFY use cases and consumer needs
- 2. MODEL resources and their relationships
- 3. DEFINE operations (CRUD + custom actions)
- 4. SPECIFY request/response schemas
- 5. DOCUMENT error scenarios
- 6. VALIDATE with consumers before implementing
- ```
-
- ### 2. Consistency Over Cleverness
-
- APIs should be predictable. Developers should be able to guess how an endpoint works based on patterns established elsewhere in the API.
-
- ```
- CONSISTENCY CHECKLIST:
- - Naming conventions (plural nouns, kebab-case)
- - Response envelope structure
- - Error format across all endpoints
- - Pagination approach
- - Query parameter patterns
- - Date/time formatting (ISO 8601)
- ```
-
- ### 3. Design for Evolution
-
- APIs must evolve without breaking existing consumers. Plan for change from day one.
-
- ```
- EVOLUTION STRATEGIES:
- - Additive changes only (new fields, endpoints)
- - Deprecation with sunset periods
- - Version negotiation (headers, URL paths)
- - Backward compatibility testing
- ```
-
- ## REST API Patterns
-
- ### Resource Modeling
-
- Resources represent business entities. URLs should reflect the resource hierarchy.
-
- ```
- GOOD:
- GET /users # List users
- POST /users # Create user
- GET /users/{id} # Get user
- PATCH /users/{id} # Partial update
- DELETE /users/{id} # Delete user
- GET /users/{id}/orders # User's orders (sub-resource)
-
- AVOID:
- GET /getUsers # Verbs in URLs
- POST /createNewUser # Redundant verbs
- GET /user-list # Inconsistent naming
- POST /users/{id}/delete # Wrong HTTP method
- ```
-
- ### HTTP Method Semantics
-
- | Method | Usage | Idempotent | Safe |
- |--------|-------|------------|------|
- | GET | Retrieve resource(s) | Yes | Yes |
- | POST | Create resource, trigger action | No | No |
- | PUT | Replace entire resource | Yes | No |
- | PATCH | Partial update | Yes | No |
- | DELETE | Remove resource | Yes | No |
- | OPTIONS | CORS preflight, capability discovery | Yes | Yes |
-
- ### Status Code Selection
-
- ```
- SUCCESS:
- 200 OK - Successful GET, PUT, PATCH, DELETE
- 201 Created - Successful POST (include Location header)
- 202 Accepted - Async operation started
- 204 No Content - Success with no response body
-
- CLIENT ERRORS:
- 400 Bad Request - Malformed request, validation failure
- 401 Unauthorized - Missing or invalid authentication
- 403 Forbidden - Authenticated but not authorized
- 404 Not Found - Resource doesn't exist
- 409 Conflict - State conflict (duplicate, version mismatch)
- 422 Unprocessable- Semantically invalid (business rule violation)
- 429 Too Many - Rate limit exceeded
+ ## Persona
- SERVER ERRORS:
- 500 Internal - Unexpected server error
- 502 Bad Gateway - Upstream service failure
- 503 Unavailable - Temporary overload or maintenance
- 504 Gateway Timeout - Upstream timeout
- ```
+ Act as an API design specialist who creates developer-friendly, consistent, and evolvable API contracts. You apply contract-first design principles, ensuring APIs are defined before implementation to enable parallel development and clear communication.
- ### Error Response Format
+ **Design Target**: $ARGUMENTS
- Standardize error responses across all endpoints:
+ ## Interface
- ```json
- {
- "error": {
- "code": "VALIDATION_ERROR",
- "message": "Request validation failed",
- "details": [
- {
- "field": "email",
- "code": "INVALID_FORMAT",
- "message": "Email must be a valid email address"
- }
- ],
- "requestId": "req_abc123",
- "timestamp": "2025-01-15T10:30:00Z",
- "documentation": "https://api.example.com/docs/errors#VALIDATION_ERROR"
- }
+ ApiStyle {
+ type: REST | GRAPHQL | HYBRID
+ versioning: URL_PATH | HEADER | QUERY_PARAM | DUAL
+ auth: API_KEY | OAUTH2 | JWT | NONE
}
- ```
- ### Pagination Patterns
-
- #### Offset-Based (Simple, not for large datasets)
-
- ```
- GET /users?offset=20&limit=10
-
- Response:
- {
- "data": [...],
- "pagination": {
- "total": 150,
- "offset": 20,
- "limit": 10,
- "hasMore": true
- }
+ DesignDecision {
+ area: String // e.g., pagination, error format, naming
+ choice: String // selected approach
+ rationale: String // why this choice fits
}
- ```
- #### Cursor-Based (Recommended for large datasets)
+ fn analyzeRequirements(target)
+ fn selectApiStyle()
+ fn designContract(style)
+ fn validateContract(contract)
+ fn recommendNextSteps(contract)
- ```
- GET /users?cursor=eyJpZCI6MTAwfQ&limit=10
+ ## Constraints
- Response:
- {
- "data": [...],
- "pagination": {
- "nextCursor": "eyJpZCI6MTEwfQ",
- "prevCursor": "eyJpZCI6OTB9",
- "hasMore": true
+ Constraints {
+ require {
+ Define the API contract before any implementation begins.
+ Apply consistent naming conventions across all endpoints (plural nouns, kebab-case).
+ Standardize error response format across all endpoints.
+ Include rate limit headers and idempotency keys for non-idempotent operations.
+ Use HTTPS exclusively.
+ Version the API from day one.
+ Document all error codes with resolution steps.
}
- }
- ```
-
- ### Filtering and Sorting
-
- ```
- FILTERING:
- GET /users?status=active # Exact match
- GET /users?created_after=2025-01-01 # Date range
- GET /users?role=admin,moderator # Multiple values
- GET /users?search=john # Full-text search
-
- SORTING:
- GET /users?sort=created_at # Ascending (default)
- GET /users?sort=-created_at # Descending (prefix -)
- GET /users?sort=status,-created_at # Multiple fields
-
- FIELD SELECTION:
- GET /users?fields=id,name,email # Sparse fieldsets
- GET /users?expand=organization # Include related
- ```
-
- ## GraphQL Patterns
-
- ### Schema Design Principles
-
- ```graphql
- # Use clear, descriptive type names
- type User {
- id: ID!
- email: String!
- displayName: String!
- createdAt: DateTime!
-
- # Relationships with clear naming
- organization: Organization
- orders(first: Int, after: String): OrderConnection!
+ never {
+ Expose internal implementation details (database IDs, stack traces) in responses.
+ Use GET for operations with side effects.
+ Mix REST and RPC styles in the same API.
+ Break existing consumers without versioning.
+ Authenticate via query parameters (except OAuth callbacks).
+ Create deeply nested URLs (more than 2 levels).
+ Return different structures for success vs error responses.
+ }
}
- # Use connections for paginated lists
- type OrderConnection {
- edges: [OrderEdge!]!
- pageInfo: PageInfo!
- totalCount: Int!
- }
+ ## State
- type OrderEdge {
- node: Order!
- cursor: String!
+ State {
+ target = $ARGUMENTS
+ apiStyle: ApiStyle // selected in selectApiStyle
+ decisions: [DesignDecision] // accumulated during designContract
+ contract: String // final specification output
}
- type PageInfo {
- hasNextPage: Boolean!
- hasPreviousPage: Boolean!
- startCursor: String
- endCursor: String
- }
- ```
+ ## Reference Materials
- ### Query Design
+ See `reference/` directory for detailed patterns:
+ - [REST Patterns](reference/rest-patterns.md) — Resource modeling, HTTP methods, status codes, error format, pagination, filtering
+ - [GraphQL Patterns](reference/graphql-patterns.md) — Schema design, queries, mutations, N+1 prevention
+ - [Versioning and Auth](reference/versioning-and-auth.md) — Versioning strategies, API keys, OAuth 2.0, JWT
+ - [OpenAPI Patterns](reference/openapi-patterns.md) — Specification structure, reusable components
- ```graphql
- type Query {
- # Single resource by ID
- user(id: ID!): User
+ ## Workflow
- # List with filtering and pagination
- users(
- filter: UserFilter
- first: Int
- after: String
- orderBy: UserOrderBy
- ): UserConnection!
+ fn analyzeRequirements(target) {
+ Identify use cases and consumer needs from target context.
+ Model resources and their relationships.
+ Determine operation types (CRUD + custom actions).
+ Assess non-functional requirements (latency, throughput, caching).
- # Viewer pattern for current user
- viewer: User
+ Constraints {
+ require {
+ Identify at least the primary consumer (web, mobile, server, third-party).
+ Map each use case to specific resource operations.
+ }
+ }
}
- input UserFilter {
- status: UserStatus
- organizationId: ID
- searchQuery: String
- }
+ fn selectApiStyle() {
+ match (requirements) {
+ multiple consumers + different data needs => GRAPHQL or HYBRID
+ simple CRUD + broad ecosystem => REST
+ real-time + subscriptions => GRAPHQL
+ public API + maximum compatibility => REST
+ }
- enum UserOrderBy {
- CREATED_AT_ASC
- CREATED_AT_DESC
- NAME_ASC
- NAME_DESC
+ Select versioning strategy (default: DUAL — major in URL, minor in header).
+ Select auth pattern based on consumer type.
}
- ```
- ### Mutation Design
+ fn designContract(style) {
+ match (style.type) {
+ REST => load reference/rest-patterns.md, design resources + endpoints
+ GRAPHQL => load reference/graphql-patterns.md, design schema + operations
+ HYBRID => load both, design unified contract
+ }
- ```graphql
- type Mutation {
- # Use input types for complex mutations
- createUser(input: CreateUserInput!): CreateUserPayload!
- updateUser(input: UpdateUserInput!): UpdateUserPayload!
- deleteUser(id: ID!): DeleteUserPayload!
- }
+ For each resource/type:
+ 1. Define request/response schemas
+ 2. Specify error scenarios
+ 3. Design pagination approach
+ 4. Document query parameters / arguments
- input CreateUserInput {
- email: String!
- displayName: String!
- organizationId: ID
+ Load reference/versioning-and-auth.md for auth and versioning details.
+ Load reference/openapi-patterns.md when generating OpenAPI spec.
}
- # Payload types for consistent responses
- type CreateUserPayload {
- user: User
- errors: [UserError!]!
- }
+ fn validateContract(contract) {
+ CONSISTENCY CHECKLIST:
+ - Naming conventions (plural nouns, kebab-case)
+ - Response envelope structure
+ - Error format across all endpoints
+ - Pagination approach
+ - Query parameter patterns
+ - Date/time formatting (ISO 8601)
- type UserError {
- field: String
- code: String!
- message: String!
+ EVOLUTION CHECK:
+ - Additive changes only (new fields, endpoints)
+ - Deprecation with sunset periods
+ - Version negotiation support
+ - Backward compatibility
}
- ```
- ### N+1 Query Prevention
-
- ```
- STRATEGIES:
- 1. DataLoader pattern for batching
- 2. Query complexity analysis and limits
- 3. Depth limiting
- 4. Field-level cost calculation
- 5. Persisted queries for production
- ```
-
- ## API Versioning Strategies
-
- ### URL Path Versioning
-
- ```
- GET /v1/users
- GET /v2/users
-
- PROS:
- - Explicit and visible
- - Easy to route in infrastructure
- - Clear in logs and monitoring
-
- CONS:
- - URL pollution
- - Harder to deprecate gracefully
- ```
-
- ### Header Versioning
-
- ```
- GET /users
- Accept: application/vnd.api+json; version=2
-
- PROS:
- - Clean URLs
- - Content negotiation friendly
- - Easier partial versioning
-
- CONS:
- - Less visible
- - Harder to test in browser
- ```
-
- ### Query Parameter Versioning
-
- ```
- GET /users?api-version=2025-01-15
-
- PROS:
- - Easy to test
- - Visible in URLs
- - Date-based versions are intuitive
-
- CONS:
- - Clutters query strings
- - Easy to forget
- ```
-
- ### Recommended: Dual Approach
-
- ```
- 1. Major versions in URL path: /v1/, /v2/
- 2. Minor versions via header: API-Version: 2025-01-15
- 3. Default to latest minor within major
- 4. Sunset headers for deprecation warnings
- ```
-
- ## Authentication Patterns
-
- ### API Keys
-
- ```
- USAGE: Server-to-server, rate limiting, analytics
- TRANSPORT: Header (Authorization: ApiKey xxx) or query param
-
- SECURITY:
- - Rotate keys regularly
- - Different keys for environments
- - Scope keys to specific operations
- - Never expose in client-side code
- ```
-
- ### OAuth 2.0 / OIDC
-
- ```
- FLOWS:
- - Authorization Code + PKCE: Web apps, mobile apps
- - Client Credentials: Server-to-server
- - Device Code: CLI tools, smart TVs
-
- TOKEN HANDLING:
- - Short-lived access tokens (15-60 min)
- - Refresh tokens for session extension
- - Token introspection for validation
- - Token revocation endpoint
- ```
-
- ### JWT Best Practices
-
- ```
- CLAIMS:
- {
- "iss": "https://auth.example.com",
- "sub": "user_123",
- "aud": "api.example.com",
- "exp": 1705320000,
- "iat": 1705316400,
- "scope": "read:users write:users"
+ fn recommendNextSteps(contract) {
+ match (contract) {
+ complete spec => Validate with consumers before implementing
+ partial design => Identify remaining decisions
+ review request => List specific improvements with rationale
+ }
}
- SECURITY:
- - Use asymmetric keys (RS256, ES256)
- - Validate all claims
- - Check token expiration
- - Verify audience matches
- - Keep tokens stateless when possible
- ```
-
- ## OpenAPI/Swagger Patterns
-
- ### Specification Structure
-
- ```yaml
- openapi: 3.1.0
- info:
- title: Example API
- version: 1.0.0
- description: API description with markdown support
- contact:
- name: API Support
- url: https://example.com/support
-
- servers:
- - url: https://api.example.com/v1
- description: Production
- - url: https://api.staging.example.com/v1
- description: Staging
-
- security:
- - bearerAuth: []
-
- paths:
- /users:
- get:
- operationId: listUsers
- summary: List all users
- tags: [Users]
- # ... operation details
-
- components:
- schemas:
- User:
- type: object
- required: [id, email]
- properties:
- id:
- type: string
- format: uuid
- email:
- type: string
- format: email
- ```
-
- ### Reusable Components
-
- ```yaml
- components:
- schemas:
- # Reusable pagination
- PaginationMeta:
- type: object
- properties:
- total:
- type: integer
- page:
- type: integer
- perPage:
- type: integer
-
- # Reusable error
- Error:
- type: object
- required: [code, message]
- properties:
- code:
- type: string
- message:
- type: string
-
- parameters:
- # Reusable query params
- PageParam:
- name: page
- in: query
- schema:
- type: integer
- default: 1
- minimum: 1
-
- responses:
- # Reusable responses
- NotFound:
- description: Resource not found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
- ```
-
- ## Best Practices
-
- ### Do
-
- - Design APIs for consumers, not implementation convenience
- - Use meaningful HTTP status codes
- - Provide idempotency keys for non-idempotent operations
- - Include rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining)
- - Return Location header for created resources
- - Support CORS properly for browser clients
- - Document all error codes with resolution steps
- - Version your API from day one
- - Use HTTPS exclusively
- - Implement request validation with clear error messages
-
- ### Avoid
-
- - Exposing internal implementation details (database IDs, stack traces)
- - Breaking changes without versioning
- - Inconsistent naming across endpoints
- - Deeply nested URLs (more than 2 levels)
- - Using GET for operations with side effects
- - Returning different structures for success/error
- - Ignoring backward compatibility
- - Over-fetching in GraphQL without limits
- - Authentication via query parameters (except OAuth callbacks)
- - Mixing REST and RPC styles in the same API
-
- ## References
-
- - `templates/rest-api-template.md` - REST API specification template
- - `templates/graphql-schema-template.md` - GraphQL schema template
+ apiContractDesign(target) {
+ analyzeRequirements(target) |> selectApiStyle |> designContract |> validateContract |> recommendNextSteps
+ }