Capstone: Designing an API for a Real Scenario
🎓 Capstone: Designing an API for a Real Scenario
The Scenario
A task-management SaaS company wants to let outside developers build integrations against their platform — a Slack bot that creates tasks from messages, a calendar sync tool, a reporting dashboard. Those integrators need to read and create tasks, and be notified the moment a task's status changes, without hammering the platform with constant polling.
Applying the Decision Framework
| Question (from Chapter 8) | Answer for This Scenario |
|---|---|
| Who's the client? | A broad, external, uncoordinated audience of third-party developers → points toward REST |
| Request/response, or something else? | Reading/creating tasks is request/response; "notify me when status changes" is not → that piece needs Webhooks |
| How complex are the client's data needs? | Mostly uniform CRUD access to tasks, not wildly varying nested shapes per integrator → plain REST is enough, GraphQL's extra complexity isn't earned here |
| What guarantees are needed? | No enterprise/transactional guarantees needed (ruling out SOAP); no internal extreme-performance requirement (ruling out gRPC) for this external-facing part |
Conclusion: REST for the main API, Webhooks for change notifications — exactly the kind of two-styles-together answer Chapter 8's worked example arrived at.
Designing the REST Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/tasks | List tasks (paginated, filterable) |
| GET | /v1/tasks/{id} | Retrieve one task |
| POST | /v1/tasks | Create a new task |
| PATCH | /v1/tasks/{id} | Partially update a task (e.g. just its status) |
| DELETE | /v1/tasks/{id} | Delete a task |
The /v1/ prefix applies Chapter 4's URL versioning strategy — the right call here since the audience is broad and external, exactly the case Chapter 4 recommended it for. PATCH rather than PUT for updates reflects Chapter 2's distinction: most real updates here (like changing just a status field) are partial, not full replacements.
Handling Creation Safely: Idempotency
Creating a Task, Safely Retryable
If an integrator's request times out and their code retries automatically, the same Idempotency-Key (Chapter 4) ensures the platform creates exactly one task, not two.
Pagination for Task Lists
Since tasks are added and completed constantly by many users at once, cursor-based pagination (Chapter 4) is the right fit — offset-based pagination would risk exactly the skipped/duplicated-row problem Chapter 4's gotcha described:
Paginating /v1/tasks
Authentication & Rate Limiting
Each request authenticates with a bearer token in the Authorization header — the token-based approach covered in depth in the Authentication & Session Security course (bc1-7), not re-taught here. Requests are capped per integrator using the X-RateLimit-* headers and 429 status introduced in Chapter 4, protecting the platform from any single integrator's runaway retry loop.
Adding Webhooks for Real-Time Notification
Rather than making integrators poll GET /v1/tasks/{id} repeatedly to detect a status change, each integrator registers a webhook URL once. When a task's status changes, the platform sends a signed event:
A task.updated Webhook
The integrator verifies X-Signature (Chapter 7's HMAC pattern) before trusting the payload, and deduplicates on evt_88f2 in case the same event is delivered more than once.
What About Internal Services?
If the platform's own task service needed to talk to its own internal search-indexing service at very low latency, gRPC (Chapter 6, with its own full course) would be the right internal choice — but that's a separate concern from this external-facing design, and folding it in here would repeat exactly the mistake Chapter 8's gotcha warned against: reaching for whichever style is already in front of you rather than asking what each specific piece of the system actually needs.
Course Recap
Across nine chapters: the client-server model and what "API" really means (Ch.1), HTTP's methods/status codes/headers (Ch.2), REST's architectural constraints (Ch.3), REST's practical design patterns (Ch.4), SOAP's formal contracts (Ch.5), the RPC lineage into gRPC (Ch.6), Webhooks (Ch.7), a decision framework (Ch.8), and this capstone applying all of it to one real design. From here, the site's API Testing & Tooling course covers how to actually test a design like this one with Postman, cURL, and more, and the dedicated gRPC course goes deep on the internal-services piece only briefly touched on above.
💻 Coding Challenges
Challenge 1: Add a Projects Resource
Tasks belong to projects. Design the REST endpoints for a new /v1/projects resource, following the same conventions (versioning, method choices, pagination) established in this capstone.
Goal: Practice extending a design consistently rather than inventing new conventions per resource.
Challenge 2: Design a task.completed Webhook
Design the webhook payload for a new task.completed event, including a plausible event id and signature header, following this chapter's task.updated example.
Goal: Practice applying the webhook payload shape and signature pattern to a new event type.
Challenge 3: Justify Cursor Pagination for /v1/tasks
Explain specifically why cursor-based pagination was chosen for /v1/tasks instead of offset/limit, referencing what would concretely go wrong with offset-based pagination given how this platform's tasks change over time.
Goal: Practice justifying a design decision with a concrete failure mode, not just a general preference.
It's easy to design an API around what happens when everything goes right — a valid request, a successful create, a clean 200. A real design also has to account for what happens when a task id doesn't exist (404), the bearer token is missing or expired (401), a required field is missing from the request body (400), or the integrator is sending requests too fast (429) — all status codes and concepts this course already covered, but easy to forget to actually design for once the "main" functionality is working. A design that only handles success is an incomplete design, however good the happy path looks.
🎉 Course Complete
That's the full API Types & Design course — from "what is an API?" through REST, SOAP, RPC/gRPC, Webhooks, a decision framework, and this final end-to-end design. Next steps from here: the API Testing & Tooling course to learn how to actually exercise an API like the one designed above, or the dedicated gRPC course to go deep on the internal-services piece this capstone only touched on briefly.