Start learning free

LESSON 120 OF 173 · BACKEND: PAYMENTS AND OTHER SERVICES

Project: Checkout in Go

Practice

So far a purchase took several requests: the order was already in the database, POST /orders/{id}/pay charged it, and the worker sent the email later. A shop's checkout does it all in one request: the client sends the cart, and the shop creates the order, takes the payment, queues the email and answers with a receipt.

The cart has a customer and a list of items, with no prices: {"customer_id": 5, "items": [{"product_id": 3, "quantity": 2}, {"product_id": 6, "quantity": 1}]}. The shop takes each price from its own products table, never from the client, who could send any price. The order is saved as 'pending' before the payment, so a declined order stays and can be paid later.

The database picks a new row's id. db.Exec(...) gives a result, and its LastInsertId() is the id of the row the INSERT just added, as an int64. For example, on another table:

res, _ := db.Exec("INSERT INTO customers (name, email) VALUES (?, ?)", "Ion Popa", "ion@example.com")
customerID, _ := res.LastInsertId()

Your code must answer, in this order:

POST /checkout  customer 5: product 3 ×2, product 6 ×1  →  201  {"order_id": 12, "payment_id": "pay_1", "status": "paid", "total": 80}
POST /checkout  customer 2: no items                    →  400  {"error": "The cart is empty"}
POST /checkout  customer 4: product 8 ×25               →  402  {"error": "Payment declined", "order_id": 13}
POST /checkout  customer 1: product 4 ×3, product 5 ×1  →  201  {"order_id": 14, "payment_id": "pay_2", "status": "paid", "total": 21}
POST /admin/run-jobs                                    →  200  {"ran": 2}

The empty cart saves nothing. The 25 gift cards cost 1250, over the provider's limit of 1000, so order 13 stays 'pending'. No email goes out during a checkout: only when the worker runs do the customers of orders 12 and 14 get their "Your order … is paid" email.

Your task: the start of POST /checkout is in the editor. It refuses an empty cart with 400 and saves the order and its items with the shop's prices, but then writes nothing, so Go answers 200 with an empty body. Finish it: charge the total, answer 402 if the card is declined, and otherwise mark the order paid, queue its email job and answer the receipt with 201.


Assignment
Follow the Coding Tutorial to finish the checkout route step by step, reusing findOrder and what the pay route already does.


Hint
LastInsertId gives an int64 and findOrder takes an int: call findOrder(int(orderID)), and its Total is the amount to charge. Put a return after the 402, or the handler goes on and marks the declined order paid.


STEP 1 OF 11
    Ctrl + Enter to check

    Pay Checkout Project in Go

    Keep going with Go1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free