api-design
travisjneuman/.claude/skills/api-design/SKILL.md
REST and GraphQL API design best practices including OpenAPI specs. Use when designing APIs, documenting endpoints, or reviewing API architecture.
Skill99 starsChanged 7 months ago
- Reads credentials
What's in it
- API Design Guide
- REST API Principles
- Resource Naming
- HTTP Methods
- Status Codes
- Response Format
- Pagination
- Filtering, Sorting, Fields
- Versioning
- OpenAPI Specification
- Authentication
- Rate Limiting
- Security Checklist
- gRPC and Protocol Buffers
- Proto Definition
- When to Use gRPC vs REST
- tRPC for TypeScript
- Webhook Design Patterns
- Webhook Payload
- Signature Verification
- Retry Strategy
- Idempotency
- API Versioning Strategies
---
name: api-design
description: REST and GraphQL API design best practices including OpenAPI specs. Use when designing APIs, documenting endpoints, or reviewing API architecture.
---
# API Design Guide
Best practices for designing developer-friendly, maintainable APIs.
## REST API Principles
### Resource Naming
**Use nouns, not verbs**:
```
✓ GET /users
✓ GET /users/123
✓ GET /users/123/orders
✗ GET /getUsers
✗ GET /fetchUserById
✗ POST /createNewOrder
```
**Use plural nouns**:
```
✓ /users
✓ /orders
✓ /products
✗ /user
✗ /order
```
**Hierarchical relationships**:
```
/users/{userId}/orders # User's orders
/users/{userId}/orders/{orderId} # Specific order
```
---
### HTTP Methods
| Method | Purpose | Idempotent | Request Body |
| ------ | ------------------------- | ---------- | ------------ |
| GET | Retrieve resource(s) | Yes | No |
| POST | Create resource | No | Yes |
| PUT | Replace resource entirely | Yes | Yes |
| PATCH | Update resource partially | No | Yes |
| DELETE | Remove resource | Yes | No |
---
### Status Codes
**Success (2xx)**:
- `200 OK` - Request succeeded
- `201 Created` - Resource created (return Location header)
- `204 No Content` - Success with no response body
**Client Error (4xx)**:
- `400 Bad Request` - Malformed request
- `401 Unauthorized` - Authentication required
- `403 Forbidden` - No permission
- `404 Not Found` - Resource doesn't exist
- `409 Conflict` - State conflict
- `422 Unprocessable Entity` - Validation failed
- `429 Too Many Requests` - Rate limited
**Server Error (5xx)**:
- `500 Internal Server Error` - Unexpected error
- `503 Service Unavailable` - Temporary outage
---
### Response Format
**Successful response**:
```json
{
"data": {
"id": "123",
"name": "John Doe",
"email": "john@example.com"
}
}
```
**Collection response**:
```json
{
"data": [
{ "id": "1", "name": "Item 1" },
{ "id": "2", "name": "Item 2" }
],
"meta": {
"page": 1,
"perPage": 20,
"total": 100,
"totalPages": 5
},
"links": {
"self": "/items?page=1",
"next": "/items?page=2",
"prev": null
}
}
```
**Error response**:
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Must be a valid email address"
}
]
}
}
```
---
### Pagination
**Offset-based** (simple, but slow on large datasets):
```
GET /users?page=2&perPage=20
GET /users?offset=40&limit=20
```
**Cursor-based** (efficient, recommended):
```
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
```
Response includes next cursor:
```json
{
"data": [...],
"meta": {
"nextCursor": "eyJpZCI6MTQzfQ",
"hasMore": true
}
}
```
---
### Filtering, Sorting, Fields
**Filtering**:
```
GET /users?status=active
GET /users?created_after=2024-01-01
GET /users?role=admin,moderator
```
**Sorting**:
```
GET /users?sort=name
GET /users?sort=-created_at # Descending
GET /users?sort=status,-created_at # Multiple fields
```
**Field selection**:
```
GET /users?fields=id,name,email
GET /users?include=orders,profile
```
---
### Versioning
**URL path** (recommended):
```
/api/v1/users
/api/v2/users
```
**Header**:
```
Accept: application/vnd.api+json;version=2
```
---
## OpenAPI Specification
```yaml
openapi: 3.0.3
info:
title: My API
version: 1.0.0
description: API for managing users
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
tags: [Users]
parameters:
- name: page
in: query
schema:
type: integer
default: 1
responses:
"200":
description: List of users
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
required: [id, email]
properties:
id:
type: string
email:
type: string
format: email
name:
type: string
```
---
## Authentication
**API Keys** (simple, for server-to-server):
```
Authorization: Api-Key YOUR_API_KEY
```
**Bearer Tokens** (JWT, OAuth):
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```
**Include in OpenAPI**:
```yaml
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
```
---
## Rate Limiting
Include headers in responses:
```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
```
Return `429 Too Many Requests` when exceeded.
---
## Security Checklist
- [ ] HTTPS only
- [ ] Authentication on protected routes
- [ ] Input validation
- [ ] Output encoding
- [ ] Rate limiting
- [ ] CORS configuration
- [ ] No sensitive data in URLs
- [ ] Audit logging
---
## gRPC and Protocol Buffers
### Proto Definition
```protobuf
syntax = "proto3";
package user.v1;
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
rpc CreateUser(CreateUserRequest) returns (User);
rpc StreamUpdates(StreamRequest) returns (stream UserUpdate);
}
message User {
string id = 1;
string name = 2;
string email = 3;
google.protobuf.Timestamp created_at = 4;
}
message GetUserRequest {
string id = 1;
}
message ListUsersRequest {
int32 page_size = 1;
string page_token = 2;
}
message ListUsersResponse {
repeated User users = 1;
string next_page_token = 2;
}
```
### When to Use gRPC vs REST
| Factor | gRPC | REST |
| ----------------- | --------------------------- | --------------------------- |
| **Performance** | Binary, fast | JSON, human-readable |
| **Streaming** | Bidirectional | SSE/WebSocket workaround |
| **Type safety** | Proto generates types | OpenAPI + codegen |
| **Browser** | Needs gRPC-Web proxy | Native |
| **Tooling** | Protoc, Buf | Swagger, Postman |
| **Best for** | Service-to-service, streaming | Public APIs, web clients |
---
## tRPC for TypeScript
```typescript
// server/router.ts
import { router, publicProcedure, protectedProcedure } from './trpc';
import { z } from 'zod';
export const appRouter = router({
user: router({
get: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return db.user.findUnique({ where: { id: input.id } });
}),
create: protectedProcedure
.input(z.object({
name: z.string().min(1),
email: z.string().email(),
}))
.mutation(async ({ input, ctx }) => {
return db.user.create({ data: { ...input, createdBy: ctx.userId } });
}),
}),
});
export type AppRouter = typeof appRouter;
// client.ts - Full type inference, no codegen
const user = trpc.user.get.useQuery({ id: '123' });
const createUser = trpc.user.create.useMutation();
```
tRPC is ideal for monorepo full-stack TypeScript apps where client and server share the same codebase.
---
## Webhook Design Patterns
### Webhook Payload
```json
{
"id": "evt_abc123",
"type": "order.completed",
"created_at": "2025-01-15T10:30:00Z",
"data": {
"order_id": "ord_456",
"total": 99.99,
"currency": "USD"
}
}
```
### Signature Verification
```typescript
// Sign webhooks with HMAC-SHA256
import crypto from 'crypto';
function signWebhook(payload: string, secret: string): string {
return crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
}
// Verify on receiving end
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = signWebhook(payload, secret);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}
```
### Retry Strategy
```
Attempt 1: Immediately
Attempt 2: After 1 minute
Attempt 3: After 5 minutes
Attempt 4: After 30 minutes
Attempt 5: After 2 hours
Attempt 6: After 24 hours (final)
Failed webhooks: log, alert, manual retry UI
```
### Idempotency
```typescript
// Include idempotency key in webhook
// Receivers should deduplicate based on event ID
async function handleWebhook(event: WebhookEvent) {
// Check if already processed
const existing = await db.processedEvents.findUnique({
where: { eventId: event.id },
});
if (existing) return { status: 'already_processed' };
// Process and record
await db.$transaction([
processEvent(event),
db.processedEvents.create({ data: { eventId: event.id } }),
]);
}
```
---
## API Versioning Strategies
| Strategy | Example | Pros | Cons |
| ------------------- | -------------------------------- | ------------------------ | ------------------------- |
| **URL path** | `/api/v1/users` | Explicit, easy to route | URL pollution |
| **Query parameter** | `/api/users?version=1` | Optional parameter | Easy to miss |
| **Header** | `Accept: application/vnd.api.v1` | Clean URLs | Hidden, harder to test |
| **Content negotiation** | `Accept: application/json;v=2` | Standards-based | Complex to implement |
**Recommendation:** URL path versioning for simplicity. Only bump major versions for breaking changes. Use additive, non-breaking changes within a version.
More agent context in travisjneuman/.claude
127 other files this repository gives its agents, the first 60 shown.
CLAUDE.md
Skill
- accessibility-a11yskills/accessibility-a11y/SKILL.md
- agent-teamsskills/agent-teams/SKILL.md
- ai-ml-developmentskills/ai-ml-development/SKILL.md
- ai-policy-generatorskills/ai-policy-generator/SKILL.md
- android-developmentskills/android-development/SKILL.md
- application-securityskills/application-security/SKILL.md
- ar-vr-xrskills/ar-vr-xr/SKILL.md
- audio-productionskills/audio-production/SKILL.md
- authentication-patternsskills/authentication-patterns/SKILL.md
- auto-claudeskills/auto-claude/SKILL.md
- battle-card-builderskills/battle-card-builder/SKILL.md
- blockchain-web3skills/blockchain-web3/SKILL.md
- brand-identityskills/brand-identity/SKILL.md
- business-strategyskills/business-strategy/SKILL.md
- career-path-plannerskills/career-path-planner/SKILL.md
- case-interview-practiceskills/case-interview-practice/SKILL.md
- codebase-documenterskills/codebase-documenter/SKILL.md
- compliance-engineeringskills/compliance-engineering/SKILL.md
- content-repurposerskills/content-repurposer/SKILL.md
- contract-redlinerskills/contract-redliner/SKILL.md
- core-workflowskills/core-workflow/SKILL.md
- course-material-creatorskills/course-material-creator/SKILL.md
- customer-persona-builderskills/customer-persona-builder/SKILL.md
- customer-successskills/customer-success/SKILL.md
- database-expertskills/database-expert/SKILL.md
- data-engineeringskills/data-engineering/SKILL.md
- data-scienceskills/data-science/SKILL.md
- debate-practice-coachskills/debate-practice-coach/SKILL.md
- debug-systematicskills/debug-systematic/SKILL.md
- devex-sdk-designskills/devex-sdk-design/SKILL.md
- devops-cloudskills/devops-cloud/SKILL.md
- docxskills/document-skills/docx/SKILL.md
- pdfskills/document-skills/pdf/SKILL.md
- pptxskills/document-skills/pptx/SKILL.md
- document-skillsskills/document-skills/SKILL.md
- xlsxskills/document-skills/xlsx/SKILL.md
- edge-computingskills/edge-computing/SKILL.md
- electron-desktopskills/electron-desktop/SKILL.md
- email-systemsskills/email-systems/SKILL.md
- embedded-iotskills/embedded-iot/SKILL.md
- event-driven-architectureskills/event-driven-architecture/SKILL.md
- event-plannerskills/event-planner/SKILL.md
- financeskills/finance/SKILL.md
- financial-scenario-plannerskills/financial-scenario-planner/SKILL.md
- flutter-developmentskills/flutter-development/SKILL.md
- frontend-enhancerskills/frontend-enhancer/SKILL.md
- fundraising-analyzerskills/fundraising-analyzer/SKILL.md
- game-developmentskills/game-development/SKILL.md
- generic-code-reviewerskills/generic-code-reviewer/SKILL.md
- generic-design-systemskills/generic-design-system/SKILL.md
- generic-feature-developerskills/generic-feature-developer/SKILL.md
- generic-fullstack-code-reviewerskills/generic-fullstack-code-reviewer/SKILL.md
- generic-fullstack-design-systemskills/generic-fullstack-design-system/SKILL.md
- generic-fullstack-feature-developerskills/generic-fullstack-feature-developer/SKILL.md
- generic-fullstack-ux-designerskills/generic-fullstack-ux-designer/SKILL.md
- generic-react-code-reviewerskills/generic-react-code-reviewer/SKILL.md
- generic-react-design-systemskills/generic-react-design-system/SKILL.md
- generic-react-feature-developerskills/generic-react-feature-developer/SKILL.md
- generic-react-ux-designerskills/generic-react-ux-designer/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

