API Design Best Practices: REST vs GraphQL vs gRPC in 2025
APIs are the backbone of modern applications. Learn how to design robust, scalable, and developer-friendly APIs using REST, GraphQL, or gRPC with authentication, versioning, and documentation best practices.
API Design Principles
1. Consistency
Use consistent naming conventions, response formats, and error handling across all endpoints.
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Goodspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Consistentspan> plural nounsspan>2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users3<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/products4<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/orders5 6<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Badspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Inconsistentspan> namingspan>7<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/user8<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/getProducts9<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/order-list2. Simplicity
Keep endpoints intuitive and URLs clean.
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Goodspan>span>2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users/<span class="text-orange-400">123span>/orders3 4<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Badspan>span>5<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/getUserOrdersById?userId=<span class="text-orange-400">123span>3. Stateless
Each request should contain all necessary information. Don't rely on server-side sessions.
4. Versioning
Always version your API from day one.
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">URLspan> <span class="text-blue-400">versioningspan>(recommended)span>2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/v1/users3<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/v2/users4 5<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Headerspan> versioningspan>6<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users7<span class="text-yellow-<span class="text-orange-400">300span>">Headerspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Acceptspan>: application/vnd.myapi.v2+json5. Documentation
Comprehensive, up-to-date documentation is non-negotiable. Use OpenAPI (Swagger), Postman collections, or GraphQL introspection.
REST API Design
HTTP Methods
- **GET**: Retrieve resources (idempotent, cacheable)
- **POST**: Create new resources
- **PUT**: Replace entire resource (idempotent)
- **PATCH**: Partial update
- **DELETE**: Remove resource (idempotent)
RESTful Resource Naming
1# <span class="text-yellow-<span class="text-orange-400">300span>">Collectionsspan>2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users # <span class="text-yellow-<span class="text-orange-400">300span>">Listspan> all users3<span class="text-yellow-<span class="text-orange-400">300span>">POSTspan> /api/users # <span class="text-yellow-<span class="text-orange-400">300span>">Createspan> user4 5# <span class="text-yellow-<span class="text-orange-400">300span>">Individualspan> resources6<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users/<span class="text-orange-400">123span> # <span class="text-yellow-<span class="text-orange-400">300span>">Getspan> user7<span class="text-yellow-<span class="text-orange-400">300span>">PUTspan> /api/users/<span class="text-orange-400">123span> # <span class="text-yellow-<span class="text-orange-400">300span>">Replacespan> user8<span class="text-yellow-<span class="text-orange-400">300span>">PATCHspan> /api/users/<span class="text-orange-400">123span> # <span class="text-yellow-<span class="text-orange-400">300span>">Updatespan> user9<span class="text-yellow-<span class="text-orange-400">300span>">DELETEspan> /api/users/<span class="text-orange-400">123span> # <span class="text-yellow-<span class="text-orange-400">300span>">Deletespan> user10 11# <span class="text-yellow-<span class="text-orange-400">300span>">Nestedspan> resources12<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users/<span class="text-orange-400">123span>/orders # <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>'s orders13<span class="text-yellow-<span class="text-orange-400">300span>">POSTspan> /api/users/<span class="text-orange-400">123span>/orders # <span class="text-yellow-<span class="text-orange-400">300span>">Createspan> order <span class="text-purple-<span class="text-orange-400">400span> font-semibold">forspan> userResponse Structure
Consistent response format:
1{2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"success"span>: true,3 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"data"span>: {4 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"id"span>: <span class="text-orange-400">123span>,5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"name"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Johnspan> <span class="text-yellow-<span class="text-orange-400">300span>">Doespan>"span>,6 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"email"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"john@example.com"span>7 },8 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"meta"span>: {9 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"timestamp"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-orange-400">2025span>-<span class="text-orange-400">01span>-15T10:<span class="text-orange-400">30span>:00Z"span>,10 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"version"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-orange-400">1span>.<span class="text-orange-400">0span>"span>11 }12}Error Handling
Use appropriate HTTP status codes:
1{2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"success"span>: false,3 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"error"span>: {4 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"code"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"VALIDATION_ERROR"span>,5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"message"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Invalidspan> email format"span>,6 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"details"span>: {7 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"field"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"email"span>,8 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"value"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"invalid-email"span>9 }10 },11 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"meta"span>: {12 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"timestamp"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-orange-400">2025span>-<span class="text-orange-400">01span>-15T10:<span class="text-orange-400">30span>:00Z"span>,13 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"requestId"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"abc-<span class="text-orange-400">123span>-def"span>14 }15}- 200 OK: Success
- 201 Created: Resource created
- 204 No Content: Success with no body
- 400 Bad Request: Invalid input
- 401 Unauthorized: Authentication required
- 403 Forbidden: Authenticated but no permission
- 404 Not Found: Resource doesn't exist
- 422 Unprocessable Entity: Validation failed
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server error
- 503 Service Unavailable: Temporary outage
Pagination
1# <span class="text-yellow-<span class="text-orange-400">300span>">Offsetspan>-based2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users?page=<span class="text-orange-400">2span>&limit=<span class="text-orange-400">20span>3 4# <span class="text-yellow-<span class="text-orange-400">300span>">Cursorspan>-<span class="text-blue-400">basedspan>(better <span class="text-purple-<span class="text-orange-400">400span> font-semibold">forspan> large datasets)5<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users?cursor=abc123&limit=<span class="text-orange-400">20span>Response:
1{2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"data"span>: [...],3 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"pagination"span>: {4 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"total"span>: <span class="text-orange-400">1000span>,5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"page"span>: <span class="text-orange-400">2span>,6 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"limit"span>: <span class="text-orange-400">20span>,7 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"totalPages"span>: <span class="text-orange-400">50span>,8 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"nextCursor"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"xyz789"span>9 }10}Filtering and Sorting
1# <span class="text-yellow-<span class="text-orange-400">300span>">Filteringspan>2<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/products?category=electronics&minPrice=<span class="text-orange-400">100span>3 4# <span class="text-yellow-<span class="text-orange-400">300span>">Sortingspan>5<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/products?sort=-price,name # -<span class="text-blue-400">pricespan>(desc), <span class="text-blue-400">namespan>(asc)6 7# <span class="text-yellow-<span class="text-orange-400">300span>">Fieldspan> selection8<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users?fields=id,name,emailRate Limiting
Include rate limit headers:
1<span class="text-yellow-<span class="text-orange-400">300span>">Xspan>-<span class="text-yellow-<span class="text-orange-400">300span>">RateLimitspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Limitspan>: <span class="text-orange-400">1000span>2<span class="text-yellow-<span class="text-orange-400">300span>">Xspan>-<span class="text-yellow-<span class="text-orange-400">300span>">RateLimitspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Remainingspan>: <span class="text-orange-400">950span>3<span class="text-yellow-<span class="text-orange-400">300span>">Xspan>-<span class="text-yellow-<span class="text-orange-400">300span>">RateLimitspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Resetspan>: <span class="text-orange-400">1642252800span>HATEOAS (Hypermedia)
Include links to related resources:
1{2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"id"span>: <span class="text-orange-400">123span>,3 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"name"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Productspan>"span>,4 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"links"span>: {5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"self"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/api/products/<span class="text-orange-400">123span>"span>,6 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"reviews"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/api/products/<span class="text-orange-400">123span>/reviews"span>,7 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"related"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"/api/products?category=electronics"span>8 }9}GraphQL API Design
Schema Design
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">Userspan> {2 id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!3 name: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>!4 email: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>!5 posts: [<span class="text-yellow-<span class="text-orange-400">300span>">Postspan>!]!6 createdAt: <span class="text-yellow-<span class="text-orange-400">300span>">DateTimespan>!7}8 9<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">Postspan> {10 id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!11 title: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>!12 content: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>!13 author: <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>!14 comments: [<span class="text-yellow-<span class="text-orange-400">300span>">Commentspan>!]!15}16 17<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">Queryspan> {18 <span class="text-blue-400">userspan>(id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>19 <span class="text-blue-400">usersspan>(first: <span class="text-yellow-<span class="text-orange-400">300span>">Intspan>, after: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>): <span class="text-yellow-<span class="text-orange-400">300span>">UserConnectionspan>!20 <span class="text-blue-400">postspan>(id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Postspan>21 <span class="text-blue-400">postsspan>(filter: <span class="text-yellow-<span class="text-orange-400">300span>">PostFilterspan>): [<span class="text-yellow-<span class="text-orange-400">300span>">Postspan>!]!22}23 24<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">Mutationspan> {25 <span class="text-blue-400">createUserspan>(input: <span class="text-yellow-<span class="text-orange-400">300span>">CreateUserInputspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>!26 <span class="text-blue-400">updateUserspan>(id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!, input: <span class="text-yellow-<span class="text-orange-400">300span>">UpdateUserInputspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>!27 <span class="text-blue-400">deleteUserspan>(id: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Booleanspan>!28}29 30<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">Subscriptionspan> {31 postAdded: <span class="text-yellow-<span class="text-orange-400">300span>">Postspan>!32 <span class="text-blue-400">commentAddedspan>(postId: <span class="text-yellow-<span class="text-orange-400">300span>">IDspan>!): <span class="text-yellow-<span class="text-orange-400">300span>">Commentspan>!33}Advantages of GraphQL
- 1No Over-fetching: Request exactly what you need
- 2No Under-fetching: Get related data in one request
- 3Strong Typing: Schema provides type safety
- 4Introspection: Self-documenting
- 5Real-time: Subscriptions for live updates
Query Example
1query {2 <span class="text-blue-400">userspan>(id: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-orange-400">123span>"span>) {3 name4 email5 <span class="text-blue-400">postsspan>(first: <span class="text-orange-400">5span>) {6 title7 comments {8 content9 author {10 name11 }12 }13 }14 }15}Mutation Example
1mutation {2 <span class="text-blue-400">createPostspan>(input: {3 title: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">GraphQLspan> is awesome"span>4 content: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Herespan>'s why..."span>5 }) {6 id7 title8 author {9 name10 }11 }12}GraphQL Best Practices
- 1Pagination: Use connection pattern
1<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">UserConnectionspan> {2 edges: [<span class="text-yellow-<span class="text-orange-400">300span>">UserEdgespan>!]!3 pageInfo: <span class="text-yellow-<span class="text-orange-400">300span>">PageInfospan>!4}5 6<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">UserEdgespan> {7 node: <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>!8 cursor: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>!9}10 11<span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan> <span class="text-yellow-<span class="text-orange-400">300span>">PageInfospan> {12 hasNextPage: <span class="text-yellow-<span class="text-orange-400">300span>">Booleanspan>!13 endCursor: <span class="text-yellow-<span class="text-orange-400">300span>">Stringspan>14}- 1Error Handling: Use errors array
1{2 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"data"span>: {3 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"user"span>: null4 },5 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"errors"span>: [6 {7 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"message"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"<span class="text-yellow-<span class="text-orange-400">300span>">Userspan> not found"span>,8 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"path"span>: [<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"user"span>],9 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"extensions"span>: {10 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"code"span>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"NOT_FOUND"span>11 }12 }13 ]14}- 1Batching: Use DataLoader to prevent N+1 queries
- 2Depth Limiting: Prevent deeply nested queries
- 3Query Complexity: Assign costs to fields
When to Use GraphQL
- Mobile apps (minimize over-fetching)
- Complex data requirements
- Rapid frontend iteration
- Multiple clients with different needs
- Simple CRUD APIs
- File uploads (use REST)
- Caching (more complex than REST)
- Small teams (learning curve)
gRPC API Design
Protocol Buffers
1syntax = <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"proto3"span>;2 3message <span class="text-yellow-<span class="text-orange-400">300span>">Userspan> {4 int32 id = <span class="text-orange-400">1span>;5 string name = <span class="text-orange-400">2span>;6 string email = <span class="text-orange-400">3span>;7 repeated string roles = <span class="text-orange-400">4span>;8}9 10message <span class="text-yellow-<span class="text-orange-400">300span>">GetUserRequestspan> {11 int32 id = <span class="text-orange-400">1span>;12}13 14message <span class="text-yellow-<span class="text-orange-400">300span>">CreateUserRequestspan> {15 string name = <span class="text-orange-400">1span>;16 string email = <span class="text-orange-400">2span>;17}18 19service <span class="text-yellow-<span class="text-orange-400">300span>">UserServicespan> {20 rpc <span class="text-yellow-<span class="text-orange-400">300span>">GetUserspan>(<span class="text-yellow-<span class="text-orange-400">300span>">GetUserRequestspan>) <span class="text-blue-400">returnsspan>(<span class="text-yellow-<span class="text-orange-400">300span>">Userspan>);21 rpc <span class="text-yellow-<span class="text-orange-400">300span>">ListUsersspan>(<span class="text-yellow-<span class="text-orange-400">300span>">Emptyspan>) <span class="text-blue-400">returnsspan>(stream <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>);22 rpc <span class="text-yellow-<span class="text-orange-400">300span>">CreateUserspan>(<span class="text-yellow-<span class="text-orange-400">300span>">CreateUserRequestspan>) <span class="text-blue-400">returnsspan>(<span class="text-yellow-<span class="text-orange-400">300span>">Userspan>);23 rpc <span class="text-yellow-<span class="text-orange-400">300span>">DeleteUserspan>(<span class="text-yellow-<span class="text-orange-400">300span>">GetUserRequestspan>) <span class="text-blue-400">returnsspan>(<span class="text-yellow-<span class="text-orange-400">300span>">Emptyspan>);24}Advantages of gRPC
- 1Performance: Binary protocol, 7x faster than REST
- 2Strongly Typed: Protocol Buffers
- 3Streaming: Bidirectional streaming support
- 4Code Generation: Auto-generate clients
- 5HTTP/2: Multiplexing, server push
gRPC Communication Patterns
Unary RPC: Single request, single response (like REST) Server Streaming: Single request, stream of responses Client Streaming: Stream of requests, single response Bidirectional Streaming: Both sides stream
When to Use gRPC
- Microservices communication
- Real-time applications
- High-performance requirements
- Internal APIs
- Mobile apps (with gRPC-Web)
- Public APIs (browser support limited)
- Simple REST-like operations
- When human readability matters
Authentication & Authorization
JWT (JSON Web Tokens)
1<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Generatespan> <span class="text-yellow-<span class="text-orange-400">300span>">JWTspan>span>2<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> token = jwt.<span class="text-blue-400">signspan>(3 { userId: <span class="text-orange-400">123span>, role: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'admin'span> },4 process.env.JWT_SECRET,5 { expiresIn: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'1h'span> }6);7 8<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Verifyspan> <span class="text-yellow-<span class="text-orange-400">300span>">JWTspan>span>9<span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> decoded = jwt.<span class="text-blue-400">verifyspan>(token, process.env.JWT_SECRET);Request:
1<span class="text-yellow-<span class="text-orange-400">300span>">Authorizationspan>: <span class="text-yellow-<span class="text-orange-400">300span>">Bearerspan> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...OAuth 2.0
- **Authorization Code Flow**: Web apps
- **PKCE**: Mobile/SPA apps
- **Client Credentials**: Service-to-service
- **Password Grant**: Legacy (not recommended)
API Keys
Simple but less secure:
1<span class="text-yellow-<span class="text-orange-400">300span>">Xspan>-<span class="text-yellow-<span class="text-orange-400">300span>">APIspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Keyspan>: abc123def456- Rotate keys regularly
- Rate limit per key
- Scope permissions
- Never commit to Git
API Documentation
OpenAPI (Swagger)
1openapi: <span class="text-orange-400">3span>.<span class="text-orange-400">0span>.<span class="text-orange-400">0span>2info:3 title: <span class="text-yellow-<span class="text-orange-400">300span>">Userspan> <span class="text-yellow-<span class="text-orange-400">300span>">APIspan>4 version: <span class="text-orange-400">1span>.<span class="text-orange-400">0span>.<span class="text-orange-400">0span>5paths:6 /users:7 get:8 summary: <span class="text-yellow-<span class="text-orange-400">300span>">Listspan> users9 parameters:10 - name: page11 in: query12 schema:13 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan>: integer14 responses:15 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-orange-400">200span>'span>:16 description: <span class="text-yellow-<span class="text-orange-400">300span>">Successspan>17 content:18 application/json:19 schema:20 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan>: array21 items:22 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">typespan>: <span class="text-yellow-<span class="text-orange-400">300span>">Userspan>Generate interactive docs with Swagger UI.
Postman Collections
Share API collections with examples and tests.
API Changelog
Document breaking changes:
1## v2.<span class="text-orange-400">0span>.<span class="text-orange-400">0span> (<span class="text-orange-400">2025span>-<span class="text-orange-400">01span>-<span class="text-orange-400">15span>)2<span class="text-yellow-<span class="text-orange-400">300span>">BREAKINGspan> <span class="text-yellow-<span class="text-orange-400">300span>">CHANGESspan>:3- <span class="text-yellow-<span class="text-orange-400">300span>">Renamedspan> user.username to user.email4- <span class="text-yellow-<span class="text-orange-400">300span>">Removedspan> /api/legacy endpoint5 6<span class="text-yellow-<span class="text-orange-400">300span>">NEWspan> <span class="text-yellow-<span class="text-orange-400">300span>">FEATURESspan>:7- <span class="text-yellow-<span class="text-orange-400">300span>">Addedspan> pagination to /api/users8- <span class="text-yellow-<span class="text-orange-400">300span>">Newspan> endpoint: /api/users/searchPerformance Optimization
Caching
1<span class="text-yellow-<span class="text-orange-400">300span>">Cachespan>-<span class="text-yellow-<span class="text-orange-400">300span>">Controlspan>: public, max-age=<span class="text-orange-400">3600span>2<span class="text-yellow-<span class="text-orange-400">300span>">ETagspan>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"33a64df551425fcc55e4d42a148795d9f25f89d4"span>Conditional requests:
1<span class="text-yellow-<span class="text-orange-400">300span>">Ifspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Nonespan>-<span class="text-yellow-<span class="text-orange-400">300span>">Matchspan>: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"33a64df551425fcc55e4d42a148795d9f25f89d4"span>Response: 304 Not Modified (no body, save bandwidth)
Compression
Enable gzip/brotli compression:
1<span class="text-yellow-<span class="text-orange-400">300span>">Contentspan>-<span class="text-yellow-<span class="text-orange-400">300span>">Encodingspan>: gzipReduces payload size by 70-90%.
CDN
Use CDN for static API responses (e.g., reference data).
Testing APIs
Unit Tests
1<span class="text-blue-400">describespan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">GETspan> /api/users/:id'span>, () => {2 <span class="text-blue-400">itspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'should <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> user'span>, <span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan> () => {3 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> res = <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">requestspan>(app)4 .<span class="text-blue-400">getspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'/api/users/<span class="text-orange-400">123span>'span>)5 .<span class="text-blue-400">expectspan>(<span class="text-orange-400">200span>);6 7 <span class="text-blue-400">expectspan>(res.body.data.id).<span class="text-blue-400">toBespan>(<span class="text-orange-400">123span>);8 });9 10 <span class="text-blue-400">itspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'should <span class="text-purple-<span class="text-orange-400">400span> font-semibold">returnspan> <span class="text-orange-400">404span> <span class="text-purple-<span class="text-orange-400">400span> font-semibold">forspan> non-existent user'span>, <span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan> () => {11 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">requestspan>(app)12 .<span class="text-blue-400">getspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'/api/users/<span class="text-orange-400">999span>'span>)13 .<span class="text-blue-400">expectspan>(<span class="text-orange-400">404span>);14 });15});Integration Tests
Test with real database:
1<span class="text-blue-400">beforeAllspan>(<span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan> () => {2 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">setupTestDatabasespan>();3});4 5<span class="text-blue-400">afterAllspan>(<span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan> () => {6 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">teardownTestDatabasespan>();7});8 9<span class="text-blue-400">testspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">Createspan> and retrieve user'span>, <span class="text-purple-<span class="text-orange-400">400span> font-semibold">asyncspan> () => {10 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Createspan>span>11 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> createRes = <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">requestspan>(app)12 .<span class="text-blue-400">postspan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'/api/users'span>)13 .<span class="text-blue-400">sendspan>({ name: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">Testspan>'span>, email: <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'test@example.com'span> })14 .<span class="text-blue-400">expectspan>(<span class="text-orange-400">201span>);15 16 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> userId = createRes.body.data.id;17 18 <span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>// <span class="text-yellow-<span class="text-orange-400">300span>">Retrievespan>span>19 <span class="text-purple-<span class="text-orange-400">400span> font-semibold">constspan> getRes = <span class="text-purple-<span class="text-orange-400">400span> font-semibold">awaitspan> <span class="text-blue-400">requestspan>(app)20 .<span class="text-blue-400">getspan>(/api/users/userId)21 .<span class="text-blue-400">expectspan>(<span class="text-orange-400">200span>);22 23 <span class="text-blue-400">expectspan>(getRes.body.data.name).<span class="text-blue-400">toBespan>(<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">'<span class="text-yellow-<span class="text-orange-400">300span>">Testspan>'span>);24});Load Testing
1# <span class="text-yellow-<span class="text-orange-400">300span>">Apachespan> <span class="text-yellow-<span class="text-orange-400">300span>">Benchspan>2ab -n <span class="text-orange-400">10000span> -c <span class="text-orange-400">100span> http:<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>=<span <span class="text-purple-<span class="text-orange-400">400span> font-semibold">classspan>="text-green-<span class="text-orange-400">400span>">"text-gray-<span class="text-orange-400">500span> italic"span>>//api.example.com/usersspan>3 4# k65k6 run load-test.jsREST vs GraphQL vs gRPC Comparison
| Feature | REST | GraphQL | gRPC | |---------|------|---------|------| | Protocol | HTTP/1.1 | HTTP/1.1 | HTTP/2 | | Format | JSON | JSON | Binary (Protobuf) | | Performance | Good | Good | Excellent | | Caching | Easy (HTTP) | Complex | Custom | | Browser Support | Native | Native | Limited (needs gRPC-Web) | | Learning Curve | Low | Medium | High | | Documentation | Manual | Auto (introspection) | Auto (generated) | | Versioning | URL/Header | Schema evolution | Backward compatible | | Best For | Public APIs | Complex data needs | Microservices |
Best Practices Checklist
- [x] RESTful resource naming
- [x] Consistent response format
- [x] Proper HTTP status codes
- [x] API versioning
- [x] Pagination for lists
- [x] HTTPS only
- [x] Authentication (JWT, OAuth)
- [x] Authorization (RBAC)
- [x] Rate limiting
- [x] Input validation
- [x] CORS configuration
- [x] Response compression
- [x] Caching headers
- [x] Database query optimization
- [x] Connection pooling
- [x] CDN for static responses
- [x] Comprehensive documentation
- [x] Code examples
- [x] Postman collection
- [x] Sandbox environment
- [x] Changelog
- [x] Logging (ELK, Splunk)
- [x] Metrics (Prometheus)
- [x] Distributed tracing (Jaeger)
- [x] Error tracking (Sentry)
- [x] Uptime monitoring
Conclusion
Choosing the right API architecture depends on your specific needs:
- Building public APIs
- Simple CRUD operations
- Caching is important
- Standard HTTP is sufficient
- Complex data requirements
- Mobile apps (minimize data)
- Rapid frontend iteration
- Multiple clients with different needs
- Microservices communication
- Performance is critical
- Real-time streaming needed
- Internal APIs
Regardless of choice, follow core principles: consistency, simplicity, security, and great documentation. A well-designed API is a developer's best friend and a poorly designed one is everyone's nightmare.
Start simple, iterate based on feedback, and always prioritize developer experience. Your API is the interface to your business logic—make it excellent.