Start learning free

LESSON 21 OF 173 · BACKEND: YOUR FIRST API

Check the Input

Practice

A client can send anything: no name, a price written as text, a negative number. Never trust input. Before you store something, check it, and if it's wrong, answer 400 Bad Request with an error that tells the client what to fix. A 400 says the client made a mistake; a 500 says your server broke.

Two things about Decode help. A field the JSON doesn't have keeps the value it had before, so a missing string stays "" and a missing int stays whatever you started it with. And Decode returns an error when a value doesn't fit its field, like the text "5" for an int. Here is the idea on another route:

type Rating struct {
	Stars int `json:"stars"`
}

app.HandleFunc("POST /ratings", func(w http.ResponseWriter, r *http.Request) {
	var data Rating
	err := json.NewDecoder(r.Body).Decode(&data)
	if err != nil || data.Stars < 1 || data.Stars > 5 {
		writeJSON(w, 400, map[string]string{"error": "Stars must be a whole number from 1 to 5"})
		return
	}
	writeJSON(w, 201, data)
})

writeJSON sends the answer, but only return stops the handler, so a refused product is never stored. Your code must give, in this order:

POST /products  {"price": 5, "category": "home"}  →  400  {"error": "Name is required"}
POST /products  {"name": "", "price": 5, "category": "home"}  →  400  {"error": "Name is required"}
POST /products  {"name": "Cup", "category": "kitchen"}  →  400  {"error": "Price must be a whole number of 0 or more"}
POST /products  {"name": "Cup", "price": "5", "category": "kitchen"}  →  400  the same price error
POST /products  {"name": "Cup", "price": -1, "category": "kitchen"}  →  400  the same price error
POST /products  {"name": "Cup", "price": 4.5, "category": "kitchen"}  →  400  the same price error
POST /products  {"name": "Sticker", "price": 0, "category": "office"}  →  201  {"id": 5, "name": "Sticker", "price": 0, "category": "office"}
GET /products/count  →  200  {"count": 5}

Your task: in the POST handler, start data with a price of -1, keep the error Decode returns, and answer 400 with the right error when the name is missing or empty or the price isn't a whole number of 0 or more.


Assignment
Follow the Coding Tutorial to add the name check and the price check to the POST handler.


Hint
Each check is an if with a return inside it, right after the 400 answer. A missing price keeps the -1 data started with, and a price that isn't a whole number makes err not nil.


STEP 1 OF 8
    Ctrl + Enter to check