REST API Bookstore Project
Concepts become skills through practice. A complete small project joins resources, methods, status codes, validation, and security into one working design. A bookstore API makes a friendly example, because everyone understands books, customers, and orders.
The Project Goal
Design an API that lets customers browse books, place orders, and track them, while staff members manage the catalog. Build the plan on paper first. The same plan works in any language or framework.
Step 1: List the Resources
| Resource | Purpose |
|---|---|
| books | Items for sale |
| authors | People who write books |
| customers | People who buy |
| orders | Purchases by customers |
| order items | Books inside one order |
Step 2: Draw the Relationships
Author ──< Book >── Order Item >── Order >── Customer one to many many to one many to one
One author writes many books. One order holds many order items. Each order item points to one book.
Step 3: Define the Endpoints
| Method | Path | Action | Success |
|---|---|---|---|
| GET | /books | List books with filters | 200 |
| GET | /books/{id} | Read one book | 200 |
| POST | /books | Add a book (staff) | 201 |
| PATCH | /books/{id} | Update a book (staff) | 200 |
| DELETE | /books/{id} | Remove a book (staff) | 204 |
| POST | /orders | Place an order | 201 |
| GET | /orders/{id} | Read own order | 200 |
| GET | /customers/{id}/orders | List own orders | 200 |
| POST | /orders/{id}/cancellation | Cancel an order | 200 |
Step 4: Shape the Data
Book
{
"id": "b-905",
"title": "Atlas of Rivers",
"author": { "id": "a-12", "name": "Neha Rao" },
"price": { "amount": 45000, "currency": "INR" },
"stock": 14,
"publishedAt": "2025-03-14"
}
Order request
{
"items": [
{ "bookId": "b-905", "quantity": 2 },
{ "bookId": "b-117", "quantity": 1 }
]
}
Step 5: Add Search Features
GET /books?author=a-12&max_price=50000&sort=-publishedAt&limit=20&cursor=abc
Filters narrow results, sort orders them, and a cursor pages through the rest.
Step 6: Walk Through an Order
Customer ── POST /orders (Idempotency-Key) ──→ API
│ validate items and quantities
│ check stock
│ save order, reduce stock
Customer ←── 201 Created, Location: /orders/o-3001 ── API
Customer ── GET /orders/o-3001 ──→ API ──→ status: "paid"
Step 7: Plan the Errors
| Situation | Status |
|---|---|
| Invalid quantity | 422 |
| Book does not exist | 404 |
| Not enough stock | 409 |
| Missing or expired token | 401 |
| Customer reads another customer's order | 403 |
| Too many requests | 429 |
Step 8: Secure It
- Require sign-in with OAuth or JWT for orders and customer data.
- Limit catalog changes to a staff role.
- Check order ownership on every read.
- Validate every field, and reject unknown fields.
- Serve everything over HTTPS.
Step 8A: Review the Whole Design
Walk through three user stories before building anything. A shopper searches for books by an author, adds two titles, and places an order. A staff member lowers a price and checks that the change appears in the catalog. A customer cancels an order within an hour and expects the stock to return to the shelf. Trace each story across the endpoints, the data fields, and the error cases. Gaps show up quickly on paper. A missing cancellation rule or an unclear stock field costs a few minutes now and days later.
Story 1: search ──→ GET /books ──→ POST /orders ──→ GET /orders/{id}
Story 2: staff ──→ PATCH /books/{id} ──→ GET /books/{id}
Story 3: cancel ──→ POST /orders/{id}/cancellation ──→ stock restored
Step 9: Document and Test
- Describe every endpoint in an OpenAPI file.
- Build a Postman collection with one request per endpoint.
- Write tests for the main order flow and each error case.
- Add logging with a request id on every call.
Stretch Ideas
- Add book reviews as a nested collection under each book.
- Send a webhook when an order ships.
- Offer a bulk endpoint for importing a catalog.
- Version the API as /v1 from the first release.
Common Mistakes
Coding Before Designing
Rewriting endpoints after the code exists costs more than rewriting a plan. Finish the tables and diagrams first.
Forgetting Failure Cases
Real users send bad data and retry orders. Plan every error before writing handlers.
