Grokking Modern API Design Interview
Vote

0% completed

A Framework for API Design Answers

  1. The 45-Minute Framework
  1. Why the Order Matters

Choice one: Start from the caller

Choice two: Design one operation completely

  1. Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes
  1. Step 2: Model the Resources, 5 Minutes

Resource test

  1. Step 3: List the Operations, 10 Minutes

Prioritize instead of expanding

  1. Step 4: Design One Operation in Complete Detail, 10 Minutes

Request

Success response

Named failures

Retry behavior

  1. Step 5: Address the Hard Parts, 10 Minutes

Prioritize by risk

  1. Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes

Trade-off 1: Expanded task response versus separate assignee reads

Trade-off 2: Explicit assign operation versus patching an ID array

Trade-off 3: Cursor versus offset pagination

Trade-off 4: Full created resource versus identifier-only response

A final summary pattern

  1. Compressing the Framework for a 30-Minute Round

What compression changes

What compression must not change

  1. Staying Oriented When the Interviewer Interrupts

A practical whiteboard layout

Key Takeaways

API design questions feel open-ended because the interviewer can ask about almost anything: resources, URLs, field types, status codes, pagination, retries, permissions, rate limits, or versions.

Without a structure, candidates follow whatever the latest question asks about. They spend ten minutes naming endpoints, remember authentication, return to requirements, mention errors, and discover that no operation has been completed.

The solution is a fixed sequence.

Every complete answer in this course follows six steps, in this exact order:

  1. Identify the consumers and the jobs they need to finish.
  2. Model the resources.
  3. List the operations.
  4. Design one operation in complete detail.
  5. Address the hard parts, such as paging, retries, versioning, authentication, and rate limits.
  6. State the trade-offs taken and the options rejected.

The sequence is more than a memory aid. Each step gives the next step the information it needs. Consumers reveal jobs. Jobs reveal resources. Resources reveal operations. Operations give you one contract to examine deeply. That complete operation exposes the hard parts. The final trade-offs show the cost of the decisions you made.

1. The 45-Minute Framework

Use this budget when the entire 45-minute session is available for API design.

The total is 45 minutes.

This is a target, not a stopwatch. An interviewer may interrupt after three minutes or spend fifteen minutes on one operation. Follow the same sequence even when the timing changes. If the discussion jumps to retries during Step 3, answer the question and then return to the unfinished step.

The six steps with their minute budget and the artifact each one produces: consumers and jobs 5, resources 5, operations 10, one operation in full 10, the hard parts 10, and trade-offs 5. Step four is marked never cut. The total is 45 minutes.
The six steps with their minute budget and the artifact each one produces: consumers and jobs 5, resources 5, operations 10, one operation in full 10, the hard parts 10, and trade-offs 5. Step four is marked never cut. The total is 45 minutes.

2. Why the Order Matters

The framework makes two important structural choices.

Choice one: Start from the caller

The API is a promise to the caller, so the caller should shape it.

Suppose a service stores customer information in separate profile, address, preference, and subscription tables. A mobile application may need one account-summary response. A billing partner may need only the subscription and billing contact. An internal fraud service may need a stable customer identifier and a few risk-relevant fields.

If you start from the tables, all three callers inherit the storage layout. If you start from the jobs, each contract can expose the information required for its task while storage remains free to change.

This creates a useful separation:

Caller job -> Stable API promise -> Replaceable implementation

The implementation may later denormalize data, split a service, merge tables, add a cache, or change databases. Those changes should not require every caller to rewrite its code.

Choice two: Design one operation completely

Operation names contain almost no decisions. CreateTask and ListTasks do not say what creation requires, which fields are optional, whether duplicate creation is safe, what success returns, which failures exist, or how authorization differs between reading and deleting. One complete operation forces all of those decisions, which is why Step 4 keeps its ten minutes in both the 45-minute and 30-minute versions.

3. Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes

Your goal is not to collect every possible requirement. It is to gather enough context to prevent the wrong contract, which is a much smaller job.

Ask:

  • Who calls this API?
  • Is the caller first-party, internal, public, or automated?
  • What are the two or three most important jobs?
  • Which job should we optimize and design in depth?
  • Is the API new, or do existing callers constrain us?

For a team task-management API, your visible output might be:

ConsumerJobImportant consequence
First-party web and mobile clientsCreate, assign, and display tasksCommon screens should require few calls; responses should be compact and predictable.
Internal automationCreate tasks from alerts and workflowsWrites need stable external identifiers and safe retries.
Public partner integrationRead and update selected tasksCompatibility, explicit permissions, rate limits, and documentation matter.

