1. What is a REST API?
A REST API is a web interface that follows the Representational State Transfer architectural style, exposing resources over HTTP so clients can read and change them through standard methods. Each resource is identified by a URL and transferred as a representation, usually JSON. REST was defined by Roy Fielding in his 2000 dissertation and relies on a uniform interface, statelessness and standard HTTP semantics rather than a fixed protocol.
2. What are the six constraints of REST?
The REST constraints are client-server, stateless, cacheable, uniform interface, layered system and, optionally, code on demand. Client-server separates UI from data storage. Stateless means each request carries all needed context. Cacheable responses declare whether they can be reused. Layered systems allow proxies and gateways between client and server. The uniform interface covers resource identification, manipulation through representations, self-descriptive messages and HATEOAS.
3. What are the main HTTP methods used in REST and what does each do?
The main methods are GET (read), POST (create or trigger an action), PUT (replace), PATCH (partially update) and DELETE (remove). HEAD returns only headers and OPTIONS describes what a resource supports, which is also used in CORS preflight. Using each method for its defined semantics lets clients, caches and proxies behave predictably.
GET /users/42 read user 42
POST /users create a user
PUT /users/42 replace user 42
PATCH /users/42 update some fields
DELETE /users/42 delete user 42
4. What is the difference between safe and idempotent HTTP methods?
A safe method does not change server state, while an idempotent method can be repeated and leaves the server in the same state as a single call. GET, HEAD and OPTIONS are safe. GET, HEAD, OPTIONS, PUT and DELETE are idempotent. POST is neither, and PATCH is not guaranteed to be idempotent. Idempotency matters because clients and proxies can safely retry after a timeout.
5. What is idempotency and why does it matter in REST APIs?
Idempotency means making the same request multiple times has the same effect on server state as making it once. It matters because networks fail and clients retry, and a retry must not create duplicate orders or double charges. PUT and DELETE are idempotent by definition. For POST, APIs often accept an Idempotency-Key header and store the result so a repeated key returns the original response.
POST /payments
Idempotency-Key: 7b1f3c9e-2a44-4c1a-9d10-5f3e8a2c1b00
6. What is the difference between PUT and PATCH?
PUT replaces the entire resource with the payload you send, while PATCH applies a partial modification to specific fields. With PUT, omitted fields are typically reset or removed, and the call is idempotent. PATCH is lighter when changing one field, and its payload may be a merge document (JSON Merge Patch) or a list of operations (JSON Patch).
PATCH /users/42
{ "email": "new@example.com" }
7. What is the difference between POST and PUT?
POST creates a new resource or triggers processing and is not idempotent, whereas PUT creates or replaces a resource at a URL the client specifies and is idempotent. With POST /orders the server picks the new ID and returns it. With PUT /orders/123 the client targets a known URI, so repeating the call yields the same state.
8. What are the most common HTTP status code classes and what do they mean?
Status codes are grouped in five classes: 1xx informational, 2xx success, 3xx redirection, 4xx client error and 5xx server error. A 2xx means the request was accepted and handled, a 3xx tells the client to look elsewhere or reuse a cached copy, a 4xx means the client sent something wrong, and a 5xx means the server failed on a valid request.
9. Which HTTP status codes should a REST API return for common situations?
Use 200 OK for successful reads and updates, 201 Created with a Location header after creation, 204 No Content for successful requests with no body, 400 for malformed input, 401 for missing or invalid credentials, 403 for authenticated but forbidden, 404 for a missing resource, 409 for conflicts, 422 for validation failures, 429 for rate limiting and 500 for unexpected server errors.
10. What is the difference between 401 Unauthorized and 403 Forbidden?
401 means the request lacks valid authentication, while 403 means the server knows who you are but you are not allowed to do this. Despite its name, 401 is about authentication, and it should include a WWW-Authenticate header. Logging in again may fix a 401, but it will not fix a 403 because the problem is permissions.
11. What is the difference between 400, 404 and 422 status codes?
400 Bad Request means the request is malformed, such as invalid JSON syntax. 404 Not Found means the target resource does not exist. 422 Unprocessable Content means the syntax is valid but the data fails semantic validation, such as a negative quantity. Many teams use 400 for both malformed and invalid input, so what matters is staying consistent and documenting it.
12. What does it mean that REST is stateless?
Stateless means the server stores no client session context between requests, so every request must contain everything needed to process it, such as an auth token and all parameters. This lets any server instance handle any request, which makes horizontal scaling and load balancing simple. Session state, if needed, lives on the client or in a shared store keyed by a token.
13. How do you design good REST API URLs and name resources?
Use plural nouns for resources, express hierarchy with nesting, and let the HTTP method express the action. Prefer /users/42/orders over /getUserOrders. Use lowercase with hyphens, avoid verbs and file extensions, and keep nesting to about two levels. For actions that do not map to CRUD, model them as a sub-resource such as POST /orders/42/cancellation.
GET /users/42/orders
POST /orders/42/cancellation
14. When should you use path parameters versus query parameters?
Use path parameters to identify a specific resource and query parameters to filter, sort, search or paginate a collection. /users/42 points to one user, while /users?role=admin&sort=name refines a list. Path segments are part of the resource identity and required, whereas query parameters are optional modifiers that usually do not change which resource is addressed.
15. How do you implement pagination in a REST API?
Return a limited page of results with parameters to move through the rest, using either offset-based or cursor-based pagination. Offset pagination (?limit=20&offset=40) is simple but slow and unstable on large or changing data. Cursor pagination (?limit=20&after=abc123) uses an opaque marker, stays consistent and scales better. Include next-page links or a cursor in the response.
{
"data": [],
"next_cursor": "eyJpZCI6MTIwfQ",
"has_more": true
}
16. How do you handle filtering and sorting in a REST API?
Pass filters and sort order as query parameters on the collection endpoint. A common style is GET /products?category=books&price_max=20&sort=-created_at, where a leading minus means descending. Validate and whitelist allowed fields to avoid injection and slow queries, document the supported operators, and combine them with pagination so results stay bounded.
17. What are the common approaches to API versioning?
The common approaches are URI versioning (/v1/users), header or media-type versioning (Accept: application/vnd.example.v2+json), and query parameter versioning (?version=2). URI versioning is the most visible and easiest to route and cache. Header versioning keeps URLs clean but is harder to test. Whichever you choose, avoid breaking changes within a version and announce deprecation with a sunset period.
18. What are the common ways to authenticate a REST API?
Common methods are API keys, HTTP Basic auth, bearer tokens such as JWTs, and OAuth 2.0 with OpenID Connect for delegated access. Because REST is stateless, the client sends credentials on every request, typically in the Authorization header. Always use HTTPS, give tokens short lifetimes with refresh tokens, and never put secrets in URLs.
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
19. What is the difference between authentication and authorization in an API?
Authentication verifies who the caller is, while authorization decides what that caller may do. An API first validates a token or key (authentication) and then checks roles, scopes or ownership for the requested action (authorization). Failures map to 401 for authentication and 403 for authorization.
20. What is content negotiation and which headers are involved?
Content negotiation lets client and server agree on the representation format of a resource. The client uses Accept to say what it wants, such as application/json, and Content-Type to describe the body it sends. The server replies with its own Content-Type, or 406 Not Acceptable if it cannot satisfy the request, or 415 Unsupported Media Type for an unsupported request body. Accept-Language and Accept-Encoding work similarly.
Accept: application/json
Content-Type: application/json
21. How does caching work in REST APIs?
Servers mark responses as cacheable using headers so clients and intermediaries can reuse them. Cache-Control sets rules such as max-age=300 or no-store. Validators like ETag and Last-Modified let clients revalidate with If-None-Match or If-Modified-Since, and the server answers 304 Not Modified with no body when nothing changed. Only GET and HEAD responses are normally cached.
Cache-Control: public, max-age=300
ETag: "v42"
22. What is HATEOAS in REST?
HATEOAS (Hypermedia As The Engine Of Application State) means responses include links telling the client which actions and related resources are available next. The client navigates the API by following links rather than hardcoding URLs. It is part of the uniform interface constraint and defines the top level of the Richardson Maturity Model, though many real-world APIs skip it.
{
"id": 42,
"status": "open",
"_links": {
"self": { "href": "/orders/42" },
"cancel": { "href": "/orders/42/cancellation" }
}
}
23. What is the difference between REST and SOAP?
REST is an architectural style that usually uses HTTP with JSON, while SOAP is a strict XML-based protocol with a formal contract (WSDL) and standardized extensions like WS-Security. REST is lighter, cacheable and easier to consume. SOAP offers built-in standards for security, transactions and reliable messaging, so it still appears in banking and enterprise integrations.
24. What is the difference between REST and GraphQL?
REST exposes many fixed endpoints that each return a predefined shape, whereas GraphQL exposes a single endpoint where the client specifies exactly which fields it wants. GraphQL avoids over-fetching and multiple round trips, but makes HTTP caching, rate limiting and query cost control harder. REST is simpler and works naturally with HTTP caching and tooling.
25. How should you design error responses in a REST API?
Return the correct HTTP status code plus a consistent, machine-readable body that explains what went wrong. A good body has a stable error code, a human-readable message, and field-level details for validation errors. The standard application/problem+json format from RFC 9457 (which replaced RFC 7807) defines this. Never leak stack traces or internal details.
{
"type": "https://example.com/errors/validation",
"title": "Validation failed",
"status": 422,
"errors": [{ "field": "email", "message": "Invalid format" }]
}
26. How would you design a REST API for long-running operations such as video processing or report generation?
Accept the request, return 202 Accepted immediately, and let the client track progress through a status resource. The response includes a Location header pointing to something like /jobs/981. The client polls that URL, which reports pending, running, succeeded or failed, and on success links to the result. For push-style updates, offer a webhook callback instead of polling.
POST /reports -> 202 Accepted
Location: /jobs/981
GET /jobs/981 -> 200 {"status":"running","progress":40}
GET /jobs/981 -> 303 See Other, Location: /reports/55
27. How do you make a POST request safe to retry without creating duplicates?
Require an Idempotency-Key header, store the key together with the response of the first successful processing, and return that stored response for any repeat with the same key. Save the key and the business change in one database transaction, give keys an expiry such as 24 hours, and reject a reused key whose payload differs with 422 or 409. This protects payments and orders from client retries.
28. How do you handle concurrent updates to the same resource (lost update problem)?
Use optimistic concurrency control with an ETag and the If-Match header. The client reads the resource and its ETag, then sends the update with If-Match. If another client changed the resource meanwhile, the tag no longer matches and the server returns 412 Precondition Failed, so the client must refetch and retry. Requiring the header can be enforced with 428 Precondition Required.
PUT /articles/7
If-Match: "v5"
HTTP/1.1 412 Precondition Failed
29. What is wrong with this endpoint design: `POST /api/getUser?id=5`?
It uses a verb in the URL, tunnels a read through POST, and passes the identity as a query parameter. A read should be GET /users/5, which is safe, idempotent and cacheable. Using POST for reads defeats HTTP caching, makes automatic retries unsafe and hides intent from proxies and logs. The action name in the path (getUser) duplicates what the method already says.
30. How would you model a non-CRUD action such as "publish an article" or "transfer money" in REST?
Model the action as a resource or state change instead of a verb endpoint. For publishing, either PATCH /articles/7 with {"status":"published"} or create a sub-resource with POST /articles/7/publication. For a transfer, POST /transfers creates a transfer record that has its own ID, status and history. Treating the action as a noun gives you auditability, retries via idempotency keys and a place to read the outcome.
31. Why is offset pagination slow and inconsistent on large tables, and what is the alternative?
With OFFSET 100000 the database still scans and discards 100000 rows before returning the page, so latency grows with page depth. Inserts or deletes between requests also shift rows, causing duplicates or skipped items. Keyset (cursor) pagination filters by the last seen sort key and uses an index, so each page costs the same and stays stable.
SELECT id, title FROM posts
WHERE (created_at, id) < ('2026-10-01 12:00:00', 9120)
ORDER BY created_at DESC, id DESC
LIMIT 20;
32. How do you implement rate limiting in a REST API and what should the client see?
Apply a limit per API key, user or IP using an algorithm such as token bucket or sliding window, stored in a shared fast store like Redis so all instances agree. When the limit is exceeded, return 429 Too Many Requests with a Retry-After header. Expose remaining quota through headers, for example the RateLimit header fields from the IETF draft or the widely used X-RateLimit-* convention.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
33. What is CORS and why does a browser send a preflight OPTIONS request?
CORS (Cross-Origin Resource Sharing) is a browser mechanism that lets a server allow requests from a different origin. For requests that are not "simple", such as PUT, DELETE or ones with Content-Type: application/json or an Authorization header, the browser first sends an OPTIONS preflight asking if the real request is allowed. The server answers with Access-Control-Allow-Origin, -Methods and -Headers. CORS protects browsers only; it is not an API security control.
34. A client sends valid JSON but your API returns 415. What is the most likely cause?
The most likely cause is a missing or wrong Content-Type header, such as text/plain or none at all, so the server refuses to parse the body. 415 Unsupported Media Type refers to the request body format, while 406 Not Acceptable refers to the response format requested through Accept. The fix is to send Content-Type: application/json with the request.
35. How do you secure a REST API against common threats?
Layer several defenses: enforce HTTPS, authenticate every request, authorize at the object level, validate and size-limit all input, use parameterized queries, and apply rate limiting. Return minimal error detail and set strict CORS rules. Follow the OWASP API Security Top 10, where broken object level authorization (BOLA) is the most common flaw. Log security events and keep dependencies patched.
36. What is BOLA (IDOR) and how do you prevent it in an API?
BOLA, also called IDOR, happens when an API trusts an object ID from the client without checking that the caller owns it, so changing /orders/101 to /orders/102 exposes another user's data. Prevent it by checking authorization on every object access using the authenticated identity, scoping queries to the owner, and never relying on unguessable IDs alone. Return 404 rather than 403 when you do not want to reveal that the object exists.
const order = await db.orders.findOne({ id: req.params.id, userId: req.user.id });
if (!order) return res.status(404).end();
37. What is wrong with storing a JWT in localStorage and what are safer options?
Anything in localStorage is readable by any JavaScript on the page, so a single XSS flaw lets an attacker steal the token. A safer option for browser clients is an HttpOnly, Secure, SameSite cookie, which scripts cannot read, combined with CSRF protection when cookies are used. Keep access tokens short-lived and rotate refresh tokens, and for native or server clients use secure platform storage.
38. How do you revoke or invalidate a JWT before it expires?
JWTs are self-contained and validated without a database lookup, so revocation needs extra state. Common approaches are short access-token lifetimes with revocable refresh tokens, a denylist of token IDs (jti) kept in a fast store until their expiry, or a per-user token version that is checked on each request. Each option trades some statelessness for control, so choose based on how quickly revocation must take effect.
39. What does this response tell you, and is it correct? `HTTP 200` with body `{"success": false, "error": "Not found"}`
It is an anti-pattern: the status code says success while the body reports failure. Clients, caches, monitoring and retry logic rely on the status line, so they will treat the error as a good response and may even cache it. The correct response is 404 Not Found with an error body such as application/problem+json, keeping the HTTP status as the source of truth.
40. How do you handle bulk operations, such as creating or deleting 500 items, in a REST API?
Offer a dedicated batch endpoint that accepts an array and returns per-item results, instead of forcing 500 separate requests. Set a maximum batch size, and decide whether the batch is atomic (all or nothing) or partial. For partial success, return 207 Multi-Status or 200 with a result per item, each carrying its own status and error. For large jobs, combine this with an asynchronous 202 job.
{
"results": [
{ "index": 0, "status": 201, "id": 811 },
{ "index": 1, "status": 422, "error": "name is required" }
]
}
41. How do you reduce response size and improve REST API performance?
Combine several techniques: enable compression (gzip or br) through Accept-Encoding, support field selection like ?fields=id,name, paginate every collection, and use ETag and Cache-Control so clients skip unchanged data. Add database indexes, avoid N+1 queries, reuse connections with HTTP keep-alive, and serve over HTTP/2. Measure first with p95 latency, because the bottleneck is often the database rather than the payload.
42. What is the N+1 query problem in an API and how do you fix it?
The N+1 problem occurs when listing N items triggers one query for the list plus one extra query per item to load related data, such as fetching 100 orders and then each customer separately, producing 101 queries. Fix it with a join or eager loading, or by batching the related lookups into a single WHERE id IN (...) query. Query logging or an APM tool will reveal it.
SELECT o.id, c.name
FROM orders o JOIN customers c ON c.id = o.customer_id
LIMIT 100;
43. How would you handle breaking changes without breaking existing clients?
Treat adding optional fields or new endpoints as non-breaking, and treat removing or renaming fields, changing types or changing semantics as breaking. Ship breaking changes in a new version while keeping the old one running, mark the old version deprecated with Deprecation and Sunset headers, publish a migration guide, and watch usage metrics before turning it off. Clients should also be written to ignore unknown fields.
44. What are webhooks and how do they differ from polling?
Webhooks let the server push an HTTP POST to a URL the client registered when an event happens, whereas polling means the client repeatedly asks for updates. Webhooks cut latency and wasted requests. They need care: sign each payload (for example an HMAC in a header) so receivers can verify it, retry with exponential backoff on failure, include an event ID for deduplication, and expect delivery to be at least once.
POST https://client.example.com/hooks
X-Signature: sha256=9f2c...
{"id":"evt_1","type":"order.paid"}
45. Why should you document a REST API with OpenAPI, and what do you get from it?
OpenAPI is a machine-readable description of endpoints, parameters, schemas, auth and responses. A single spec file can generate interactive docs such as Swagger UI, client SDKs, server stubs, mock servers and contract tests, and it can validate requests in a gateway. Writing the spec first (design-first) helps teams agree on the contract before implementation and prevents the docs from drifting from the code.
{
"openapi": "3.1.0",
"info": { "title": "Shop API", "version": "1.0.0" },
"paths": { "/users/{id}": { "get": { "responses": { "200": { "description": "OK" } } } } }
}
46. How do you test a REST API effectively?
Use a test pyramid: unit tests for business logic, integration tests that call real endpoints against a test database, and a few end-to-end tests for critical flows. Assert status codes, headers, response schema and error cases, not just the happy path. Add contract tests so provider and consumer agree on the schema, and load tests to check latency under traffic. Tools such as Postman, REST Assured or supertest are common.
47. What is the difference between a 301 and a 308 redirect, and how do they affect API clients?
Both are permanent redirects, but 301 allows clients to change the method to GET when following it, while 308 Permanent Redirect requires the same method and body to be reused. For an API, redirecting POST /v1/orders with 301 can silently turn it into a GET and lose the body. Use 308 (or 307 for temporary) to preserve the method.
48. How should an API behave when a client sends an unknown field or a field it should not control, such as `role` or `id`?
The API should never blindly bind request bodies to database models, because that causes mass assignment, where a client sets fields like isAdmin or id. Use an explicit allowlist of writable fields through a DTO or schema, and ignore or reject unknown properties consistently. Read-only fields such as id and createdAt should be set only by the server, and rejecting with 400 or 422 makes mistakes visible.
const { name, email } = req.body;
User.create({ name, email });
49. When would you choose gRPC or WebSockets over a REST API?
Choose REST for public, resource-oriented APIs that benefit from HTTP caching and wide tooling. Choose gRPC for low-latency internal service-to-service calls with strongly typed contracts (Protocol Buffers), HTTP/2 streaming and generated clients. Choose WebSockets, or server-sent events for one-way updates, when the server must push frequent real-time data such as chat or live prices. The options are often combined in one system.
50. How would you design a REST API for a many-to-many relationship such as students and courses?
Expose both sides as top-level collections and model the relationship as its own resource when it carries data or needs independent lifecycle. For simple links, use sub-collections like GET /students/5/courses and PUT /students/5/courses/9 to enrol. If the link has attributes such as grade or date, create an /enrollments resource so you can query, update and audit it directly instead of burying it inside either parent.
GET /students/5/courses
POST /enrollments {"studentId":5,"courseId":9}
GET /courses/9/students