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.

In TypeScript, req.body has the type any, and a type you write on a constant, like const color: string = data.color;, is only a promise: TypeScript checks types when it compiles, not while the app runs. Reading a key that is missing doesn't stop the code: data.color is simply undefined when the body has no "color". So nothing refuses a bad value unless your code checks it. To check that a value is a whole number, use Number.isInteger(value): it is false for text like "5", for a decimal and for undefined. Here is the idea on another route:

app.post("/ratings", (req: Request, res: Response) => {
  const data = req.body;
  const stars: number = data.stars;
  if (!Number.isInteger(stars) || stars < 1 || stars > 5) {
    return res.status(400).json({ error: "Stars must be a whole number from 1 to 5" });
  }
  res.status(201).json({ stars: stars });
});

A return ends the function, 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 /products route, read the name and the price from data into typed constants, 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, and build the new product from the values you checked.


Assignment
Follow the Coding Tutorial to add the name check and the price check to the POST /products route.


Hint
Each check is an if with ||, and a return inside it. In the price check, write !Number.isInteger(price) before price < 0, so only whole numbers are compared with 0. Until you write the newProduct line again, TypeScript won't compile the file.


STEP 1 OF 7
    Ctrl + Enter to check