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

ResourcePurpose
booksItems for sale
authorsPeople who write books
customersPeople who buy
ordersPurchases by customers
order itemsBooks 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

MethodPathActionSuccess
GET/booksList books with filters200
GET/books/{id}Read one book200
POST/booksAdd a book (staff)201
PATCH/books/{id}Update a book (staff)200
DELETE/books/{id}Remove a book (staff)204
POST/ordersPlace an order201
GET/orders/{id}Read own order200
GET/customers/{id}/ordersList own orders200
POST/orders/{id}/cancellationCancel an order200

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

SituationStatus
Invalid quantity422
Book does not exist404
Not enough stock409
Missing or expired token401
Customer reads another customer's order403
Too many requests429

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.