You do not need to design for all three equally. State the scope:

"I'll optimize the initial design for the first-party application and internal automation. I'll keep the contract compatible with a later public API, but I will not design partner onboarding in detail unless you want to go there."

One sentence like that prevents a silent disagreement about what the answer is even trying to optimize.

4. Step 2: Model the Resources, 5 Minutes

Resources are the stable concepts a caller reads, creates, changes, or refers to later.

For the task-management example, the first model might include:

  • Project
  • Task
  • User
  • Comment

The model is not a database schema, so it needs no indexes, no partition keys, and not every field you store. It needs just enough structure to answer:

  • What has a stable identity?
  • What has its own lifecycle?
  • Which resource contains or refers to another?
  • Which relationships must the API expose?
  • Which object can become large and therefore needs separate paging?

A simple relationship sketch might be:

Project contains Tasks Task references Assignees (Users) Task has Comments

With the sketch on the board, ask whether each resource has earned its own operations.

Comments can be numerous, paginated, created independently, and deleted under separate permissions. They likely deserve a resource identity. An assignee relationship can sit directly on the task, or use explicit assign and unassign actions. It does not have to appear as a storage-style join record.

Resource test

For each proposed resource, ask:

"Does the caller think in terms of this concept, or does only the database think in terms of it?"

If only the database needs it, keep it behind the contract where you can still change it.

5. Step 3: List the Operations, 10 Minutes

Now turn the caller jobs from Step 1 into operations.

Do not generate five operations per resource out of habit. Ask what the caller actually needs to do, and publish only that.

For the selected task-management scope:

Seven caller jobs and the operation each one produces, with the design note attached to it. The first three are core because they carry the primary flow, and creation is the operation taken to full depth.
Seven caller jobs and the operation each one produces, with the design note attached to it. The first three are core because they carry the primary flow, and creation is the operation taken to full depth.

That is more useful than an endpoint list, because every line is tied to a caller job and carries one design note with it.

Prioritize instead of expanding

Mark operations as:

  • core: required for the primary flow;
  • supporting: needed soon but not designed deeply; or
  • out of scope: plausible but not required for this answer.

For example:

"Creation, retrieval, and listing are core. I'll mention update and comments for model completeness, but I'll design creation in depth. Bulk import, task templates, and full-text search are out of scope."

Scope control is part of the skill. A candidate who designs a small contract completely demonstrates better judgment than one who produces a large unfinished surface.

6. Step 4: Design One Operation in Complete Detail, 10 Minutes

This is the center of the interview, and the step most worth protecting when time runs short.

For one important operation, define the complete caller-visible contract:

  1. method and path;
  2. authentication or required permission;
  3. important headers;
  4. request fields, types, units, and validation;
  5. success status and headers;
  6. response body;
  7. named failure cases with status codes;
  8. machine-readable error body; and
  9. retry or idempotency behavior.

Use task creation as the deep operation.

Request

POST /v1/projects/prj_123/tasks Authorization: Bearer <token> Idempotency-Key: c990fbf6-2e5c-41b8-b983-bfe08116e91a Content-Type: application/json
{ "title": "Prepare launch checklist", "description": "Cover monitoring, rollback, and support ownership.", "assignee_ids": ["usr_17", "usr_42"], "due_at": "<RFC 3339 UTC timestamp>", "external_id": "alert-88421" }

Define the fields rather than leaving an interviewer to assume them:

FieldRequired?TypeRule
titleYesString1 to 200 characters after trimming.
descriptionNoStringMaximum 10,000 characters. Omission means no description.
assignee_idsNoArray of user IDsNo duplicates; every user must be assignable in the project.
due_atNoRFC 3339 timestampMust include an offset; stored and returned in UTC.
external_idNoStringUnique within the caller and project; useful for reconciliation.

Notice the contract decisions contained in this table. A title is not merely "a string." It has a length rule. A timestamp includes a format and timezone expectation. An omitted description is not automatically the same as null. An external identifier has a uniqueness scope.

Success response

HTTP/1.1 201 Created Location: /v1/tasks/tsk_789
{ "id": "tsk_789", "project_id": "prj_123", "title": "Prepare launch checklist", "description": "Cover monitoring, rollback, and support ownership.", "status": "open", "assignees": [ { "id": "usr_17", "display_name": "Ari Chen" }, { "id": "usr_42", "display_name": "Sam Rivera" } ], "due_at": "<RFC 3339 UTC timestamp>", "external_id": "alert-88421", "version": 1, "created_at": "<RFC 3339 UTC timestamp>", "updated_at": "<RFC 3339 UTC timestamp>" }

