A comprehensive, production-ready guide to designing scalable, secure, and developer-friendly APIs. From REST fundamentals to GraphQL, webhooks, async patterns, and enterprise securityβeverything you need to build APIs that teams love.
1. REST API Design (Read Full Guide)
- β URL structure conventions (kebab-case, plural resources)
- β HTTP methods & status codes (comprehensive reference)
- β Response envelopes & error handling
- β Pagination strategies (offset, cursor, keyset)
- β Filtering, sorting & full-text search
- β Authentication & authorization patterns
# Quick example: RESTful resource design
GET /api/v1/users # List all users
POST /api/v1/users # Create new user
GET /api/v1/users/:id # Get specific user
PATCH /api/v1/users/:id # Update user
DELETE /api/v1/users/:id # Delete user
GET /api/v1/users/:id/orders # Get user's orders2. GraphQL APIs (Read Full Guide)
- β Schema design best practices
- β Connection pattern for pagination
- β Error handling in GraphQL
- β Query complexity management
- β N+1 query prevention (DataLoader pattern)
- β Deprecation & versioning
query GetUser {
user(id: "usr_123") {
id
email
name
orders(limit: 10, after: "cursor") {
edges {
node { id title }
cursor
}
pageInfo { hasNextPage }
}
}
}3. Webhook Integration (Read Full Guide)
- β Event design & structure
- β Idempotency & deduplication
- β Signature verification (HMAC-SHA256)
- β Retry logic with exponential backoff
- β Webhook management endpoints
- β Event catalog & versioning
// Secure webhook verification
const signature = req.headers["x-webhook-signature"];
const timestamp = req.headers["x-webhook-timestamp"];
const payload = `${timestamp}.${JSON.stringify(req.body)}`;
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(payload)
.digest("hex");
if (crypto.timingSafeEqual(signature, expected)) {
// Process webhook
}4. Async & Event-Driven APIs (Read Full Guide)
- β Long-running operations with status tracking
- β Server-Sent Events (SSE) for streaming
- β Message queue patterns
- β Job polling & progress updates
- β Eventual consistency handling
// Start async job
POST /api/v1/bulk-import/start
β 202 Accepted { job_id: "job_123", status_url: "/jobs/job_123" }
// Poll for progress
GET /api/v1/bulk-import/job_123
β { status: "processing", progress: 45% }5. Security Patterns (Read Full Guide)
- β OAuth 2.0 & OpenID Connect
- β API Key management
- β JWT best practices
- β mTLS (mutual TLS)
- β Role-based access control (RBAC)
- β Attribute-based access control (ABAC)
- β Row-level security & multi-tenancy
- β Input validation & sanitization
- β Encryption at rest & in transit
- β Secrets management
// Secure authentication + authorization
app.get("/api/v1/orders/:id", authenticate, async (req, res) => {
const order = await Order.findById(req.params.id);
// Ownership check (resource-level authorization)
if (order.customerId !== req.user.id && !req.user.isAdmin) {
return res.status(403).json({ error: "forbidden" });
}
return res.json({ data: order });
});6. Caching & Performance (Read Full Guide)
- β HTTP caching headers (Cache-Control, ETag, Last-Modified)
- β Cache-aside pattern
- β Cache invalidation strategies
- β Stale-while-revalidate
- β Redis implementation patterns
- β CDN integration
// Smart caching with ETag validation
app.get("/api/v1/products/:id", (req, res) => {
const etag = generateETag(product);
if (req.get("If-None-Match") === etag) {
return res.status(304).send(); // Not Modified
}
res.setHeader("Cache-Control", "public, max-age=3600");
res.setHeader("ETag", `"${etag}"`);
res.json({ data: product });
});7. Observability & Monitoring (Read Full Guide)
- β Structured logging
- β Prometheus metrics
- β Distributed tracing
- β Performance monitoring
- β Error tracking & alerting
- β Business metrics
// Structured logging with context
logger.info({
timestamp: new Date().toISOString(),
method: "POST",
endpoint: "/api/v1/orders",
status: 201,
duration_ms: 145,
user_id: "usr_123",
order_id: "ord_456",
amount_usd: 299.99,
});8. Versioning & Deprecation (Read Full Guide)
- β URL path versioning
- β Header-based versioning
- β Deprecation timelines
- β Migration guides
- β Sunset headers
// Proper deprecation handling
app.get("/api/v1/users", (req, res) => {
res.setHeader("Sunset", "Sat, 01 Jan 2026 00:00:00 GMT");
res.setHeader("Deprecation", "true");
res.setHeader(
"Link",
'</api/v2/users>; rel="successor-version"'
);
// Response...
});# Clone the repository
git clone https://github.com/yourusername/api-design-guide.git
cd api-design-guide
# Read the main guide
cat GUIDE.md
# Check out specific domains
cat docs/rest-api-design.md
cat docs/security.md
cat docs/webhooks.md# Copy the checklist to your project
cp templates/api-design-checklist.md ./API-CHECKLIST.md
# Use the OpenAPI template
cp templates/openapi-template.yaml ./openapi.yaml
# Implement security patterns
cp patterns/security-patterns.ts ./src/middleware/# TypeScript/Express example
cat examples/typescript-express/api-server.ts
# Python/FastAPI example
cat examples/python-fastapi/main.py
# Go/Gin example
cat examples/go-gin/main.goapi-design-guide/
βββ README.md # This file
βββ GUIDE.md # Complete comprehensive guide
β
βββ docs/ # Topic-specific guides
β βββ rest-api-design.md
β βββ graphql-design.md
β βββ webhooks.md
β βββ async-apis.md
β βββ security.md
β βββ caching.md
β βββ observability.md
β βββ versioning.md
β βββ error-handling.md
β
βββ templates/ # Ready-to-use templates
β βββ api-design-checklist.md
β βββ openapi-template.yaml
β βββ error-response-schema.json
β βββ webhook-event-template.json
β βββ security-headers-config.ts
β
βββ patterns/ # Code patterns & snippets
β βββ authentication/
β β βββ jwt-auth.ts
β β βββ oauth2-flow.ts
β β βββ api-key-auth.ts
β βββ security/
β β βββ rate-limiting.ts
β β βββ input-validation.ts
β β βββ encryption.ts
β βββ caching/
β β βββ redis-cache.ts
β β βββ http-caching.ts
β βββ pagination/
β βββ offset-pagination.ts
β βββ cursor-pagination.ts
β βββ keyset-pagination.ts
β
βββ examples/ # Full working examples
β βββ typescript-express/
β β βββ package.json
β β βββ main.ts
β β βββ routes/
β β βββ middleware/
β β βββ schemas/
β βββ python-fastapi/
β β βββ requirements.txt
β β βββ main.py
β β βββ models/
β β βββ routes/
β βββ go-gin/
β βββ go.mod
β βββ main.go
β βββ handlers/
β βββ models/
β
βββ tools/ # Utilities & testing
β βββ api-validator.js
β βββ webhook-simulator.js
β βββ load-test.js
β βββ security-scanner.js
β
βββ checklists/ # Before-launch checklists
β βββ design-checklist.md
β βββ security-checklist.md
β βββ testing-checklist.md
β βββ deployment-checklist.md
β
βββ CONTRIBUTING.md # How to contribute
- Resource naming conventions
- HTTP methods & semantics
- Status codes reference (2xx, 3xx, 4xx, 5xx)
- Request/response envelopes
- Error handling & error codes
- Pagination strategies
- Filtering & sorting
- Full-text search
- Rate limiting
- Versioning strategies
- Schema design
- Query optimization
- Connection patterns
- Error handling
- Deprecation
- Complexity management
- DataLoader for N+1 prevention
- Event design
- Idempotency & deduplication
- Signature verification
- Retry strategies
- Event catalog
- Dead letter queues
- OAuth 2.0 / OpenID Connect
- API Keys
- JWT (JSON Web Tokens)
- mTLS (Mutual TLS)
- RBAC (Role-Based Access Control)
- ABAC (Attribute-Based Access Control)
- Row-level security
- Input validation & sanitization
- Encryption (at rest & in transit)
- Secrets management
- CORS configuration
- OWASP Top 10 for APIs
- HTTP caching headers
- ETag & Last-Modified
- Cache-Control directives
- Application-level caching
- Redis patterns
- Cache invalidation
- Stale-while-revalidate
- Structured logging
- Metrics & monitoring
- Distributed tracing
- Error tracking
- Performance monitoring
- Business metrics
import express, { Router } from "express";
import { z } from "zod";
const router = Router();
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
router.post("/users", async (req, res) => {
const result = createUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(422).json({
error: {
code: "validation_error",
message: "Validation failed",
details: result.error.issues,
},
});
}
const user = await createUser(result.data);
return res.status(201)
.setHeader("Location", `/api/v1/users/${user.id}`)
.json({ data: user });
});
export default router;from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr
app = FastAPI()
class CreateUserRequest(BaseModel):
email: EmailStr
name: str
@app.post("/users", status_code=201)
async def create_user(request: CreateUserRequest):
user = await UserService.create(request.dict())
return {"data": user}func CreateUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
user, _ := userService.Create(req)
c.Header("Location", "/api/v1/users/"+user.ID)
c.JSON(201, gin.H{"data": user})
}Before deploying any API:
- HTTPS/TLS enabled (HSTS header set)
- Authentication implemented
- Authorization checks in place
- Input validation & sanitization
- Rate limiting configured
- CORS configured appropriately
- Secrets managed securely (not in code)
- SQL injection prevention (parameterized queries)
- XSS prevention (output encoding)
- CSRF protection
- Sensitive data not in logs
- Error messages don't leak implementation details
- Request/response size limits
- Dependency vulnerabilities scanned
- API key rotation mechanism
- Audit logging enabled
- Monitoring & alerting in place
β
Use pagination (cursor-based for scalability)
β
Implement caching (HTTP & app-level)
β
Use sparse fieldsets to reduce payloads
β
Compress responses (gzip, brotli)
β
Index frequently filtered/sorted fields
β
Use database query limits
β
Monitor slow queries
β
Load test before production
π Response time (p50, p95, p99)
π Error rate
π Cache hit rate
π Database query time
π Payload size
π Concurrent connections
π Rate limit violations
π Business metrics (orders/min, revenue/hour, etc.)
β
Schema validation (happy path + error cases)
β
Business logic
β
Authorization checks
β
End-to-end API flow
β
Error cases (4xx, 5xx responses)
β
Rate limiting
β
Pagination
β
Filtering & sorting
β
Concurrent requests
β
Authentication bypass attempts
β
Authorization bypasses
β
SQL injection
β
XSS attacks
β
Rate limit evasion
β
Large payload handling
β
Concurrent users (1K, 10K, 100K)
β
Sustained load (24 hours)
β
Spike handling
β
Memory leaks
We welcome contributions! Here's how:
-
Fork the repository
git clone https://github.com/yourusername/api-design-guide.git
-
Create a branch
git checkout -b feature/add-websocket-patterns
-
Make your changes
- Add patterns, examples, or improvements
- Follow the existing structure
- Add comprehensive documentation
-
Submit a pull request
- Reference any related issues
- Describe your changes
- Include examples if applicable
- Add more language examples (Rust, Java, C#)
- Add more real-world case studies
- Expand security patterns
- Add monitoring/observability examples
- Improve documentation
- Fix typos/improve clarity
- Add diagrams & visualizations
- REST (Representational State Transfer)
- HTTP Specification (RFC 7231)
- OpenAPI / Swagger
- GraphQL Specification
- JSON:API
- OAuth 2.0
- "REST API Design Rulebook" by Mark Masse
- "Building Microservices" by Sam Newman
- "API Security in Action" by Neil Madden
- "Designing Data-Intensive Applications" by Martin Kleppmann
This guide is licensed under the MIT License. You're free to use it for any purpose, commercial or personal. See LICENSE for details.
- Questions? Open an issue
- Want to discuss? Use GitHub Discussions
- Found a bug? File a bug report
This guide is built on years of API design experience and best practices from:
- IETF specifications (HTTP, OAuth, etc.)
- OWASP security guidelines
- Industry standards (GraphQL, REST Maturity Model)
- Real-world implementations at scale
- Community contributions & feedback
- Last Updated: January 15, 2025
- Topics Covered: 8 major categories
- Code Examples: 50+
- Patterns & Templates: 40+
- Contributors: Open to all
- Stars: β Please consider starring if this helps you!
Made for developers, by developers.