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 and PUT 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 failed PUT or DELETE 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 vs PUT?

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.