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), a status (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 items and totals consistently 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.

// src/lib/repositories/cartsRepo.ts
export interface CartRow {
  id: string;
  status: string;
  created_at: string;
  updated_at: string;
}

function mapCartStatus(status: string): Cart['status'] {
  return ['open', 'checked_out', 'abandoned'].includes(status) ? (status as Cart['status']) : 'open';
}
  • CartRow mirrors the carts table columns exactly, using string for status because Postgres returns it as text. This keeps the “DB shape” separate from the “domain shape”.
  • mapCartStatus is 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.
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal