API Design
Real scenarios for designing and documenting APIs.
REST API
Goal: Design a REST API for orders.
Command:
Design REST API for orders with list, create, update, cancelWhat happens:
- Defines resource structure
- Creates endpoint specifications
- Generates OpenAPI schema
- Documents request/response formats
Result:
yaml
# openapi.yaml
paths:
/api/orders:
get:
summary: List orders
parameters:
- name: page
in: query
type: integer
- name: status
in: query
type: string
enum: [pending, confirmed, shipped, delivered]
responses:
200:
description: Order list
content:
application/json:
schema:
$ref: '#/components/schemas/OrderList'
post:
summary: Create order
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOrderRequest'
responses:
201:
description: Order created
/api/orders/{id}:
patch:
summary: Update order
delete:
summary: Cancel orderGraphQL Schema
Goal: Design GraphQL schema for products.
Command:
Design GraphQL schema for products with queries and mutationsResult:
graphql
type Product {
id: ID!
name: String!
description: String
price: Float!
category: Category!
images: [String!]!
createdAt: DateTime!
}
type Category {
id: ID!
name: String!
products: [Product!]!
}
type Query {
products(
page: Int = 1
limit: Int = 20
category: ID
search: String
): ProductConnection!
product(id: ID!): Product
}
type Mutation {
createProduct(input: CreateProductInput!): Product!
updateProduct(id: ID!, input: UpdateProductInput!): Product!
deleteProduct(id: ID!): Boolean!
}
input CreateProductInput {
name: String!
description: String
price: Float!
categoryId: ID!
images: [String!]
}Database Modeling
Goal: Design database schema for e-commerce.
Command:
Design database schema for e-commerce with products, orders, usersResult:
sql
-- Users
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- Products
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
description TEXT,
price_cents INTEGER NOT NULL,
category_id UUID REFERENCES categories(id),
inventory INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
-- Orders
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
status VARCHAR(50) DEFAULT 'pending',
total_cents INTEGER NOT NULL,
shipping_address JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Order Items
CREATE TABLE order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id UUID REFERENCES orders(id) ON DELETE CASCADE,
product_id UUID REFERENCES products(id),
quantity INTEGER NOT NULL,
price_cents INTEGER NOT NULL
);
-- Indexes
CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_products_category ON products(category_id);API Versioning
Goal: Add versioning to existing API.
Command:
Add versioning to our API with v1 and v2 supportResult:
API Versioning Strategy
Option 1: URL Path (Recommended)
/api/v1/products
/api/v2/products
Option 2: Header
Accept: application/vnd.api+json; version=2
Implementation:
1. Keep v1 endpoints unchanged
2. Create v2 routes in separate folder
3. v2 can import shared logic from v1
4. Document breaking changes
Folder Structure:
api/
├── v1/
│ ├── products/
│ └── orders/
└── v2/
├── products/ # New response format
└── orders/ # Uses v1 logic
Migration Path:
- Deprecation notice in v1 responses
- 6 month migration period
- Monitor v1 usage before removalError Handling
Goal: Standardize API error responses.
Command:
Design standard error response format for our APIResult:
typescript
// Standard error response
interface APIError {
error: {
code: string // Machine-readable: "VALIDATION_ERROR"
message: string // Human-readable: "Invalid input"
details?: Array<{ // Field-level errors
field: string
message: string
}>
requestId: string // For debugging
}
}
// Examples
// 400 Bad Request
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{ "field": "email", "message": "Invalid email format" },
{ "field": "price", "message": "Must be positive" }
],
"requestId": "req_abc123"
}
}
// 401 Unauthorized
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired token",
"requestId": "req_def456"
}
}
// 404 Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "Product not found",
"requestId": "req_ghi789"
}
}
// 500 Internal Error
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"requestId": "req_jkl012"
}
}Quick Tips
Be Specific About Resources
# Vague
Design an API
# Clear
Design REST API for:
- Users (register, login, profile)
- Products (CRUD, search, categories)
- Orders (create, list, cancel)
- Payments (charge, refund)Include Constraints
Design API with:
- Pagination (cursor-based)
- Rate limiting (100 req/min)
- Filtering by status, date range
- Sorting by created_at, priceRelated Scenarios
- Build Features — Implement the API
- Security — Secure the API
- Database — Design the data layer