Api Designer Examples
Externalized from the agent definition per the few-shot-examples rule (#1587).
API Designer — Worked Examples
Externalized from the agent definition per the few-shot-examples rule (#1587).
Few-Shot Examples
Example 1: Simple - REST Endpoint Specification
Input: "Design a REST API endpoint for retrieving a single user by ID. Include OpenAPI specification with response schema, error codes, and security requirements."
Output:
openapi: 3.1.0
info:
title: User Management API
version: 1.0.0
description: API for managing user accounts
paths:
/api/users/{userId}:
get:
summary: Get user by ID
description: Retrieves a single user account by unique identifier
operationId: getUserById
tags:
- users
security:
- bearerAuth: []
parameters:
- name: userId
in: path
required: true
description: Unique identifier for the user
schema:
type: string
format: uuid
example: "550e8400-e29b-41d4-a716-446655440000"
responses:
'200':
description: User retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
success:
value:
id: "550e8400-e29b-41d4-a716-446655440000"
email: "[email protected]"
firstName: "John"
lastName: "Doe"
role: "user"
isActive: true
createdAt: "2024-01-15T10:30:00Z"
updatedAt: "2024-01-20T14:45:00Z"
'401':
description: Authentication required
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
examples:
unauthorized:
value:
type: "https://api.example.com/errors/unauthorized"
title: "Unauthorized"
status: 401
detail: "Valid authentication token required"
instance: "/api/users/550e8400-e29b-41d4-a716-446655440000"
'403':
description: Insufficient permissions
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
examples:
forbidden:
value:
type: "https://api.example.com/errors/forbidden"
title: "Forbidden"
status: 403
detail: "Insufficient permissions to access this resource"
instance: "/api/users/550e8400-e29b-41d4-a716-446655440000"
'404':
description: User not found
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
examples:
notFound:
value:
type: "https://api.example.com/errors/not-found"
title: "Not Found"
status: 404
detail: "User with ID '550e8400-e29b-41d4-a716-446655440000' not found"
instance: "/api/users/550e8400-e29b-41d4-a716-446655440000"
'500':
description: Internal server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
components:
schemas:
User:
type: object
required:
- id
- email
- firstName
- lastName
- role
- isActive
- createdAt
- updatedAt
properties:
id:
type: string
format: uuid
description: Unique identifier for the user
email:
type: string
format: email
description: User's email address
firstName:
type: string
minLength: 1
maxLength: 100
description: User's first name
lastName:
type: string
minLength: 1
maxLength: 100
description: User's last name
role:
type: string
enum: [admin, user, guest]
description: User's role in the system
isActive:
type: boolean
description: Whether the user account is active
createdAt:
type: string
format: date-time
description: Timestamp when user was created
updatedAt:
type: string
format: date-time
description: Timestamp when user was last updated
ProblemDetails:
type: object
required:
- type
- title
- status
properties:
type:
type: string
format: uri
description: URI reference identifying the problem type
title:
type: string
description: Short, human-readable summary of the problem
status:
type: integer
format: int32
description: HTTP status code
detail:
type: string
description: Human-readable explanation specific to this occurrence
instance:
type: string
format: uri
description: URI reference identifying the specific occurrence
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token obtained from /api/auth/login
Why This Is Good:
- Complete OpenAPI specification: Uses OpenAPI 3.1.0 standard with all required fields and proper structure
- Rich error handling: Defines 401, 403, 404, 500 responses with RFC 7807 Problem Details format for consistency
- Detailed schema definitions: User schema includes validation constraints (min/max length, enum values, format specifications)
- Security-first: Explicit bearer authentication requirement with JWT format specification
- Concrete examples: Includes example values for both success and error responses to guide implementation
- Clear documentation: Every field has a description, making the API self-documenting
Example 2: Moderate - Payment API Error Handling
Input: "Design comprehensive error handling for a payment processing API. Cover validation errors (400), authentication failures (401), authorization issues (403), and internal errors (500). Use RFC 7807 Problem Details format with extension fields for payment-specific context."
Output:
openapi: 3.1.0
info:
title: Payment Processing API
version: 1.0.0
description: Secure payment processing with comprehensive error handling
paths:
/api/payments:
post:
summary: Process payment
description: Processes a payment transaction
operationId: processPayment
tags:
- payments
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentRequest'
responses:
'201':
description: Payment processed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentResponse'
'400':
description: Validation error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/PaymentValidationProblem'
examples:
invalidAmount:
value:
type: "https://api.example.com/payments/errors/validation"
title: "Validation Error"
status: 400
detail: "Payment validation failed"
instance: "/api/payments"
errors:
- field: "amount"
code: "AMOUNT_TOO_SMALL"
message: "Amount must be at least 0.01"
rejectedValue: 0
- field: "currency"
code: "UNSUPPORTED_CURRENCY"
message: "Currency 'XYZ' is not supported"
rejectedValue: "XYZ"
supportedValues: ["USD", "EUR", "GBP"]
invalidCard:
value:
type: "https://api.example.com/payments/errors/validation"
title: "Validation Error"
status: 400
detail: "Payment method validation failed"
instance: "/api/payments"
errors:
- field: "paymentMethod.cardNumber"
code: "INVALID_CARD_NUMBER"
message: "Card number fails Luhn check"
rejectedValue: "****1234"
- field: "paymentMethod.expiryDate"
code: "CARD_EXPIRED"
message: "Card expired on 2023-12"
rejectedValue: "2023-12"
'401':
description: Authentication required
content:
application/problem+json:
schema:
$ref: '#/components/schemas/PaymentAuthenticationProblem'
examples:
missingToken:
value:
type: "https://api.example.com/payments/errors/authentication"
title: "Authentication Required"
status: 401
detail: "Valid bearer token required for payment processing"
instance: "/api/payments"
authenticationScheme: "Bearer"
realm: "payment-api"
expiredToken:
value:
type: "https://api.example.com/payments/errors/authentication"
title: "Token Expired"
status: 401
detail: "Authentication token expired at 2024-01-20T15:30:00Z"
instance: "/api/payments"
expiredAt: "2024-01-20T15:30:00Z"
authenticationScheme: "Bearer"
'403':
description: Insufficient permissions or payment declined
content:
application/problem+json:
schema:
$ref: '#/components/schemas/PaymentAuthorizationProblem'
examples:
insufficientPermissions:
value:
type: "https://api.example.com/payments/errors/forbidden"
title: "Insufficient Permissions"
status: 403
detail: "User lacks permission to process payments"
instance: "/api/payments"
requiredPermission: "payments:create"
userPermissions: ["payments:read"]
paymentDeclined:
value:
type: "https://api.example.com/payments/errors/declined"
title: "Payment Declined"
status: 403
detail: "Payment declined by payment processor"
instance: "/api/payments"
declineReason: "INSUFFICIENT_FUNDS"
declineCode: "51"
canRetry: false
merchantMessage: "Insufficient funds - request alternate payment method"
fraudSuspected:
value:
type: "https://api.example.com/payments/errors/declined"
title: "Payment Declined"
status: 403
detail: "Payment declined due to fraud detection"
instance: "/api/payments"
declineReason: "FRAUD_SUSPECTED"
declineCode: "59"
canRetry: false
merchantMessage: "Suspected fraud - contact issuer"
riskScore: 0.92
'429':
description: Rate limit exceeded
content:
application/problem+json:
schema:
$ref: '#/components/schemas/PaymentRateLimitProblem'
examples:
rateLimited:
value:
type: "https://api.example.com/payments/errors/rate-limit"
title: "Rate Limit Exceeded"
status: 429
detail: "Payment processing rate limit exceeded"
instance: "/api/payments"
rateLimit:
limit: 100
remaining: 0
resetAt: "2024-01-20T16:00:00Z"
'500':
description: Internal server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/PaymentInternalErrorProblem'
examples:
processorTimeout:
value:
type: "https://api.example.com/payments/errors/internal"
title: "Payment Processor Timeout"
status: 500
detail: "Payment processor did not respond within timeout period"
instance: "/api/payments"
errorId: "err_1234567890abcdef"
canRetry: true
retryAfter: 30
supportContact: "[email protected]"
databaseError:
value:
type: "https://api.example.com/payments/errors/internal"
title: "Internal Server Error"
status: 500
detail: "An unexpected error occurred while processing payment"
instance: "/api/payments"
errorId: "err_fedcba0987654321"
canRetry: true
retryAfter: 60
supportContact: "[email protected]"
components:
schemas:
PaymentRequest:
type: object
required:
- amount
- currency
- paymentMethod
properties:
amount:
type: number
format: decimal
minimum: 0.01
description: Payment amount
currency:
type: string
enum: [USD, EUR, GBP]
description: Three-letter currency code
paymentMethod:
$ref: '#/components/schemas/PaymentMethod'
PaymentMethod:
type: object
required:
- type
- cardNumber
- expiryDate
- cvv
properties:
type:
type: string
enum: [card]
cardNumber:
type: string
pattern: '^[0-9]{13,19}$'
expiryDate:
type: string
pattern: '^[0-9]{4}-[0-9]{2}$'
description: Format YYYY-MM
cvv:
type: string
pattern: '^[0-9]{3,4}$'
PaymentResponse:
type: object
required:
- id
- status
- amount
- currency
properties:
id:
type: string
format: uuid
status:
type: string
enum: [succeeded, processing]
amount:
type: number
currency:
type: string
PaymentValidationProblem:
allOf:
- $ref: '#/components/schemas/BaseProblemDetails'
- type: object
required:
- errors
properties:
errors:
type: array
description: Detailed validation errors
items:
type: object
required:
- field
- code
- message
properties:
field:
type: string
description: JSON path to the invalid field
code:
type: string
description: Machine-readable error code
message:
type: string
description: Human-readable error message
rejectedValue:
description: The value that was rejected
supportedValues:
type: array
description: List of supported values (if applicable)
PaymentAuthenticationProblem:
allOf:
- $ref: '#/components/schemas/BaseProblemDetails'
- type: object
properties:
authenticationScheme:
type: string
description: Expected authentication scheme
realm:
type: string
description: Authentication realm
expiredAt:
type: string
format: date-time
description: When the token expired (if applicable)
PaymentAuthorizationProblem:
allOf:
- $ref: '#/components/schemas/BaseProblemDetails'
- type: object
properties:
requiredPermission:
type: string
description: Permission required for this operation
userPermissions:
type: array
items:
type: string
description: Permissions the user currently has
declineReason:
type: string
description: Reason payment was declined
declineCode:
type: string
description: Processor-specific decline code
canRetry:
type: boolean
description: Whether retrying might succeed
merchantMessage:
type: string
description: Message to display to merchant
riskScore:
type: number
format: float
minimum: 0
maximum: 1
description: Fraud risk score (if applicable)
PaymentRateLimitProblem:
allOf:
- $ref: '#/components/schemas/BaseProblemDetails'
- type: object
required:
- rateLimit
properties:
rateLimit:
type: object
required:
- limit
- remaining
- resetAt
properties:
limit:
type: integer
description: Maximum requests allowed
remaining:
type: integer
description: Requests remaining in window
resetAt:
type: string
format: date-time
description: When the rate limit resets
PaymentInternalErrorProblem:
allOf:
- $ref: '#/components/schemas/BaseProblemDetails'
- type: object
required:
- errorId
properties:
errorId:
type: string
description: Unique error identifier for support tracking
canRetry:
type: boolean
description: Whether retrying the request might succeed
retryAfter:
type: integer
description: Suggested retry delay in seconds
supportContact:
type: string
description: Contact information for support
BaseProblemDetails:
type: object
required:
- type
- title
- status
properties:
type:
type: string
format: uri
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
format: uri
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
Why This Is Good:
- RFC 7807 compliance: Uses standard Problem Details format for all errors, ensuring consistency
- Payment-specific extensions: Adds domain-specific fields like `declineReason`, `declineCode`, `canRetry`, `riskScore` for actionable error handling
- Comprehensive error scenarios: Covers validation, authentication, authorization, rate limiting, and internal errors with realistic examples
- Merchant-friendly messages: Includes `merchantMessage` field with user-facing guidance on how to resolve issues
- Retry guidance: Explicit `canRetry` and `retryAfter` fields help clients implement smart retry logic
- Detailed validation errors: Array of field-level errors with machine-readable codes and human-readable messages
- Support tracking: Error IDs and support contact information enable effective troubleshooting
Example 3: Complex - API Versioning Strategy
Input: "Design an API versioning strategy for migrating from v1 to v2 of a user management API. The v2 API changes the user model structure and adds new required fields. Include deprecation headers, sunset policy, backward compatibility approach, and migration guide."
Output:
# API Versioning Strategy: User Management API v1 → v2
## Executive Summary
This document defines the versioning strategy for migrating the User Management API from v1 to v2. Version 2 introduces breaking changes to the user model structure and adds new required fields for enhanced security and compliance.
## Version Comparison
### v1 User Model (Current)
{ "id": "550e8400-e29b-41d4-a716-446655440000", "email": "[email protected]", "name": "John Doe", "role": "user", "createdAt": "2024-01-15T10:30:00Z" }
### v2 User Model (Target)
{ "id": "550e8400-e29b-41d4-a716-446655440000", "email": "[email protected]", "profile": { "firstName": "John", "lastName": "Doe", "displayName": "John Doe" }, "role": "user", "security": { "mfaEnabled": true, "lastPasswordChange": "2024-01-20T14:00:00Z" }, "metadata": { "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-20T14:00:00Z", "version": 2 } }
### Breaking Changes
| Change | Impact | Migration Required |
|--------|--------|-------------------|
| `name` → `profile.firstName` + `profile.lastName` | HIGH | Clients must split name field |
| New required field: `security.mfaEnabled` | HIGH | Clients must handle new field |
| New required field: `security.lastPasswordChange` | MEDIUM | Clients must handle new field |
| `createdAt` → `metadata.createdAt` | MEDIUM | Clients must update field path |
| Added `metadata.version` | LOW | Informational only |
## Versioning Approach
### URL-Based Versioning
v1: https://api.example.com/v1/users/{userId} v2: https://api.example.com/v2/users/{userId}
**Rationale**: URL-based versioning provides clear separation, simplifies routing, and allows independent evolution of each version.
### Deprecation Timeline
| Date | Milestone | Action |
|------|-----------|--------|
| 2024-02-01 | v2 Release | v2 API goes live, v1 continues working |
| 2024-02-01 | Deprecation Notice | v1 endpoints return `Deprecation` and `Sunset` headers |
| 2024-05-01 | Warning Phase | v1 endpoints return `410 Gone` for new clients |
| 2024-08-01 | Sunset | v1 endpoints removed from production |
**Deprecation Period**: 6 months from v2 release to v1 sunset
### Deprecation Headers (v1 Endpoints)
All v1 endpoints will return the following headers:
HTTP/1.1 200 OK Deprecation: true Sunset: Wed, 01 Aug 2024 00:00:00 GMT Link: https://api.example.com/docs/v1-to-v2-migration; rel="deprecation" X-API-Version: v1 X-API-Latest-Version: v2 X-API-Deprecation-Reason: "Version 1 is deprecated. Please migrate to v2."
### Backward Compatibility Strategy
#### Option 1: Dual-Mode Server (Recommended)
Both v1 and v2 endpoints exist simultaneously during the deprecation period.
**v1 Endpoint** (`/v1/users/{userId}`):
- Returns legacy format
- Internally transforms v2 data to v1 format
- Includes deprecation headers
**v2 Endpoint** (`/v2/users/{userId}`):
- Returns new format
- Native v2 data structure
**Implementation**:
Internal data transformation layer
v1_response: name: "{{ user.profile.firstName }} {{ user.profile.lastName }}" email: "{{ user.email }}" role: "{{ user.role }}" createdAt: "{{ user.metadata.createdAt }}"
v2_response: profile: firstName: "{{ user.profile.firstName }}" lastName: "{{ user.profile.lastName }}" displayName: "{{ user.profile.firstName }} {{ user.profile.lastName }}" email: "{{ user.email }}" role: "{{ user.role }}" security: mfaEnabled: "{{ user.security.mfaEnabled }}" lastPasswordChange: "{{ user.security.lastPasswordChange }}" metadata: createdAt: "{{ user.metadata.createdAt }}" updatedAt: "{{ user.metadata.updatedAt }}" version: 2
#### Option 2: Accept-Version Header
Single URL with version negotiation via header:
GET /api/users/550e8400-e29b-41d4-a716-446655440000 HTTP/1.1 Accept: application/json Accept-Version: v2
**Not Recommended**: Adds complexity, harder to route, caching issues.
## Migration Guide
### For API Consumers
#### Step 1: Test v2 in Development (Week 1-2)
Update base URL
OLD: https://api.example.com/v1/users NEW: https://api.example.com/v2/users
Test v2 endpoint
curl -H "Authorization: Bearer TOKEN" \ https://api.example.com/v2/users/550e8400-e29b-41d4-a716-446655440000
#### Step 2: Update Code to Handle v2 Response (Week 3-4)
**Before (v1)**:
const user = await fetch('/v1/users/123'); console.log(user.name); // "John Doe"
**After (v2)**:
const user = await fetch('/v2/users/123'); console.log(user.profile.firstName); // "John" console.log(user.profile.lastName); // "Doe" console.log(user.profile.displayName); // "John Doe"
#### Step 3: Update POST/PUT Requests (Week 5)
**Before (v1)**:
POST /v1/users { "email": "[email protected]", "name": "New User", "role": "user" }
**After (v2)**:
POST /v2/users { "email": "[email protected]", "profile": { "firstName": "New", "lastName": "User" }, "role": "user", "security": { "mfaEnabled": false } }
#### Step 4: Deploy to Production (Week 6)
- Gradual rollout with feature flags
- Monitor error rates
- Rollback plan ready
### Code Migration Examples
#### JavaScript/TypeScript
// Helper function for backward compatibility function normalizeUser(user: any, apiVersion: 'v1' | 'v2') { if (apiVersion === 'v1') { return { id: user.id, email: user.email, firstName: user.name.split(' ')[0], lastName: user.name.split(' ').slice(1).join(' '), role: user.role, mfaEnabled: false, // v1 doesn't have this createdAt: user.createdAt, }; } else { return { id: user.id, email: user.email, firstName: user.profile.firstName, lastName: user.profile.lastName, role: user.role, mfaEnabled: user.security.mfaEnabled, createdAt: user.metadata.createdAt, }; } }
// Usage const user = await getUserById('123', 'v2'); const normalized = normalizeUser(user, 'v2');
#### Python
def normalize_user(user: dict, api_version: str) -> dict: """Normalize user data across API versions.""" if api_version == 'v1': name_parts = user['name'].split(' ', 1) return { 'id': user['id'], 'email': user['email'], 'first_name': name_parts[0], 'last_name': name_parts[1] if len(name_parts) > 1 else '', 'role': user['role'], 'mfa_enabled': False, 'created_at': user['createdAt'], } else: # v2 return { 'id': user['id'], 'email': user['email'], 'first_name': user['profile']['firstName'], 'last_name': user['profile']['lastName'], 'role': user['role'], 'mfa_enabled': user['security']['mfaEnabled'], 'created_at': user['metadata']['createdAt'], }
## Monitoring & Observability
### Metrics to Track
| Metric | Purpose | Alert Threshold |
|--------|---------|-----------------|
| `api.requests.v1.count` | v1 usage trends | N/A (informational) |
| `api.requests.v2.count` | v2 adoption rate | <10% after 2 months |
| `api.errors.v1.rate` | v1 error rate | >5% |
| `api.errors.v2.rate` | v2 error rate | >2% |
| `api.latency.v1.p95` | v1 performance | >500ms |
| `api.latency.v2.p95` | v2 performance | >500ms |
### Client Migration Dashboard
Track migration progress by client:
SELECT client_id, SUM(CASE WHEN api_version = 'v1' THEN 1 ELSE 0 END) as v1_requests, SUM(CASE WHEN api_version = 'v2' THEN 1 ELSE 0 END) as v2_requests, (v2_requests / (v1_requests + v2_requests)) * 100 as migration_percentage FROM api_requests WHERE timestamp > NOW() - INTERVAL '7 days' GROUP BY client_id ORDER BY migration_percentage ASC;
## Rollback Plan
If critical issues arise in v2:
1. **Immediate**: Extend sunset date by 3 months
2. **Week 1**: Fix v2 issues
3. **Week 2**: Deploy fixes to v2
4. **Week 3**: Resume migration communications
5. **Month 2**: Resume deprecation timeline
## Communication Plan
### Announcement Schedule
| Date | Channel | Message |
|------|---------|---------|
| 2024-01-15 | Email, Blog | v2 preview announcement |
| 2024-02-01 | Email, Blog, In-App | v2 released, v1 deprecation notice |
| 2024-03-01 | Email | 5 months until v1 sunset |
| 2024-05-01 | Email, In-App | 3 months until v1 sunset, warning phase starts |
| 2024-07-01 | Email, In-App | 1 month until v1 sunset, final warning |
| 2024-08-01 | Email | v1 sunset complete |
### Stakeholder Communication
**For Product Teams**:
- Migration guide: https://api.example.com/docs/v1-to-v2-migration
- Breaking changes: https://api.example.com/docs/v2-breaking-changes
- Support channel: #api-migration-support
**For Management**:
- Migration dashboard: https://dashboard.example.com/api-migration
- Risk assessment: [Link to risk document]
- Cost analysis: [Link to cost document]
## Success Criteria
| Criterion | Target | Measurement |
|-----------|--------|-------------|
| v2 adoption rate | >90% by Month 4 | % of requests to v2 endpoints |
| v1 error rate | <1% during deprecation | Error rate on v1 endpoints |
| v2 error rate | <2% after launch | Error rate on v2 endpoints |
| Migration support tickets | <50 total | Support ticket count |
| Client satisfaction | >4.0/5.0 | Post-migration survey |
## OpenAPI Specifications
### v1 Endpoint
/v1/users/{userId}: get: deprecated: true x-sunset-date: "2024-08-01T00:00:00Z" responses: '200': description: User retrieved (DEPRECATED) headers: Deprecation: schema: type: boolean example: true Sunset: schema: type: string format: date-time example: "Wed, 01 Aug 2024 00:00:00 GMT" Link: schema: type: string example: 'https://api.example.com/docs/v1-to-v2-migration; rel="deprecation"'
### v2 Endpoint
/v2/users/{userId}: get: summary: Get user by ID responses: '200': description: User retrieved successfully content: application/json: schema: $ref: '#/components/schemas/UserV2'
## References
- RFC 8594: Sunset HTTP Header
- Semantic Versioning 2.0.0
- [Internal] API Governance Policy
- [Internal] Deprecation Process Guidelines
Why This Is Good:
- Comprehensive strategy: Covers technical, communication, monitoring, and rollback aspects of API versioning
- Clear migration path: Provides concrete examples in multiple languages showing before/after code patterns
- Deprecation best practices: Uses standard HTTP headers (Deprecation, Sunset, Link) per RFC 8594
- Realistic timeline: 6-month deprecation period with clear milestones and stakeholder communication plan
- Measurable success: Defines specific metrics and success criteria to track migration progress
- Backward compatibility: Dual-mode server approach allows gradual migration without breaking existing clients
- Risk mitigation: Includes rollback plan, monitoring dashboard, and support communication channels