201 Created states that a new resource exists. Location identifies it. The full representation lets a first-party client render the result without an immediate read. The version field can support later concurrency control.

Named failures

Every failure names what the caller should do about it, rather than only what went wrong.

Eight named failures for task creation. Each carries a status code, a stable machine-readable error code, the condition that produces it, and the action the caller should take next, because a failure the caller cannot act on is an unfinished contract.
Eight named failures for task creation. Each carries a status code, a stable machine-readable error code, the condition that produces it, and the action the caller should take next, because a failure the caller cannot act on is an unfinished contract.

A consistent error body might be:

{ "error": { "code": "invalid_assignee", "message": "User usr_42 cannot be assigned to this project.", "field": "assignee_ids[1]", "request_id": "req_91a8" } }

Retry behavior

If the caller times out it cannot know whether the task was created, and repeating an unprotected POST may create a second one.

The Idempotency-Key makes retry behavior explicit:

  • same key and same request body: return the original result;
  • same key and different body: return 400 idempotency_key_reused;
  • new key: treat as a new creation attempt.

You do not need to design the idempotency storage during an API round unless somebody asks, because the caller-visible promise is the part being graded.

7. Step 5: Address the Hard Parts, 10 Minutes

The hard parts are cross-cutting decisions that affect several operations.

Common topics include:

  • paging and filtering;
  • retries and idempotency;
  • authentication and authorization;
  • rate limits;
  • versioning and compatibility;
  • concurrency;
  • asynchronous work;
  • caching;
  • consistency guarantees; and
  • multi-tenancy.

Do not recite all of them. Choose the ones your own requirements and your deep operation actually created.

For the task API, five relevant decisions might be:

Five hard parts for the task API: pagination, safe retries, authorization, rate limits, and concurrency. Each shows the decision taken and the reason that decision fits this question rather than a general checklist.
Five hard parts for the task API: pagination, safe retries, authorization, rate limits, and concurrency. Each shows the decision taken and the reason that decision fits this question rather than a general checklist.

Then explain behavior at the contract boundary.

For example:

"Task lists use an opaque next_cursor. Filters are repeated on every request, and the cursor is valid only for the same filter and sort. The response does not promise a total count because calculating an exact count may be expensive and can become stale immediately."

Or:

"An update carries the ETag from the last read in an If-Match header. If another writer changed the task, the server returns 412 Precondition Failed so the client can reload before deciding whether to retry."

Prioritize by risk

When time is short, choose the hard parts most likely to cause duplicate work, data exposure, wrong client behavior, or future incompatibility.

For a public write API, authentication, authorization, idempotency, rate limits, and versioning may dominate. For a list-heavy first-party application, paging, filtering, payload size, and caching may dominate. For long-running work, asynchronous state and completion delivery may dominate.

Name several caller-visible decisions, each connected to a requirement. "We will have rate limiting" is not enough: state who is limited, what happens at the limit, and how the caller recovers.

8. Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes

Use the final minutes to make your judgment visible to somebody who has to score it.

Walk back through the important decisions and name what each one gave up.

For the task API:

Trade-off 1: Expanded task response versus separate assignee reads

"I included compact assignee summaries in the task response so the first-party client can render the common screen without additional reads. The cost is duplicated user data and a larger payload. I accept that for item reads but would keep large task lists more compact."

Trade-off 2: Explicit assign operation versus patching an ID array

"I chose an explicit assignment operation instead of treating assignees as a generic replaceable array. This adds an operation, but it gives assignment its own permissions, duplicate behavior, audit event, and errors."

Trade-off 3: Cursor versus offset pagination

"I chose cursor pagination because tasks can be inserted and reordered while a caller is paging. The cost is that callers cannot jump to an arbitrary page number."

Trade-off 4: Full created resource versus identifier-only response

"Creation returns the full task so the client does not need an immediate read. The cost is a larger response and more fields in the compatibility surface."

A final summary pattern

Close with:

"The design optimizes the first-party task flow and safe automation writes. I gave up some payload efficiency and surface minimalism to reduce client calls and make state transitions explicit. If the primary consumer changed to a high-volume public integration, I would revisit the expanded representations and limits."

A statement like that reminds the interviewer the design follows your stated requirements, rather than claiming to be optimal for everybody.

