A page shows a product's photo with a tag like <img src="/products/1/photo">. The browser sends a GET to that address and draws whatever image comes back. So the shop answers the photo's bytes as they are, not JSON.
Bytes don't say what they are. The answer's Content-Type header tells the browser how to read them: image/png, image/jpeg... writeJSON always sets it to application/json; for bytes, you set it yourself with w.Header().Set, before you write anything. Then w.Write sends the bytes, and when you set no status, Go answers 200. For example, a route that answers plain text:
app.HandleFunc("GET /robots.txt", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("User-agent: *"))
})
The package mime knows the type of each file extension, and filepath.Ext cuts the extension out of a file name, dot included: filepath.Ext("report.pdf") gives ".pdf", and mime.TypeByExtension(".pdf") gives "application/pdf". When a product has no row, Scan gives sql.ErrNoRows.
After the tests upload two photos, the shop must answer:
POST /products/1/photo (photo: mug.png, 16 bytes) → 201 {"filename": "mug.png", "product_id": 1, "size": 16}
POST /products/3/photo (photo: lamp.jpg, 17 bytes) → 201 {"filename": "lamp.jpg", "product_id": 3, "size": 17}
GET /products/1/photo → 200 Content-Type: image/png, the 16 bytes
GET /products/3/photo → 200 Content-Type: image/jpeg, the 17 bytes
GET /products/2/photo → 404 {"error": "This product has no photo"}
Your task: add GET /products/{id}/photo. Look up the product's row in photos; with no row, answer 404; otherwise answer the stored bytes with status 200 and the Content-Type for the photo's file name.
Assignment
Follow the Coding Tutorial to add the route that serves a product's photo.
Hintmime and path/filepath are already imported. Pass filepath.Ext(filename) to mime.TypeByExtension. Set the header before w.Write(data): once the body is written, headers can't change anymore.
Free plan: 30 tutor messages. PRO is unlimited.
