Start learning free

LESSON 159 OF 173 · BACKEND: BACKEND WITH AI

The AI Left the Door Open

Practice

An AI assistant wrote the route the shop's admin uses to delete a product. Here is the AI's version:

app.HandleFunc("DELETE /products/{id}", func(w http.ResponseWriter, r *http.Request) {
	id, _ := strconv.Atoi(r.PathValue("id"))
	res, _ := db.Exec("DELETE FROM products WHERE id = ?", id)
	changed, _ := res.RowsAffected()
	if changed == 0 {
		writeJSON(w, 404, map[string]string{"error": "Product not found"})
		return
	}
	w.WriteHeader(204)
})

Every line is right, and a quick try works. The hole is a line that isn't there: the handler never asks who is calling, so anyone on the internet can delete every product.

A route that changes data checks the caller first, and there are two ways to refuse. 401 means "we don't know who you are": no token, or a token the shop never gave out. 403 Forbidden means "we know who you are, and you may not do this". The helper currentRole(r) reads the token from the Authorization header and gives that user's role from the map tokens, or "". Each refusal ends with return: writing an answer doesn't stop a Go handler, and the delete below it would still run. Here is the first check on another route:

app.HandleFunc("GET /account", func(w http.ResponseWriter, r *http.Request) {
	role := currentRole(r)
	if role == "" {
		writeJSON(w, 401, map[string]string{"error": "Login required"})
		return
	}
	writeJSON(w, 200, map[string]string{"role": role})
})

The tests run in this order, on one database:

DELETE /products/8   (no token)                →  401  {"error": "Login required"}
DELETE /products/8   Bearer ana-token-123      →  403  {"error": "Admins only"}
GET    /products/8                             →  200  {"id": 8, "name": "Gift card", "price": 50, "category": null, "stock": 999}
DELETE /products/8   Bearer admin-token-456    →  204  (empty)
GET    /products/8                             →  404  {"error": "Product not found"}
DELETE /products/8   Bearer admin-token-456    →  404  {"error": "Product not found"}
DELETE /products/3   Bearer let-me-in          →  401  {"error": "Login required"}
DELETE /products/99  (no token)                →  401  {"error": "Login required"}
GET    /products/3                             →  200  {"id": 3, "name": "Lamp", "price": 29, "category": "home", "stock": 1}

Your task: rewrite the DELETE /products/{id} handler. Delete the product and answer 204, or 404 if there was none. Then add the checks at the top: 401 {"error": "Login required"} when the role is "", and 403 {"error": "Admins only"} when the role isn't "admin", each followed by return.


Assignment
Follow the Coding Tutorial to rewrite the delete handler so only the admin can delete a product.


Hint
Both checks go before db.Exec: the delete is saved the moment it runs, whatever you answer after it. The 401 check comes first, then role != "admin" for the 403, and each if ends with return.


STEP 1 OF 12
    Ctrl + Enter to check