Creating and Viewing Carts
Creating and Viewing Carts
Welcome! 👋 In this lesson we’ll add the two most important “entry points” for working with carts: creating a cart, and fetching a cart by ID in a predictable, client-friendly shape.
You’ll see how the cart is modeled as a real backend resource (not just “a list of products”), and how our codebase builds a fully “hydrated” cart response that includes items and totals—even when the cart is empty. By the end, you’ll understand exactly where persistence happens (repository), where coordination happens (service), and how the API route ties everything together.
A cart is a real resource, not just a list
In this project, a cart has its own identity and lifecycle:
- It has an
id(UUID), astatus(open,checked_out,abandoned), and timestamps. - It can exist before any items are added.
- When you fetch a cart, the response is intentionally stable: the API should return
itemsandtotalsconsistently so clients don’t need special “empty cart” logic.
That stability is created in the repository layer by composing the cart from multiple queries: the cart row, its item rows, and the referenced product data.
The repository file src/lib/repositories/cartsRepo.ts is where we talk to PostgreSQL. It does SQL-in / rows-out, then maps database rows into domain objects.
Database row types and status mapping
This first chunk defines what we expect from the database and how we normalize the status string into the domain union type.
CartRowmirrors thecartstable columns exactly, usingstringforstatusbecause Postgres returns it as text. This keeps the “DB shape” separate from the “domain shape”.mapCartStatusis a small defensive layer: if the DB ever contains an unexpected status string, we fall back to'open'instead of crashing or leaking invalid data through the API.- This mapping is important because the domain type
Cart['status']is a union, and the rest of the app assumes it only ever sees valid values.
