Summary
What we built
Over the past 19 lessons, we designed and built a complete bookstore API. We started with the idea that an API is a contract, and we followed that principle through every decision. Let’s look at everything the API can do.
| Pattern | Where it appears |
|---|---|
| Resource-based URLs | /books, /authors, /reviews |
| HTTP methods | GET, POST, PUT, PATCH, DELETE on each resource |
| Idempotency | PUT and DELETE are idempotent, POST supports idempotency keys |
| Safe methods | GET never modifies data |
| Status codes | 200, 201, 204, 400, 404, 409, 422, 429 |
| Error format | Consistent { error: { code, message, details? } } |
| Nested resources | /books/:id/reviews |
| Embedding | Book responses include author summary |
| Field selection | ?fields=id,title,author.name |
| Cursor pagination | ?cursor=...&limit=20 |
| Filtering | ?genre=fiction&authorId=author-1 |
| Sorting | ?sort=-publishedAt |
| Searching | ?q=hemingway |
| Versioning | /v1/books |
| Content negotiation | JSON default, CSV export |
| Rate limiting | Per-client with headers |
| Bulk operations | POST /books/bulk with partial success |
| Long-running ops | POST /reports, then poll for status |
| HATEOAS | _links on resources and pagination |
The principles behind every decision
Every choice we made in this API traces back to a principle.
URLs are resources. /books, not /getBooks. The HTTP method provides the verb. The URL provides the noun.
Status codes are meaningful. 201 for created, 204 for deleted, 409 for duplicates. Not 200 for everything. Every status code tells the client something specific.
Errors are consistent. Every error has a code and a message, using the same shape. Consumers write one error handler and it works everywhere.
Lists are paginated. Cursor-based by default. The limit is capped. Responses are wrapped in an object so metadata can be added without breaking changes.
Filters compose. ?genre=fiction&sort=-publishedAt&q=sea&limit=5. Each parameter is independent and optional. They all work together.
Changes are additive. New fields are added alongside old ones. Breaking changes get a version bump. Consumers migrate on their own schedule.
Abuse is limited. Rate limiting with transparent headers. Clients know their quota. 429 with Retry-After when they exceed it.
Long work is asynchronous. 202 Accepted for operations that take more than a few seconds. Poll for status. Retry-After tells the client when to check back.
These principles are not specific to bookstores. They work for any API. The domain changes, but the design stays the same.
What is the single most important principle from this course?
A client sends POST /books with an Idempotency-Key header. The server creates the book but the response is lost. The client retries with the same key. What should happen?