Well-designed APIs are the backbone of modern web applications, enabling frontend-backend communication, third-party integrations, and microservices coordination. This guide covers best practices for building REST APIs, when to choose GraphQL, and how microservices architecture influences API design decisions for scalable, maintainable applications.
What Makes a REST API Well-Designed?
REST (Representational State Transfer) remains the most widely used API architecture. A well-designed REST API follows these principles:
- Resource-based URLs: Use nouns, not verbs.
/api/v1/users/123not/api/getUser?id=123. Plural nouns for collections. - Correct HTTP methods: GET for reading, POST for creating, PUT/PATCH for updating, DELETE for removing. Never use GET for state-changing operations.
- Consistent response format: Standardise your JSON response envelope (data, meta, errors) across all endpoints. Use camelCase for JSON properties.
- Meaningful status codes: 200 for success, 201 for created, 400 for bad request, 401 for unauthorised, 403 for forbidden, 404 for not found, 429 for rate-limited, 500 for server error.
- Pagination: Always paginate list endpoints. Use cursor-based pagination for large datasets; offset-based for simpler use cases.
- Filtering and sorting: Support query parameters for filtering (
?status=active) and sorting (?sort=-created_at) on collection endpoints.
When Should You Choose GraphQL Over REST?
GraphQL is not a replacement for REST; it solves different problems. Choose GraphQL when:
| Scenario | Better Choice | Reason |
|---|---|---|
| Multiple client types (web, mobile, IoT) needing different data shapes | GraphQL | Clients request exactly the fields they need |
| Deeply nested or related data (social graphs, e-commerce catalogs) | GraphQL | Single query replaces multiple REST calls |
| Simple CRUD operations with predictable data needs | REST | Simpler to implement, cache, and debug |
| Public APIs for third-party developers | REST | More universally understood, easier to document |
| Real-time data (subscriptions) | GraphQL | Built-in subscription support |
| File uploads and downloads | REST | GraphQL handles binary data awkwardly |
How Do Microservices Change API Design?
Microservices architecture splits a monolithic application into small, independently deployable services that communicate through APIs. This has significant implications for API design:
- API Gateway: Use an API gateway (Kong, AWS API Gateway, or Nginx) as a single entry point that routes requests, handles authentication, rate limiting, and protocol translation.
- Service-to-service communication: Use lightweight protocols. REST over HTTP for synchronous calls, message queues (RabbitMQ, Apache Kafka) for asynchronous communication.
- Contract-first design: Define API contracts (OpenAPI/Swagger specifications) before implementation. This lets frontend and backend teams work in parallel.
- Backward compatibility: Never break existing consumers. Use API versioning (URL path or header-based) and deprecation cycles.
- Circuit breakers: Implement circuit breaker patterns to prevent cascading failures when downstream services are unavailable.
- Distributed tracing: Use correlation IDs in headers to trace requests across services for debugging.
What Security Practices Are Essential for APIs?
- Authentication: Use OAuth 2.0 with JWT tokens for user-facing APIs. API keys for server-to-server communication. Never pass credentials in URL parameters.
- Rate limiting: Protect against abuse with per-client rate limits. Return 429 status with Retry-After header.
- Input validation: Validate and sanitise all input on the server side. Never trust client input regardless of frontend validation.
- HTTPS only: Enforce TLS for all API communication. Redirect HTTP to HTTPS.
- CORS configuration: Whitelist specific origins. Never use wildcard (*) in production.
- Sensitive data: Never log or return sensitive data (passwords, tokens, Aadhaar numbers, PAN details) in API responses or error messages.
How do you version APIs without breaking existing clients?
Use URL-based versioning (/api/v1/, /api/v2/) for public APIs where clarity matters. Use header-based versioning (Accept: application/vnd.api+json;version=2) when URL aesthetics matter. Support at least two versions simultaneously with a 6-12 month deprecation notice for older versions. Document breaking changes clearly in your changelog.
What documentation tools work best for API teams?
Write OpenAPI 3.0 specifications and generate interactive documentation with Swagger UI or Redoc. For Indian development teams, Postman Collections combined with Postman’s built-in documentation feature is popular because developers already use Postman for testing. Maintain a public changelog and status page.
Should Indian startups start with microservices?
Usually no. Start with a well-structured monolith with clear module boundaries. Extract microservices only when specific parts of your application need independent scaling, deployment, or technology choices. Premature microservices adoption adds complexity that slows down small teams. When your team grows beyond 15-20 developers or you have clear scaling bottlenecks, microservices become worthwhile.
How do you handle API errors consistently?
Define a standard error response format and use it across all endpoints. Include a machine-readable error code, a human-readable message, and optionally a documentation URL. For validation errors, include field-level details. Log errors with request context (correlation ID, user ID, endpoint) for debugging without exposing internal details to the client.






