REST API design patterns including resource naming, HTTP methods, status codes, pagination, filtering, error responses, versioning, rate limiting, idempotency, and security. Always activate when the user is designing or reviewing API endpoints, adding pagination or filtering, implementing error handling, planning versioning, building public or partner-facing APIs, or asks how to structure a route, response, or status code — even if they don't use the word "API design".
Installation
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
REST API design patterns including resource naming, HTTP methods, status codes, pagination, filtering, error responses, versioning, rate limiting, idempotency, and security. Always activate when the user is designing or reviewing API endpoints, adding pagination or filtering, implementing error handling, planning versioning, building public or partner-facing APIs, or asks how to structure a route, response, or status code — even if they don't use the word "API design".
API Design Patterns
Conventions and best practices for designing consistent, secure, developer-friendly REST APIs.
Workflow
When this skill activates:
Identify the scope — new endpoint design, review of existing API, adding pagination/filtering, versioning strategy, or security hardening.
Apply the checklist at the bottom before marking any endpoint complete.
Adapt the implementation examples to the user's stack — TypeScript, Python, and Go patterns are all provided.
Flag violations proactively if spotted in user-provided code — wrong status codes, unhandled JSON parse errors, tokens in query params, and missing auth checks are the most common.
For public or partner APIs: always address versioning, deprecation timeline, rate limiting, and OpenAPI documentation.
Resource Design
URL Structure
# Resources are nouns — plural, lowercase, kebab-case
GET /api/v1/users
GET /api/v1/users/:id
POST /api/v1/users
PUT /api/v1/users/:id # full replacement
PATCH /api/v1/users/:id # partial update
DELETE /api/v1/users/:id
# Sub-resources for ownership relationships
GET /api/v1/users/:id/orders
POST /api/v1/users/:id/orders
# Actions that don't map to CRUD — use verbs sparingly, always POST
POST /api/v1/orders/:id/cancel
POST /api/v1/auth/login
POST /api/v1/auth/refresh
Naming Rules
# GOOD
/api/v1/team-members # kebab-case for multi-word
/api/v1/orders?status=active # filtering via query params
/api/v1/users/123/orders # nested for ownership
# BAD
/api/v1/getUsers # verb in URL
/api/v1/user # singular
/api/v1/team_members # snake_case in URLs
/api/v1/users/123/getOrders # verb in nested resource
HTTP Methods and Status Codes
Method Semantics
Method
Idempotent
Safe
Use For
GET
Yes
Yes
Retrieve resources
POST
No
No
Create resources, trigger actions
PUT
Yes
No
Full replacement of a resource
PATCH
No*
No
Partial update
DELETE
Yes
No
Remove a resource
*PATCH can be made idempotent with a conditional If-Match header.
Status Code Reference
# Success
200 OK — GET, PUT, PATCH (with response body)
201 Created — POST (include Location header)
204 No Content — DELETE, PUT (no response body)
# Client Errors
400 Bad Request — Malformed JSON, invalid syntax
401 Unauthorized — Missing or invalid authentication
403 Forbidden — Authenticated but not authorized
404 Not Found — Resource doesn't exist
409 Conflict — Duplicate entry, state conflict
422 Unprocessable Entity — Valid JSON but semantically invalid data
429 Too Many Requests — Rate limit exceeded
# Server Errors
500 Internal Server Error — Unexpected failure (never expose internal details)
502 Bad Gateway — Upstream service failed
503 Service Unavailable — Overloaded; include Retry-After header
Common Mistakes
# BAD: 200 for everything
{ "status": 200, "success": false, "error": "Not found" }
# GOOD: semantic HTTP status codes
HTTP/1.1 404 Not Found
{ "error": { "code": "not_found", "message": "User not found" } }
# BAD: 500 for validation errors → GOOD: 400 or 422 with field-level details
# BAD: 200 for created resources → GOOD: 201 with Location header
{"error":{"code":"validation_error","message":"Request validation failed","details":[{"field":"email","message":"Must be a valid email address","code":"invalid_format"},{"field":"age","message":"Must be between 0 and 150","code":"out_of_range"}]}}
Rules:
Always return Content-Type: application/json
Never expose stack traces, SQL errors, or internal service names in error responses
Machine-readable code field enables client-side handling without string matching on message
Pros: Consistent performance at any depth, stable with concurrent inserts
Cons: Cannot jump to arbitrary page; cursor is opaque to clients
When to Use Which
Use Case
Type
Admin dashboards, small datasets (<10K rows)
Offset
Infinite scroll, feeds, large datasets
Cursor
Public APIs (default)
Cursor
Search results (users expect page numbers)
Offset
Filtering, Sorting, and Search
# Simple equality
GET /api/v1/orders?status=active&customer_id=abc-123
# Comparison operators — bracket notation
GET /api/v1/products?price[gte]=10&price[lte]=100
GET /api/v1/orders?created_at[after]=2025-01-01
# Multiple values — comma-separated
GET /api/v1/products?category=electronics,clothing
# Sorting — prefix - for descending, comma-separated for multiple fields
GET /api/v1/products?sort=-created_at
GET /api/v1/products?sort=-featured,price,-created_at
# Full-text search
GET /api/v1/products?q=wireless+headphones
# Sparse fieldsets — reduce payload
GET /api/v1/users?fields=id,name,email
Authentication and Authorization
# Bearer token — always in Authorization header, never in query params
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# API key — server-to-server
X-API-Key: sk_live_abc123
# ⚠️ Never in query string — shows up in logs, browser history, referrer headers
# BAD: GET /api/v1/data?token=sk_live_abc123
// Resource-level: check ownership before returning
app.get("/api/v1/orders/:id", async (req, res) => {
const order = awaitOrder.findById(req.params.id);
if (!order) return res.status(404).json({ error: { code: "not_found" } });
if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });
return res.json({ data: order });
});
// Role-based: guard with middleware
app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
awaitUser.delete(req.params.id);
return res.status(204).send();
});
Idempotency Keys
For non-idempotent POST operations (payments, email sends, order creation), accept an Idempotency-Key header. If the same key is seen again within a TTL window, return the stored response instead of re-executing.
POST /api/v1/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
# On retry with same key → return original response, do not charge twice
Every production API needs at minimum a liveness check:
GET /health → 200 { "status": "ok" } (liveness — is the process up?)
GET /health/ready → 200 { "status": "ok", "db": "ok" } (readiness — can it serve traffic?)
or → 503 { "status": "degraded", "db": "timeout" }
Pros: Explicit, easy to route, cacheable, visible in logs
Cons: URL changes between versions
Header Versioning
GET /api/users
Accept: application/vnd.myapp.v2+json
Pros: Clean URLs. Cons: Easy to forget, harder to test, not visible in logs.
Deprecation Strategy
1. Start with /api/v1/ — don't version until you need a breaking change
2. Maintain at most 2 active versions (current + previous)
3. Deprecation timeline (public APIs):
- Announce deprecation with 6 months notice
- Add: Deprecation: true and Sunset: Sat, 01 Jan 2026 00:00:00 GMT headers
- Return 410 Gone after sunset date
4. Non-breaking changes (no new version needed):
- Adding new fields to responses
- Adding new optional query parameters
- Adding new endpoints
5. Breaking changes (require new version):
- Removing or renaming fields
- Changing field types
- Changing URL structure
- Changing authentication method
Implementation Examples
Read references/implementations.md for complete working route handlers in:
TypeScript (Next.js) — POST handler with JSON parse guard, Zod validation, CORS middleware, idempotency key pattern, cursor pagination
Python (FastAPI) — POST handler with Pydantic, global exception handler, cursor pagination with SQLAlchemy
Go (net/http) — POST handler with error mapping, writeJSON/writeError helpers, health endpoints
API Design Checklist
Before shipping any endpoint:
URL is plural, kebab-case, no verbs — actions use POST
Correct HTTP method (GET for reads, POST for creates, etc.)
Appropriate status code (not 200 for everything; 201 + Location for creates)
Request body JSON parse error returns 400, not 500