- API Designer
- Design robust, scalable, and developer-friendly APIs.
- Core Principles
- 1. Developer Experience First
- Clear, predictable naming conventions
- Comprehensive documentation
- Helpful error messages
- Consistent patterns across endpoints
- 2. Design for Evolution
- Versioning strategy from day one
- Backward compatibility
- Deprecation process
- Migration guides for breaking changes
- 3. Security by Default
- Authentication and authorization
- Rate limiting and throttling
- Input validation and sanitization
- HTTPS only, no exceptions
- 4. Performance Matters
- Efficient queries and indexing
- Caching strategies
- Pagination for large datasets
- Compression (gzip, brotli)
- REST API Design
- Resource Naming Conventions
- ✅ Good (Nouns, plural, hierarchical):
- GET /users # List all users
- GET /users/123 # Get specific user
- POST /users # Create user
- PUT /users/123 # Replace user
- PATCH /users/123 # Update user
- DELETE /users/123 # Delete user
- GET /users/123/posts # User's posts (nested)
- GET /users/123/posts/456 # Specific post
- ❌ Bad (Verbs, inconsistent, unclear):
- GET /getUsers
- POST /createUser
- GET /user-list
- GET /UserData?id=123
- HTTP Methods & Semantics
- Method
- Purpose
- Idempotent
- Safe
- Request Body
- Response Body
- GET
- Retrieve data
- Yes
- Yes
- No
- Yes
- POST
- Create resource
- No
- No
- Yes
- Yes (created)
- PUT
- Replace resource
- Yes
- No
- Yes
- Yes (optional)
- PATCH
- Partial update
- No
- No
- Yes
- Yes (optional)
- DELETE
- Remove resource
- Yes
- No
- No
- No (204) or Yes
- Idempotent
-
- Multiple identical requests have same effect as single request
- Safe
- Request doesn't modify server state HTTP Status Codes Success (2xx) : 200 OK - Successful GET, PUT, PATCH, DELETE 201 Created - Successful POST, includes Location header 204 No Content - Successful request, no response body (often DELETE) Client Errors (4xx) : 400 Bad Request - Invalid syntax, validation error 401 Unauthorized - Authentication required or failed 403 Forbidden - Authenticated but lacks permission 404 Not Found - Resource doesn't exist 409 Conflict - Request conflicts with current state 422 Unprocessable Entity - Validation error (semantic) 429 Too Many Requests - Rate limit exceeded Server Errors (5xx) : 500 Internal Server Error - Generic server error 502 Bad Gateway - Upstream service error 503 Service Unavailable - Temporary unavailability 504 Gateway Timeout - Upstream timeout Response Format Standards Success Response : { "data" : { "id" : "123" , "type" : "user" , "attributes" : { "name" : "John Doe" , "email" : "john@example.com" , "created_at" : "2025-01-15T10:30:00Z" } } } Error Response : { "error" : { "code" : "VALIDATION_ERROR" , "message" : "Request validation failed" , "details" : [ { "field" : "email" , "code" : "REQUIRED" , "message" : "Email is required" } , { "field" : "age" , "code" : "OUT_OF_RANGE" , "message" : "Age must be between 18 and 120" } ] , "request_id" : "req_abc123" , "documentation_url" : "https://api.example.com/docs/errors/validation" } } List Response with Pagination : { "data" : [ ... ] , "pagination" : { "cursor" : "eyJpZCI6MTIzfQ==" , "has_more" : true , "total_count" : 1000 } , "links" : { "next" : "/users?cursor=eyJpZCI6MTIzfQ==&limit=20" , "prev" : "/users?cursor=eyJpZCI6MTAwfQ==&limit=20" } } Pagination Strategies Cursor-based (Recommended) : GET /users?cursor=abc123&limit=20 Pros: Consistent results, efficient, handles real-time data Cons: Can't jump to arbitrary page Use when: Large datasets, real-time data, performance critical Offset-based : GET /users?page=1&per_page=20 GET /users?offset=0&limit=20 Pros: Simple, can jump to any page Cons: Inconsistent with concurrent writes, inefficient at scale Use when: Small datasets, admin interfaces, simple use cases Filtering, Sorting, and Search Filtering : GET /users?status=active&role=admin&created_after=2025-01-01 Sorting : GET /users?sort=-created_at,name # Descending created_at, then ascending name Search : GET /users?q=john&fields=name,email # Search across specified fields Authentication & Authorization JWT Bearer Token (Recommended for SPAs) : Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... Pros: Stateless, includes user claims, works across domains Cons: Can't revoke until expiry, larger payload API Keys (for service-to-service) : X-API-Key: sk_live_abc123... Pros: Simple, easy to rotate, per-service keys Cons: No user context, must be kept secret OAuth 2.0 (for third-party access) : Authorization: Bearer access_token Pros: Delegated auth, scoped permissions, industry standard Cons: Complex setup, requires OAuth server Basic Auth (only for internal/admin tools) : Authorization: Basic base64(username:password) Pros: Simple, built-in to HTTP Cons: Credentials in every request, must use HTTPS Rate Limiting Standard Headers : X-RateLimit-Limit: 1000 # Max requests per window X-RateLimit-Remaining: 999 # Requests left X-RateLimit-Reset: 1640995200 # Unix timestamp when limit resets Retry-After: 60 # Seconds to wait (on 429) Common Strategies : Fixed window: 1000 requests per hour Sliding window: 1000 requests per rolling hour Token bucket: Burst allowance with refill rate Per-user, per-IP, or per-API-key limits Versioning Strategies URL Versioning (Recommended) : /v1/users /v2/users Pros: Explicit, easy to route, clear in logs Cons: URL pollution, harder to evolve incrementally Header Versioning : Accept: application/vnd.myapp.v2+json API-Version: 2 Pros: Clean URLs, follows REST principles Cons: Less visible, harder to test in browser Best Practices : Start with v1, not v0 Only increment for breaking changes Support N and N-1 versions simultaneously Provide migration guides Announce deprecation 6-12 months ahead GraphQL API Design Schema Design type User { id : ID ! name : String ! email : String ! posts ( first : Int , after : String ) : PostConnection ! createdAt : DateTime ! } type PostConnection { edges : [ PostEdge ! ] ! pageInfo : PageInfo ! } type PostEdge { node : Post ! cursor : String ! } type PageInfo { hasNextPage : Boolean ! endCursor : String } type Query { user ( id : ID ! ) : User users ( first : Int , after : String ) : UserConnection ! } type Mutation { createUser ( input : CreateUserInput ! ) : CreateUserPayload ! updateUser ( id : ID ! , input : UpdateUserInput ! ) : UpdateUserPayload ! } input CreateUserInput { name : String ! email : String ! } type CreateUserPayload { user : User errors : [ Error ! ] } GraphQL Best Practices 1. Use Relay Connection Pattern for Pagination : query { users ( first : 10 , after : "cursor" ) { edges { node { id name } cursor } pageInfo { hasNextPage endCursor } } } 2. Input Types for Mutations :
✅ Good: Input type + payload
mutation { createUser ( input : { name : "John" , email : "john@example.com" } ) { user { id name } errors { field message } } }
❌ Bad: Flat arguments
mutation { createUser ( name : "John" , email : "john@example.com" ) { id name } } 3. Error Handling : type Mutation { createUser ( input : CreateUserInput ! ) : CreateUserPayload ! } type CreateUserPayload { user : User
Null if errors
errors : [ Error ! ]
Field-level errors
} type Error { field : String ! code : String ! message : String ! } REST vs GraphQL Decision Use REST when : Simple CRUD operations Caching is critical (HTTP caching) Public API for third-parties File uploads/downloads Team unfamiliar with GraphQL Use GraphQL when : Clients need flexible queries Reducing over-fetching/under-fetching Rapid frontend iteration Complex nested data relationships Strong typing and schema benefits API Documentation OpenAPI/Swagger Specification openapi : 3.0.0 info : title : User Management API version : 1.0.0 description : API for managing users and posts servers : - url : https : //api.example.com/v1 paths : /users : get : summary : List users parameters : - name : page in : query schema : type : integer default : 1 - name : per_page in : query schema : type : integer default : 20 maximum : 100 responses : '200' : description : Success content : application/json : schema : $ref : '#/components/schemas/UserList' '401' : $ref : '#/components/responses/Unauthorized' post : summary : Create user requestBody : required : true content : application/json : schema : $ref : '#/components/schemas/CreateUserInput' responses : '201' : description : User created content : application/json : schema : $ref : '#/components/schemas/User' components : schemas : User : type : object properties : id : type : string name : type : string email : type : string format : email securitySchemes : bearerAuth : type : http scheme : bearer bearerFormat : JWT Documentation Best Practices ✅ Include request/response examples ✅ Document all error codes ✅ Provide authentication guides ✅ Interactive API playground (Swagger UI, GraphQL Playground) ✅ Code examples in multiple languages ✅ Rate limit information ✅ Changelog for API updates Security Checklist HTTPS only (redirect HTTP → HTTPS) Authentication required for protected endpoints Authorization checks (user can only access own data) Input validation (schema validation, sanitization) Rate limiting per user/IP CORS configuration (whitelist origins) SQL injection prevention (parameterized queries) No sensitive data in URLs (use headers/body) Audit logging for sensitive operations API keys rotatable and revocable Related Resources