An AI assistant wrote product_label, the text for the shop's shelf: GET /products/1/label answers {"label": "Mug (kitchen)"}. It put its code in a try, which is a good idea: when something fails, the route still answers. But look at what its except sends back:
@app.get("/products/<int:product_id>/label")
def product_label(product_id):
query = "SELECT name, category FROM products WHERE id = ?"
try:
row = db.execute(query, (product_id,)).fetchone()
label = row["name"] + " (" + row["category"] + ")"
return jsonify({"label": label})
except Exception as error:
return jsonify({"error": str(error), "sql": query, "trace": traceback.format_exc()}), 500
That answer goes to whoever made the request. It holds the error's text, the SQL query and the stack trace: the files, line numbers and lines of code that led to the crash. A customer can't do anything with it. An attacker can: table names, column names and your code are a free map for finding the next hole.
The rule: the details go to the log, which only you read, and the visitor gets a short safe message. Here it is on another route:
except Exception as error:
logging.error("order %s failed: %s", order_id, error)
return jsonify({"error": "Please try again later"}), 500
A missing product is not a server error, so it answers 404, not 500. Your rewrite must give these answers (product 8 is a Gift card with no category, a bug nobody had found yet):
GET /products/1/label → 200 {"label": "Mug (kitchen)"}
GET /products/6/label → 200 {"label": "Teapot (kitchen)"}
GET /products/8/label → 500 {"error": "Something went wrong on our side"}
GET /products/99/label → 404 {"error": "Product not found"}
The check then reads your log through /_test/log, a route it adds only for the test, and expects one line: ERROR GET /products/8/label failed: can only concatenate str (not "NoneType") to str.
Your task: rewrite product_label so any error answers only {"error": "Something went wrong on our side"} with 500 and logs the method, the path and the error, while a missing product answers 404.
Assignment
Follow the Coding Tutorial to rewrite product_label with a try that builds the label and an except that logs the details and answers a safe message.
Hint
Indentation matters: the except sits at the depth of try:, and the 404 check sits inside the try, right below the row line. Pass logging.error the text "%s %s failed: %s", then the three values in order.
Free plan: 30 tutor messages. PRO is unlimited.
