8. Web APIs
Design robust, observable HTTP services with predictable contracts and safe retries.
Question: When designing a REST API endpoint, what are the key considerations?
Answer: Key considerations include using the correct HTTP methods, choosing appropriate status codes, implementing robust input validation, handling authentication/authorization, and ensuring security.
Explanation:
HTTP Methods: Use methods semantically (
POST
for creation,GET
for retrieval,PUT
for replacement).GET
andPUT
should be idempotent.Status Codes: Return standard codes like
200 OK
,201 Created
,400 Bad Request
,404 Not Found
.Validation: Use a library like Pydantic (as FastAPI does) to define data schemas and automatically validate incoming requests.
Security: Use HTTPS, handle authentication (e.g., with JWTs), and authorize that a user has permission to perform an action.
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
async def get_current_user():
# In a real app: validate token, return user or raise
return {"id": 1}
@app.post("/items", status_code=201)
async def create_item(item: Item, user = Depends(get_current_user)):
saved = await save_item(item, user)
if not saved:
raise HTTPException(400, "Cannot save item")
return saved
Question: How do you implement basic rate limiting?
Answer: Use a token-bucket/leaky-bucket algorithm backed by Redis (or a gateway) to cap requests per key.
Question: How do you expose OpenAPI docs and validate schemas?
Answer: Frameworks like FastAPI generate OpenAPI automatically; document response models and error formats.
Question: Beyond the basics, what makes a REST API well-designed?
Answer: A well-designed REST API is consistent, well-documented, and predictable. Key features include clear versioning, support for idempotency, consistent error payloads, and hypermedia controls (HATEOAS).
Explanation:
Versioning: Expose the API version in the URL (e.g.,
/api/v1/...
) or a header to manage changes without breaking clients.Idempotency: For non-
POST
requests, ensure that making the same call multiple times has the same effect as making it once. Clients can safely retry failedPUT
orDELETE
requests.Consistent Error Payloads: Return errors in a standard format (e.g.,
{"error": {"code": "AUTH_ERROR", "message": "Invalid token"}}
) across all endpoints.HATEOAS (Hypermedia as the Engine of Application State): Responses should include links to related actions or resources, making the API discoverable. For example, a response for a bank account might include links to "deposit," "withdraw," or "close" the account.
Question: How do you implement pagination, filtering, and ETags for cache-friendly APIs?
Answer: Use cursor-based pagination for stability, accept filter/sort params, and include ETag
/Last-Modified
with conditional requests (If-None-Match
).
Explanation: Cursors avoid page drift; ETags enable 304 Not Modified
responses to save bandwidth.
GET /items?cursor=abc&limit=50&sort=created_at&filter=status%3Dactive
If-None-Match: "W/\"etag123\""
Question: When should you use
PATCH
vsPUT
?
Answer: PUT
replaces the entire resource (idempotent); PATCH
applies a partial update.
Explanation: Prefer PATCH
for sparse updates; define a schema to avoid ambiguous merges.
Question: How do you design for idempotency and safe retries in write APIs?
Answer: Make PUT
/DELETE
idempotent and use idempotency keys for POST
. On duplicates, return the same response (200/201
) or a clear conflict (409
).
Explanation: Clients retry on network failures; servers should de-duplicate. Accept an Idempotency-Key
header and cache the first result for that key for a TTL window.
POST /payments
Idempotency-Key: 3f2d-...-9a
Question: What is the difference between JWT and OAuth2?
Answer: They are related but serve different purposes. JWT (JSON Web Token) is a token format for securely transmitting information. OAuth2 is an authorization framework that defines how a client can obtain access to resources on behalf of a user.
Explanation: OAuth2 is a protocol. It can use various token formats, and JWT is a popular choice. In a typical OAuth2 flow, a user authorizes a client application, which then receives an access token from an authorization server. This token (often a JWT) is then sent to the resource server (the API) with each request to prove the client is authorized. JWTs are self-contained; they carry user information and permissions as a JSON payload, which is digitally signed to prevent tampering.