Designing the Coffee Shop API - A Practical Blueprint

A good API design doesn’t start with code. It starts with modeling real-world interactions and making thoughtful design choices that allow different software components to communicate clearly and consistently.

In this article, we’ll walk through designing a Coffee Shop API by applying the principles we learned in previous article. This won’t involve code just design decisions that shape a future-proof interface.


Step 1: Think in Real-World Terms

Mainly think about → Participants (who will use the app) and Activities (what will they do with the app)

Participants

  • Customer - wants to place orders and view the menu
  • Cashier - helps place orders on behalf of customers

Activities

  • Customer browses coffee options
  • Customer builds/modifies a cart
  • Customer places or cancels an order

Step 2: Define Requirements

Let’s identify what the API must do:

Functional Requirements

  • Browse menu, look at a specific item
  • Add/remove/clear items in a cart
  • Place/cancel an order

Non-Functional Requirements

  • Secure endpoints via authentication
  • Scalable and simple to maintain

Based on our requirements, we can identify entities of your API →

menu , cart and order


Step 3: Defining Architecture of API

Architectural Style: REST

We choose REST over HTTP for this API because it’s resource-oriented ( ideal for entities like menucart, and order ) on top of that it fits CRUD style well.

Data Format: JSON

JSON as it’s readable and sufficient for our domain.

Protocol: HTTP/1.1

We wont need HTTP-2 and above as there is no need of multiplexing or streaming. Our only requirement is a persistent connections (useful for cart/order updates)

Map Resources to HTTP Verbs and Endpoints

Based on activities, we define the resources and the operations each supports. We also chose Versioning technique and Endpoints based on that.

ResourceActionHTTP MethodEndpoint
menuView menuGET/v1/menu
Get a item detailsGET/v1/menu/items/{itemId}
cartView cartGET/v1/cart/
Add item to cartPOST/v1/cart/items/
Remove item from cartDELETE/v1/cart/items/
Clear cartDELETE/v1/cart/
orderPlace orderPOST/v1/order
View orderGET/v1/order/{orderId}
Cancel orderDELETE/v1/order/{orderId}

Step 4: Mock & Prototype Before Coding

Before implementing in code, create static mock responses (JSON) for each endpoint. Validate naming, structure, and flow (tools like Swagger/OpenAPI, Postman mock server) might help.

In our case, we just take example requests:

  • Looking at cappuccino details →
// GET /v1/menu/items/123
{
  "id": "123",
  "name": "Cappuccino",
  "price": 140
}
  • Adding cappuccino to cart →
// POST /v1/cart/items
{
  "itemId": "123",
  "quantity": 1,
}

Similarly we can mock all the API endpoints to find wholes in our design.


Step 5: Security

We can do a simple Authentication using JWT tokens as it is made for a small coffee shop. Can add Authorization levels as Customer is allowed to GET menu, Add to Cart and Post Order but only Cashier can cancel order once places, as that is a special case.


Step 6: API Evolvution

Design should accommodate change, we can add filters (GET /v1/orders?status=cancelled&date=today) or add new endpoints (e.g., /v1/customer/preferences) without breaking older versions


Final Summary

Using this simple example we saw a whole timeline of how decisions are made while building a API. We went from identifying entities, choosing Architecture, mapping endpoints and then later we develop. This design-first approach ensures our API is scalable, secure, and easy to use before writing a single line of code.