APIs & Protocols
- Design clean REST APIs that serve as the contract for your system
- Know when REST, GraphQL, and gRPC are each the right choice
- Understand pagination, versioning, and authentication at the API level
- Avoid common API design mistakes that cost points in interviews
In the Delivery Framework, API design is step 3, right after requirements and core entities. Your API defines the contract between clients and your system. Every component you draw in the high-level design exists to serve these endpoints. Get the API wrong, and the rest of your design builds on a shaky foundation.
This lesson covers how to design APIs well in an interview context: which protocol to choose, how to structure endpoints, and the details (pagination, auth, versioning) that separate a senior-level API from a junior one.
REST
REST (Representational State Transfer) is your default choice for system design interviews. It's the most widely understood API style, maps cleanly to CRUD operations, and is the right fit for the vast majority of interview problems.
Core Principles
REST models your system as resources, the nouns of your system, accessed through standard HTTP methods. A resource is a thing in your system, like a user or a tweet. The URL identifies the resource, and the HTTP method specifies the action.
•
GET reads a resource (idempotent, cacheable)•
POST creates a new resource•
PUT replaces a resource entirely (idempotent)•
PATCH updates specific fields of a resource•
DELETE removes a resource (idempotent)Idempotent means calling the same operation multiple times produces the same result. GET, PUT, and DELETE are idempotent, so if the client retries after a network timeout, nothing breaks. POST is not. Retrying it might create duplicate resources. The distinction matters when you discuss retry logic and failure handling.
URL Design
Resource names should be plural nouns. Use path hierarchy to express relationships. Keep URLs predictable and consistent.
Do
GET /v1/users/:id/ordersexposes a user's orders as a sub-resourcePOST /v1/tweetscreates a tweet (noun, plural)DELETE /v1/comments/:iddeletes by resource ID
Don't
GET /v1/getUserOrdersputs a verb in the URL, not RESTfulPOST /v1/createTweetputs the action in the URL, redundant with POSTPOST /v1/tweet/delete/:idshould use the DELETE method instead
Request & Response Design
Derive the user from the auth token. Never pass the current user's ID in the request body. The server extracts the authenticated user from the JWT or session token. That's more secure and avoids a whole class of authorization bugs.
Use standard HTTP status codes: 200 for success, 201 for created, 400 for bad request, 401 for unauthorized, 404 for not found, 429 for rate limited, 500 for server error. Don't invent custom codes.
GraphQL
GraphQL lets clients request exactly the data they need in a single query. Instead of hitting multiple REST endpoints and getting back fixed response shapes, the client specifies the exact fields it wants, and the server returns precisely that.
GraphQL Strengths
- No over-fetching or under-fetching; the client gets exactly what it asks for
- A single endpoint handles all queries, so endpoints never proliferate
- Great for diverse clients (web, mobile, TV) that need different data shapes
- Built-in type system and introspection
GraphQL Drawbacks
- More complex server implementation than REST
- Harder to cache (single endpoint, POST requests)
- Risk of expensive queries if not carefully constrained (query depth limiting)
- Overkill for simple CRUD applications
When to use GraphQL in interviews: when the problem involves multiple client types (mobile app, web app, third-party API) that need different subsets of the same data. A social media feed where the mobile client needs thumbnails and the web client needs full-resolution images is a good example.
When NOT to use it: for simple backend-to-backend communication, or when you have a single client type. Don't reach for GraphQL just because it sounds modern. The added complexity needs justification.
gRPC
gRPC is a high-performance RPC framework that uses Protocol Buffers (protobuf) for serialization and HTTP/2 for transport. It's significantly faster than REST/JSON for service-to-service communication because protobuf is a compact binary format and HTTP/2 enables multiplexing and streaming.
When to use gRPC in interviews: for internal service-to-service communication in a microservices architecture where latency and throughput matter. A recommendation service calling a user profile service millions of times per second is a good use case.
When NOT to use it: for client-facing APIs (browsers don't natively support gRPC), or when human-readable payloads are important for debugging. The common pattern is REST or GraphQL for external APIs, gRPC for internal service communication.
Choosing the Right Protocol
Default to REST
It's universally understood, easy to reason about, and sufficient for the vast majority of system design problems. Start here unless you have a specific reason not to.
Consider GraphQL for diverse clients
When mobile, web, and third-party clients need different views of the same data, GraphQL eliminates the need for multiple endpoint variants.
Use gRPC for internal high-throughput
When services communicate millions of times per second and latency matters, gRPC's binary serialization and HTTP/2 multiplexing make a real difference.
WebSockets for real-time push
When the server needs to push data to clients without them asking, like chat or live notifications, use WebSockets alongside your REST API.
Pagination
Any endpoint that returns a list needs pagination. Returning thousands of results in a single response is a performance disaster and a red flag in interviews. There are two main approaches.
Offset-Based
GET /tweets?page=3&limit=20- Simple to implement and understand
- Supports jumping to arbitrary pages
- Breaks when data changes between pages (items shift)
- Slow on large offsets (DB must scan and skip rows)
Cursor-Based
GET /tweets?cursor=abc123&limit=20- Stable results even when data changes
- Efficient at any depth (no offset scanning)
- Cannot jump to arbitrary pages
- Best for infinite scroll, feeds, timelines
Default to cursor-based pagination in interviews. It's more scalable and better suited to the feed-like interfaces that dominate system design questions. Mention the trade-off: "Cursor-based is more efficient but doesn't support jumping to page 50, which we don't need for a feed."
Versioning & Auth
Versioning: prefix your API paths with a version number: /v1/tweets, /v2/tweets. This lets you make breaking changes without disrupting existing clients. In an interview, always include v1 in your endpoints. It's a small detail that signals experience.
Authentication: use token-based auth (JWT or OAuth). The client sends a token in the Authorization header, and the server validates it to identify the user. Don't design a custom auth scheme in an interview. Just say "auth is handled via JWT" and move on. Authentication is important but rarely the interesting part of a system design.
API Design in Interviews
Your API design step should take about 5 minutes. Here's the pattern:
For each functional requirement, define one or two endpoints. Use your core entities as resource names. Include the HTTP method, path, request body (if any), and response type. Don't over-specify. You're sketching the shape of the API, not writing Swagger docs.
POST /v1/posts { image_url, caption } → PostGET /v1/feed → Post[]POST /v1/follows { followee_id }POST /v1/posts/:id/likesGET /v1/posts/:id/comments → Comment[]Five endpoints, directly mapped to the functional requirements. Auth token provides the user context. Pagination cursor on list endpoints.
Common Mistakes
Verbs in URLs. POST /createUser instead of POST /v1/users. The HTTP method already specifies the action, so the URL just identifies the resource.
Passing user ID in the body. POST /v1/tweets { user_id: "123", text: "..." } is a security risk, since the caller could pass someone else's ID. Derive the user from the auth token.
Forgetting pagination. Any endpoint returning a list should accept a cursor or page parameter. Unbounded list responses are a scaling issue and a red flag.
Over-specifying the API. Spending 10 minutes defining every field of every request and response body. Keep it high-level: method, path, key parameters, return type. You can add details as they become relevant during the high-level design.
Key Takeaways
- ✓Default to REST for interview API designs. GraphQL for diverse clients, gRPC for internal high-throughput service calls.
- ✓Resources are plural nouns (/users, /tweets). HTTP methods define the action. Derive the current user from the auth token.
- ✓Always include pagination for list endpoints. Prefer cursor-based for feeds and timelines.
- ✓Version your API (/v1/...) and use standard HTTP status codes.
- ✓Spend about 5 minutes on API design. Define endpoints for each functional requirement, then move to high-level design.