Start learning free

LESSON 31 OF 58 · FULL-STACK: CART AND CHECKOUT

Never Trust the Client's Total

Practice

The storefront runs in the visitor's browser, and anything that runs there can be changed. With the browser's dev tools, curl or a short script, anyone can send POST /api/checkout with any JSON they like, even "total": 1. So the server never takes a price or a total from req.body. It takes them from its own database.

The given cartOf(userId) already does that: it joins cart_items with products, so every item's price and the cart's total come from shop.db. Now checkout turns that cart into an order: one row in orders, and one row per product in order_items with the unit_price paid. Ending an INSERT with RETURNING id and running it with .get() gives back the new row's id. Here it is on another table:

app.post("/api/reviews", requireLogin, (req, res) => {
  const review = db.prepare("INSERT INTO reviews (user_id, text) VALUES (?, ?) RETURNING id").get(req.user.id, req.body.text);
  res.status(201).json({ id: review.id });
});

The author comes from the session (req.user.id), not from the request body. The check logs in as Ana on the page, adds the Mug ($12) and the Lamp ($29) and places the order. Then Ben sends his own request with a total of 1:

> click "Place order"  →  POST /api/checkout -> 201
                          status: Order 8 placed: $41
                          link: Cart (0) -> /cart
POST /api/checkout {"name": "Ben Ortiz", …, "total": 1}  →  201  {"id": 9, "total": 41}
the new orders in shop.db:  8 | ana@example.com | pending | 41
                            9 | ben@example.com | pending | 41
their items:  order 8 and order 9: Mug at 12, Lamp at 29

Your task: in server/app.js, below the form checks of POST /api/checkout, find the customer, insert a pending order, insert an order_items row for each cart item at the database's price, then empty the user's cart.


Assignment
Follow the Coding Tutorial to save the order in POST /api/checkout: the customer, a pending order, one order_items row per cart item priced from the database, and then an empty cart.


Hint
Use item.price (read by cartOf from the products table) as unit_price, and never anything from req.body. INSERT … RETURNING id with .get() gives you order.id.


STEP 1 OF 5
    Ctrl + Enter to check