API Design — Cheat Sheet

Tags: api, rest, http, graphql, design, architecture

Level: intermediate

TL;DR: Best practices for contract-first API design, clear resource naming, predictable HTTP semantics, idempotency, and robust error handling.

Key concepts

Treat API contracts as public interfaces where breaking changes require explicit versioning.

Use nouns for resource endpoints and HTTP verbs for operations (GET, POST, PUT, PATCH, DELETE).

Differentiate PUT (full replacement) from PATCH (partial resource update).

Maintain idempotency on PUT, DELETE, and safe read methods like GET and HEAD.

Implement idempotent retries for mutating POST operations using unique Idempotency-Key headers.

Return standardized machine-readable error responses adhering to RFC 7807 (Problem Details).

Decouple internal database representations from external API DTOs and view models.

Support pagination via cursor-based tokens rather than offset/limit for large or mutable datasets.

Use explicit API versioning strategies such as URI pathing (/v1/) or custom request headers.

Enforce strict rate limiting using standard response headers (Retry-After, RateLimit-Remaining).

Typical questions and ready answers

Q: How do you handle breaking changes in an active production API?R: I introduce a new API version under a versioned path or header while deprecating the old endpoint with sunset warning headers, running both in parallel until clients migrate.

Q: What is the difference between PUT and PATCH, and when do you choose each?R: I use PUT when the client provides the full representation to replace the resource, and PATCH when sending partial deltas to modify specific fields without overwriting the rest.

Q: How do you guarantee idempotency in distributed payment or creation requests?R: I require clients to send a unique Idempotency-Key header, which I cache atomically with the execution state and response payload to return cached results on retries.

Pitfalls and common mistakes

Using verbs in endpoint paths like /getUser or /createOrder instead of standard REST resources.

Returning 200 OK with an error message in the payload body instead of proper HTTP status codes.

Leaking internal database identifiers, primary keys, or stack traces directly into API responses.

Relying on OFFSET pagination on volatile data tables, leading to skipped or duplicated records.

Over-fetching large datasets by not providing field filtering, sparse fieldsets, or pagination.

Snippets and commandsHTTP

```POST /v1/payments HTTP/1.1

Host: api.example.com

Content-Type: application/json

Idempotency-Key: 7b2c9e42-8f92-4917-91a5-83e91d5fa114

{

"amount": 4900,

"currency": "EUR"

}

{

"type": "https://api.example.com/errors/resource-not-found",

"title": "Resource Not Found",

"status": 404,

"detail": "Customer 48102 does not exist.",

"instance": "/v1/customers/48102"

}

```

To review

[ ] Cursor-based pagination vs offset pagination trade-offs

[ ] RFC 7807 Problem Details for HTTP APIs

[ ] Idempotency keys implementation with Redis

[ ] GraphQL vs REST trade-offs for over-fetching scenarios

Jarvis Interviews
Jarvis