Start learning free

LESSON 74 OF 173 · BACKEND: APIS WITH A DATABASE

What an Order Contains

Practice

An order can hold several products. They are in a third table, order_items: one row per product in an order, with the order_id it belongs to, the product_id, the quantity and the unit_price, the price of one item when the order was placed. A JOIN with products gives each item its name.

Such a query can find many rows. db.Query gives them all in rows, and a for rows.Next() loop reads them one at a time with rows.Scan. To add up a value over the rows, start a variable at 0 before the loop and add to it inside the loop. Here is the idea on another value, the prices of the kitchen products:

rows, _ := db.Query("SELECT price FROM products WHERE category = ?", "kitchen")
defer rows.Close()
total := 0
for rows.Next() {
    var price int
    rows.Scan(&price)
    total = total + price
}

An order's total uses unit_price, the price saved with the order, not the product's price today: when the shop changes a price, the orders already placed keep their totals. db.Query doesn't give sql.ErrNoRows when nothing matches: the loop just runs zero times. Every order has at least one item, so an items slice that is still empty after the loop means there is no such order.

Your handler must give these answers (the PUT raises the Mug's price to 15 before order 7 is read):

GET /orders/1/items   →  200  {"items": [{"name": "Mug", "quantity": 2, "unit_price": 12}, {"name": "Pen", "quantity": 5, "unit_price": 2}], "order_id": 1, "total": 34}
GET /orders/5/items   →  200  {"items": [{"name": "Teapot", "quantity": 2, "unit_price": 22}, {"name": "Lamp", "quantity": 1, "unit_price": 29}], "order_id": 5, "total": 73}
GET /orders/6/items   →  200  {"items": [{"name": "Stapler", "quantity": 1, "unit_price": 9}], "order_id": 6, "total": 9}
PUT /products/1  {"name": "Mug", "price": 15, "category": "kitchen"}  →  200  {"id": 1, "name": "Mug", "price": 15, "category": "kitchen", "stock": 10}
GET /orders/7/items   →  200  {"items": [{"name": "Mug", "quantity": 4, "unit_price": 12}, {"name": "Notebook", "quantity": 2, "unit_price": 7}], "order_id": 7, "total": 62}
GET /orders/99/items  →  404  {"error": "Order not found"}

Your task: the handler GET /orders/{id}/items, its id line and the OrderItem struct are given. Fill in the handler: read the order's items with their product names, add up the total from the saved prices, and answer 404 when no item belongs to that order.


Assignment
Follow the Coding Tutorial to fill in the GET /orders/{id}/items handler: its JOIN query, the loop that builds items and total, and the 404 for an order with no items.


Hint
db.Query never gives sql.ErrNoRows: when nothing matches, the loop runs zero times, so check len(items) == 0 after it. Start total at 0 before the loop, not inside it.


STEP 1 OF 12
    Ctrl + Enter to check