REST Interview Questions Common REST and API design questions asked in backend and fullstack interviews. Understanding the reasoning behind REST conventions sep…
REST Interview Questions
Common REST and API design questions asked in backend and fullstack interviews. Understanding the reasoning behind REST conventions separates strong candidates from those who just memorize definitions.
1. What is REST and what are its key constraints?
REST (Representational State Transfer) is an architectural style for distributed hypermedia systems, defined by Roy Fielding in his 2000 doctoral dissertation. It is defined by six constraints: client-server (separating concerns), stateless (no server-side session; each request contains all needed info), cacheable (responses must declare cacheability), uniform interface (resources identified by URI, manipulated via representations, self-descriptive messages, HATEOAS), layered system (client cannot tell if it's talking to the server directly or a proxy), and code on demand (optional: server can send executable code). An API satisfying all mandatory constraints is RESTful.
2. What is the difference between REST, SOAP, and GraphQL?
SOAP is a rigid XML-based protocol with a strict contract (WSDL). It has built-in standards for security (WS-Security), transactions, and error handling. Used in enterprise and financial systems where formal contracts matter. REST is an architectural style using HTTP and any format (usually JSON). Flexible, human-readable, leverages HTTP caching and semantics. Best for CRUD-style APIs and public APIs. GraphQL is a query language where clients specify exactly what data they need in a single request. Eliminates over-fetching and under-fetching, great for complex client-driven data requirements. Requires more backend work; no native HTTP caching. Best when clients have very diverse data needs (mobile vs web vs analytics).
3. What is the difference between PUT and PATCH?
PUT replaces the entire resource. You send the complete representation, and the server stores it as-is. If you omit a field, it gets cleared. PUT is idempotent: calling it multiple times with the same body produces the same result. PATCH applies a partial update - you only send the fields you want to change, and the server merges them into the existing resource. PATCH is usually idempotent in practice (setting name to "Alice" repeatedly = same result) but not guaranteed by the spec if the operation is relative (e.g., "increment counter by 1"). For a user API: PUT /users/42 needs the full user object; PATCH /users/42 can send just {"name": "Alice"}.
4. What does statelessness mean in REST and why does it matter?
Stateless means the server does not store any session state between requests. Every request must contain everything needed to process it - authentication credentials, context, and parameters. The server has no memory of previous requests from the same client. This matters for scalability: any server instance can handle any request, so load balancers can route freely and you can horizontally scale without sticky sessions. For reliability: if a server crashes, the client just retries with the next server - no lost state. The trade-off is that clients must manage state themselves, and auth tokens must travel with every request (typically as Authorization: Bearer headers).
5. How do you handle authentication in REST APIs?
The most common patterns: (1) JWT (JSON Web Token): client gets a signed token after login, sends it as Authorization: Bearer <token> with every request. Server verifies the signature without a DB lookup - stateless. Use short-lived access tokens (15min) + long-lived refresh tokens. (2) OAuth 2.0: authorization framework for delegated access (logging in with Google, third-party app permissions). Client gets an access token from the authorization server. (3) API Keys: simple string sent in a header (X-API-Key) or query param. Good for server-to-server. Easy to rotate. (4) Session cookies: server stores session in DB/Redis, sends session ID cookie. Simpler for traditional web apps but requires sticky sessions or shared state store.
6. What is idempotency and why is it important for API design?
An operation is idempotent if applying it multiple times produces the same result as applying it once. In HTTP: GET, PUT, DELETE are idempotent; POST is not. Idempotency matters for reliability because networks fail and clients retry. DELETE /users/42 twice should be safe - the second call can return 404 (user gone) or 204 (no change), but must NOT accidentally delete user 43. For non-idempotent operations like payments (POST), use idempotency keys - the client generates a unique UUID per operation and sends it in the Idempotency-Key header. The server stores the result and returns it on retry without re-processing. This is how Stripe prevents double-charges on network retries.
7. What is the difference between 401 and 403?
401 Unauthorized means the request lacks valid authentication credentials - the client is not identified (no token, expired token, invalid signature). The response should include WWW-Authenticate header telling the client how to authenticate. 403 Forbidden means the client IS authenticated but is not authorized to perform this action - they don't have permission. A common mistake: returning 401 for missing login, and 404 instead of 403 when you don't want to reveal the existence of a resource the user can't access. Security tip: for resources that should be hidden entirely from unauthorized users, return 404 instead of 403 to prevent information disclosure about what exists.
8. How do you implement rate limiting in a REST API?
Rate limiting prevents abuse and ensures fair usage. Common algorithms: Fixed window (count requests per minute, reset at window boundary - susceptible to burst at boundary), sliding window log (track timestamps of requests, count in last N seconds - memory intensive), token bucket (refill tokens at rate R, allow burst up to capacity B - smooth), leaky bucket (queue requests, process at fixed rate - uniform output). Implementation: use Redis with INCR + EXPIRE for fixed window, or Redis sorted sets for sliding window. Return 429 Too Many Requests with Retry-After header. Different limits per user tier. Distinguish IP-based limits (unauthenticated) from API key/user limits (authenticated). Rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
9. How do you version a REST API without breaking existing clients?
First, minimize breaking changes: add new optional fields (additive changes are safe), never remove or rename fields without a version bump, never change field types. When you must break: use URL versioning (/api/v2/) or header versioning (API-Version: 2025-03-01). Announce deprecation early with Sunset and Deprecation headers. Support old versions for 6-12 months with clear migration guides. Stripe's approach is a best practice: date-based versions where each client pins to the date they integrated. New clients get the latest behavior; old clients keep old behavior. Changes are documented by date.
10. When would you choose cursor-based over offset pagination?
Offset pagination (LIMIT N OFFSET M) is simple to implement and allows jumping to any page, but has two problems: inconsistency (if items are inserted/deleted between requests, you see duplicates or skip items) and performance (large OFFSETs require the DB to scan and discard M rows). Cursor-based pagination uses an opaque cursor (usually the last item's id or a base64-encoded timestamp+id) as the starting point for the next page. It is stable under insertion/deletion (always starts from a known item) and efficient (uses indexed WHERE id > cursor). The trade-off: cannot jump to page 5 directly; only next/previous navigation is possible. Use cursor for: real-time feeds, infinite scroll, large datasets. Use offset for: admin tables with page numbers, small datasets.