BMAD-METHOD/expansion-packs/bmad-javascript-fullstack/data/api-implementation-patterns.md

212 lines
4.9 KiB
Markdown

# <!-- Powered by BMAD™ Core -->
# API Implementation Patterns
Reference guide for implementing REST, GraphQL, and tRPC APIs. Use this when implementing API designs.
## REST API Implementation
### Resource Naming
- Use nouns, not verbs (`/users` not `/getUsers`)
- Plural for collections (`/users` not `/user`)
- Hierarchical for relationships (`/users/123/posts`)
- kebab-case for multi-word resources (`/blog-posts`)
### HTTP Methods
- **GET**: Retrieve (safe, idempotent)
- **POST**: Create (not idempotent)
- **PUT**: Replace entire resource (idempotent)
- **PATCH**: Partial update (idempotent)
- **DELETE**: Remove (idempotent)
### Status Codes
- **2xx Success**: 200 OK, 201 Created, 204 No Content
- **4xx Client Errors**: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
- **5xx Server Errors**: 500 Internal Server Error, 503 Service Unavailable
### Versioning
- **URL path**: `/api/v1/users` (recommended - simple, explicit)
- **Header**: `Accept: application/vnd.api.v1+json` (cleaner URLs)
- **Query param**: `/api/users?version=1` (not recommended - breaks caching)
### Pagination
- **Offset-based**: `/users?page=1&limit=20` (simple, familiar)
- **Cursor-based**: `/users?cursor=abc123&limit=20` (consistent, handles real-time data)
- Always include: total count, has_next, has_prev
### Filtering & Sorting
- Query params: `/users?role=admin&status=active&sort=-createdAt`
- Use `-` prefix for descending sort
- Support multiple filters with AND logic
- Document available filters in API docs
### Error Responses
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{"field": "email", "message": "Invalid email format"}
]
}
}
```
## GraphQL Implementation
### Schema Design
- Define types and relationships clearly
- Use enums for fixed values
- Mark required fields as non-null
- Input types for mutations
- Cursor-based pagination (connections)
### Resolver Best Practices
- Implement DataLoader to avoid N+1 queries
- Field-level resolvers for computed properties
- Structured error handling
- Authentication at resolver level
- Use context for request-scoped data
### Performance
- Query depth limiting (prevent deep nesting abuse)
- Query complexity analysis (cost-based)
- Persisted queries for production
- Caching with Apollo or similar
- Batching with DataLoader
### Error Handling
```graphql
type Error {
message: String!
code: String!
path: [String!]
}
type UserResult {
user: User
errors: [Error!]
}
```
## tRPC Implementation
### Procedures
```typescript
import { z } from 'zod';
const userRouter = router({
getById: publicProcedure
.input(z.string())
.query(({ input }) => db.user.findUnique({ where: { id: input } })),
create: protectedProcedure
.input(z.object({
email: z.string().email(),
name: z.string().min(2)
}))
.mutation(({ input }) => db.user.create({ data: input })),
});
```
### Middleware
- Auth middleware for protected procedures
- Logging middleware for all procedures
- Error handling middleware
- Context builders for request-scoped data
### Router Organization
- Separate routers by domain (user, post, comment)
- Merge at app level
- Share middleware across routers
- Type-safe throughout
## WebSocket Patterns
### Event Structure
```typescript
// Server → Client
{
event: 'message',
data: { userId: '123', text: 'Hello' },
timestamp: 1234567890
}
// Client → Server
{
action: 'send_message',
payload: { text: 'Hello' }
}
```
### Connection Management
- Authenticate on connection
- Heartbeat/ping-pong for keepalive
- Reconnection logic with exponential backoff
- Room/channel management for broadcasts
### Error Handling
- Send error events to client
- Graceful degradation (fallback to polling)
- Connection state management
## Rate Limiting
### Implementation
- Token bucket algorithm (smooth traffic)
- Fixed window (simple, good enough)
- Sliding window (accurate, complex)
### Headers
```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1234567890
Retry-After: 60
```
### Response
```json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"retryAfter": 60
}
}
```
## Caching
### HTTP Caching
```
Cache-Control: public, max-age=3600
ETag: "abc123"
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
```
### Conditional Requests
- `If-None-Match: "abc123"` → 304 Not Modified
- `If-Modified-Since: ...` → 304 Not Modified
### Cache Invalidation
- Time-based (TTL)
- Event-based (on mutations)
- Tag-based (grouped invalidation)
## Documentation
### OpenAPI/Swagger
- Define all endpoints, parameters, responses
- Include examples for each
- Document authentication
- Use tags for grouping
- Validate spec before deploying
### GraphQL SDL
- Add descriptions to all types and fields
- Document deprecations with @deprecated
- Provide usage examples in comments
- Auto-generate docs from schema