home
›
cheatsheets
›
system_design
›
api_design
Free to read Every card and diagram, and Quiz me
2
Free account Star cards. Your Quiz me marks are kept, so next time you drill just what you missed
3
Pro All 92 answers on this sheet, My sheet across every topic, and PDFs
A free account keeps your stars and Quiz me marks. Pro adds all 92 answers on this sheet, My sheet across every topic, and PDFs.
/
Read
Quiz me
Comfortable
Compact
My misses 0
Click any code to copy it
Done 0 /0
To review 0
On this sheet
The model
01 Resources & methods02 Errors & retries03 Auth & security04 Paging, caching & speed05 Versions & change06 Async & real-time07 Architecture & scale08 gRPC basics09 gRPC in production10 Docs, tests & monitoring
The model An API is a contract that clients you don't control depend on. Change it by adding, never by removing or renaming. REST names resources with nouns, like /orders/7, and acts on them with HTTP methods. Stateless means each request carries its own token and context. Any server can answer it, so you scale by adding servers.Networks fail and clients retry. Make writes idempotent , so a repeat has the same effect as one call. gRPC keeps the contract in a .proto file and sends binary messages over HTTP/2. It suits calls between your own services.The gateway refuses a bad token or too many calls. Your code refuses a caller who isn't allowed, a missing record or bad input.
Resources & methods name things, then act on them with HTTP What REST is Name REST's six constraints Client-server, stateless, cacheable, uniform interface, layered system and optional code on demand.
Pick SOAP over REST Only for a WSDL contract or message-level security.
Tip HATEOAS means responses carry links to related actions, like _links.orders.
Name resources Name a collection GET /users Plural nouns, no verbs.
Pick one item by path, or filter by query GET /users/123 GET /users?role=admin
Show a parent and its children GET /users/123/orders
Tell a URI, URL and URN apart URLs locate, URNs name. Both are URIs.
Tip Keep nesting shallow. Reach a deep child directly, like /reviews/789.
Pick the HTTP method Read a resource GET /users/123 Safe and idempotent.
Create one, and let the server pick the id POST /users Neither safe nor idempotent.
Create or replace it at an id you choose PUT /users/123 Idempotent.
Change only some fields PATCH /users/123 Not guaranteed to be idempotent.
Remove it DELETE /users/123 Idempotent. 204 on success.
Tip HEAD and OPTIONS are safe too. A repeat DELETE can return 404 and still be idempotent.
Trap A PUT body is the whole resource. Leave a field out and the server should reset it to its default or null.
Model an action that isn't CRUD Cancel when only the status changes PATCH /orders/7 With {"status": "cancelled"}.
Cancel with a reason or a refund POST /orders/7/cancellation
Use a custom method, Google style POST /orders/7:cancel
Tip If it already shipped, refuse with 409 Conflict and say why.
Trap Avoid bare verb paths like /cancelOrder. They hide the resource the action changes.
Formats and content types Say what format a body is in Content-Type: application/json
Ask for JSON, with XML as second choice Accept: application/json, application/xml;q=0.9
Say why most APIs use JSON It's light and readable, and every language parses it.
Trap Set Content-Type on every body. A browser that guesses the type can read data as something else.
Errors & retries fail clearly, and retry without harm Status codes to know Answer a POST that created something 201 Created
Reject a body that won't parse 400 Bad Request
Reject a body that fails validation 422 Unprocessable Content
Reject missing or bad credentials 401 Unauthorized
Refuse a known caller who lacks access 403 Forbidden
Turn away a client over its rate limit 429 Too Many Requests
Trap 401 Unauthorized really means unauthenticated. Send 403 when you know the caller and still refuse.
Shape an error response Use the standard error format Content-Type: application/problem+json RFC 9457. It replaced RFC 7807.
Name its five standard fields type, title, status, detail and instance.
Report every bad field at once List each with its field name, a stable code and a message.
Tip Set the real HTTP status on the response too. Keep stack traces, SQL and hostnames out.
Trap Clients must branch on a stable code or type, never on the message text.
Retry without doing harm Pick which failures to retry Timeouts, dropped connections, 429 and 503.
Space out the retries Exponential backoff with full jitter, so clients don't all retry at once.
Retry a payment without charging twice Idempotency-Key: <uuid> Repeats get the first result.
Stop a PUT overwriting a newer edit If-Match: "abc123" Fails if the ETag changed.
Tip Keep a retry budget. Once retries pass about 10% of requests, fail fast instead.
Trap A write that timed out may already have run. Retry it only if it's idempotent or carries a key.
Auth & security prove who's calling, then limit what they can do Authenticate callers Identify a calling app X-API-Key: <key> Names the app, not the user.
Store an API key Show the user the key once, then keep only a hash and a prefix.
Check callers with no session store Authorization: Bearer <jwt> Hard to revoke before it expires.
Let an app act for a user OAuth 2.0, with scoped tokens you can revoke.
Log a user in from a mobile app or SPA Code flow with PKCE. It binds the code to the app that asked.
Trap Send keys in a header, never in the query string. URLs end up in logs.
Authorize every request Grant access by role RBAC. Code checks permissions, never role names.
Make the database filter by tenant Row-level security. Connect as a non-owner, since owners bypass it.
Trap Take the tenant id from the verified token, never from the URL or the body.
Common API attacks Name the top OWASP API risk Broken object level authorization, or BOLA.
Block injection Validate input against a schema. Use parameterized queries.
Tip BOLA is a caller changing an id to read someone else's data. Check ownership on every lookup.
Rate limiting Tell a limited client when to come back Retry-After: 30
Allow short bursts Token bucket. It refills steadily up to its size.
Count requests per clock minute Fixed window. Bursts can double at the edges.
Tip A sliding window smooths those edges. Keep every counter in a shared store like Redis.
Paging, caching & speed serve big reads fast Page, filter and sort a list Page by offset GET /users?offset=40 Any page, but deep ones are slow.
Page by cursor GET /users?cursor=abc123 Same cost every page. No jumping.
Match any of several values GET /orders?status=open,paid Commas mean OR. Separate fields mean AND.
Sort newest first GET /orders?sort=-created_at,id
Tip A leading - sorts descending. End every sort with a unique field like id, or pages repeat and skip rows.
Trap Offset pages shift when rows are inserted between requests, so items repeat or go missing.
Cache responses Let any cache keep it for an hour Cache-Control: public, max-age=3600
Keep per-user data out of shared caches Cache-Control: private
Check a cached copy is still current If-None-Match: "abc123" No change gets 304.
Cache gRPC responses In a server interceptor keyed by method and request.
Tip Caches sit in the browser, a CDN, a reverse proxy, an app cache like Redis and the database.
Make responses faster Send only the fields asked for GET /users?fields=id,name
Serve phones on slow networks Make fewer, smaller calls, or add a backend for frontend.
Scale by adding servers Stateless servers, a cache, pooled connections, then shards.
Tip Old app versions stay installed for years, so give each mobile API version a long support window.
Versions & change change the contract without breaking clients Version an API Put the version in the path GET /v1/users Clear, but it clutters URLs.
Version a gRPC service package user.v2; A new package for breaking changes.
Trap A header or media-type version needs Vary on the response, or shared caches mix up versions.
Change without breaking clients Add an optional field or endpoint Safe. Clients ignore what they don't use.
Remove, rename or retype a field Breaking. Ship a new version and run both.
Mark an endpoint deprecated Deprecation: @1788220800 RFC 9745. @ plus Unix seconds.
Say when it stops answering Sunset: Wed, 31 Mar 2027 23:59:59 GMT
Point to the replacement Link: </v2/users>; rel="successor-version"
Answer after the sunset date 410 Gone
Tip Clients must ignore unknown fields. Even an added field breaks a client that rejects them.
Trap Deprecation: true is an old draft form and no longer valid. Send a date that comes before the Sunset date.
Async & real-time work that outlasts one request Long jobs and webhooks Start a job that takes minutes 202 Accepted Plus a status URL to poll.
Prove a webhook is yours and fresh HMAC-sign the timestamp and raw body. Reject old timestamps.
Handle a receiver that's down Retry with backoff, then move the event to a dead-letter queue.
Handle the same event arriving twice Dedupe on the event id, and reply before slow work.
Trap Webhooks arrive at least once and in no fixed order. Receivers must expect duplicates.
Push updates to clients Real time Two-way Plain HTTP
Polling Ask again on a timer
Long polling Hold each request until there's news
Content-Type: text/event-stream Server-Sent Events Stream a feed or a dashboard
WebSockets Run chat, live cursors or multiplayer
yes no
Trap SSE and WebSockets pin each client to one server, so fanning out needs a pub/sub backplane.
Upload files Upload a small file Content-Type: multipart/form-data
Upload a large file Hand out a pre-signed URL. The bytes go straight to storage.
Tip Check the type, enforce a size limit and scan for viruses before anyone downloads it.
Architecture & scale where the API sits in a bigger system REST, GraphQL or gRPC HTTP cache Web page Stream
REST Build a public API with simple CRUD and heavy caching
GraphQL Serve many clients that want different shapes of data
gRPC Make fast internal calls with typed clients
yes no, or only with extra work
Tip GraphQL ends over-fetching, but a deep query can hit the database many times. Add cost limits.
Gateway or service mesh Give outside clients one front door An API gateway, for routing, auth, rate limits and logs.
Secure and retry calls between services A service mesh. Sidecar proxies add mTLS, retries and tracing.
Tip The gateway handles north-south traffic, and the mesh east-west. A small system starts with a gateway alone.
Services calling services orders stock payment shipping orchestration The orders service calls each step in turn, and undoes them if one fails.orders stock payment shipping choreography No coordinator. Each service reacts to the event the one before it published.Decouple services A queue for one consumer, an event stream for many.
Run one flow across several services A saga. Local steps, with compensations to undo them on failure.
Choose strong or eventual consistency Strong for money. Eventual for feeds and analytics.
Stay up when parts fail Survive a server dying Stateless copies behind a health-checked load balancer.
Stop one failing service taking others down A circuit breaker. It fails fast, then lets a trial call through.
Tip Put a timeout on every call, and fall back to cached or partial results when a dependency is down.
gRPC basics the contract, the wire format and the four call types Define a gRPC service Send one request, get one response rpc GetUser(Req) returns (User);
Send one request, get a stream back rpc List(Req) returns (stream User);
Stream requests, get one response rpc Upload(stream Chunk) returns (Res);
Stream both ways at once rpc Chat(stream Msg) returns (stream Msg);
Generate Go stubs and message types protoc --go_out=. --go-grpc_out=. user.proto
Trap A field's number is its name on the wire. Never change or reuse one.
Protobuf and HTTP/2 Say why gRPC uses protobuf Binary, so smaller and faster than JSON. The schema is typed.
Run many calls over one connection HTTP/2 multiplexing. It also compresses headers.
gRPC from browsers and tools Call gRPC from a browser gRPC-Web through a proxy. Unary and server streaming only.
Let tools like grpcurl list your services reflection.Register(s) grpcurl -plaintext localhost:8080 list
Trap Reflection exposes your whole schema. Keep it off, or restricted, on services the public can reach.
gRPC in production keep calls fast, safe and easy to debug Errors, deadlines and retries Report a missing record codes.NotFound Return it with status.Error.
Set a five-second deadline context.WithTimeout(ctx, 5*time.Second)
Retry brief outages "retryableStatusCodes": ["UNAVAILABLE"] In retryPolicy.
Tip The deadline caps the whole call, retries included. Retry only idempotent calls.
Metadata, interceptors and auth Run code around every call grpc.UnaryInterceptor(f)
Send a token with every call Per-call credentials, sent as authorization metadata.
Make clients prove who they are Mutual TLS, checked against your own CA, not system roots.
Reject bad requests before the handler protovalidate rules, enforced in an interceptor.
Trap Unary interceptors skip streaming calls. Register stream interceptors too.
Connections and load balancing client L4 proxy A B C per connection An L4 proxy picks a server per connection, so every call lands on A. B and C sit idle.client L7 proxy A B C per call An L7 proxy, or the client itself, picks a server for each call.Open one channel and share it grpc.NewClient(addr, opts...) It replaces the deprecated grpc.Dial.
Spread calls over every server {"loadBalancingPolicy": "round_robin"} The default is pick first.
Tune for high throughput A few pooled channels, compression and keepalive.
Trap A plain Kubernetes Service gives one virtual IP, so every call goes to one pod. Use a headless Service.
Streams and backpressure Stream results to the client stream.Send(user) The client loops on Recv.
Slow down for a slow reader Let Send block. HTTP/2 flow control pauses it.
Trap Set a deadline on every stream, or a client that stops reading holds server resources forever.
Run and debug a gRPC server Tell balancers a service is ready Register the health service and set SERVING.
Shut down without dropping calls server.GracefulStop() Set NOT_SERVING first, and call Stop if it hangs.
Trace calls across services Add OpenTelemetry's otelgrpc stats handlers on both sides.
Tip When a call fails, read its status code first, then turn up the logs with GRPC_GO_LOG_SEVERITY_LEVEL=info .
Docs, tests & monitoring prove it works, and watch it in production Document the contract Keep docs true to the code An OpenAPI spec beside the code. CI fails when they differ.
Agree the API before anyone codes it API-first. Write the spec, then generate stubs and SDKs.
Prototype fast Code-first. Generate the docs from annotations in the code.
Tip A public API also needs examples, SDKs, a sandbox and self-serve keys.
Test an API Shape the test suite A pyramid. Many unit tests, few end-to-end ones.
Catch a breaking change before deploy Consumer-driven contract tests, like Pact.
Find the breaking point A stress test, judged by p95 and error rate.
Monitor an API Name the four golden signals Latency, traffic, errors and saturation.
Follow one request through the logs X-Request-ID: <uuid>
Tip For usage analytics, record one event per request in middleware and send it off the request path.
Spot a bad API design Fix POST /getUserByEmail GET /users?email=a@b.com
Fix a 200 whose body says not found 404 Not Found
Nothing matches. Try a shorter word, or clear the search.
Practice Guided practice One question at a time, with the ones you miss coming back.
Practice 110 interview questions Full answers, from beginner to expert.
Found this useful? Pass it on.
Share on LinkedIn
Share on X
Copy link
This sheet stays free. With Pro , you can:
Every answer on this sheet. Read the full answer to all 92 questions it links, not just the 18 free ones.
My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.