9. Compressing the Framework for a 30-Minute Round

For a 30-minute round, halve every step except Step 4, which still gets its full ten minutes.

The compressed steps total 27.5 minutes, leaving 2.5 minutes for interviewer questions and transitions.

What compression changes

In 30 minutes you identify one primary caller rather than every consumer, model only the resources the selected flow needs, list three to five operations rather than the full surface, discuss two or three hard parts rather than a checklist, and state two precise trade-offs. Step 4 is untouched.

What compression must not change

Never reduce Step 4 to a method and a path, because that is the evidence the round exists to collect.

The deep operation is where the interviewer sees field design, success behavior, failures, retries, and consistency working together. If you halve every step equally, you may finish on time but provide no strong evidence.

When a round is unexpectedly shortened, protect depth by cutting breadth instead.

Keep: one caller, one job, a small resource model, a few operations, one complete operation, the two hardest concerns, and two trade-offs.

Remove first: secondary callers, rare operations, speculative features, and long debates about naming.

The 45-minute and 30-minute budgets side by side. Every step halves except step 4, the complete operation, which keeps its full ten minutes. The compressed steps total 27.5 minutes and leave 2.5 minutes of buffer for clarification and transitions.
The 45-minute and 30-minute budgets side by side. Every step halves except step 4, the complete operation, which keeps its full ten minutes. The compressed steps total 27.5 minutes and leave 2.5 minutes of buffer for clarification and transitions.

10. Staying Oriented When the Interviewer Interrupts

Interviewers interrupt for good reasons: to test one decision, to redirect the scope, or to give you information you were missing.

Answer the question directly, then restore the structure:

"That covers the retry behavior. I was listing the core operations, so I'll finish that list and then design creation in detail."

Keep a small six-line checklist visible:

1. Consumers and jobs [done] 2. Resources [done] 3. Operations [in progress] 4. One operation in full 5. Hard parts 6. Trade-offs

That is not a script to follow mechanically. It is a reference that stops one interruption from becoming the rest of the interview.

A practical whiteboard layout

Reserve the areas before you begin, as laid out in the diagram below. The layout makes progress visible and reduces rewriting.

A whiteboard divided into six regions. Callers and jobs, resources, and operations stay small along the top. One operation in full takes the largest region. The hard parts run down the right side and the trade-offs across the bottom.
A whiteboard divided into six regions. Callers and jobs, resources, and operations stay small along the top. One operation in full takes the largest region. The hard parts run down the right side and the trade-offs across the bottom.

Key Takeaways

  • Every answer in the course follows six steps in this exact order: consumers and jobs, resources, operations, one complete operation, hard parts, and trade-offs.
  • The 45-minute budget is 5 + 5 + 10 + 10 + 10 + 5 minutes.
  • Starting from the caller keeps the published promise stable while storage and implementation remain free to change.
  • Operation names contain almost no decisions; one complete operation exposes inputs, outputs, status codes, failures, and retry behavior.
  • Step 5 should cover the hard parts created by the requirements, not every API topic you remember.
  • Trade-offs should name the selected option, rejected alternative, benefit, and accepted cost.
  • For a 30-minute round, halve every step except Step 4, which remains ten minutes; the resulting 27.5-minute plan leaves a 2.5-minute buffer.
  • When you lose time, reduce breadth before depth.

You now have the structure for a complete answer. The next lesson goes deeper into Step 1: how to identify the caller, ask requirements that settle real API decisions, and derive a contract by writing the client code you wish existed.

On This Page

  1. The 45-Minute Framework
  1. Why the Order Matters

Choice one: Start from the caller

Choice two: Design one operation completely

  1. Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes
  1. Step 2: Model the Resources, 5 Minutes

Resource test

  1. Step 3: List the Operations, 10 Minutes

Prioritize instead of expanding

  1. Step 4: Design One Operation in Complete Detail, 10 Minutes

Request

Success response

Named failures

Retry behavior

  1. Step 5: Address the Hard Parts, 10 Minutes

Prioritize by risk

  1. Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes

Trade-off 1: Expanded task response versus separate assignee reads

Trade-off 2: Explicit assign operation versus patching an ID array

Trade-off 3: Cursor versus offset pagination

Trade-off 4: Full created resource versus identifier-only response

A final summary pattern

  1. Compressing the Framework for a 30-Minute Round

What compression changes

What compression must not change

  1. Staying Oriented When the Interviewer Interrupts

A practical whiteboard layout

Key Takeaways