Clients often want to search instead of listing everything: /products?name=Mug. The part after the ? is the query string. req.query.name reads it, and is undefined when the request has no name. A query string can also send a list, like ?name=Mug&name=Lamp, so you add as string | undefined: you treat it as one text, or nothing.
Never build SQL by gluing a visitor's text into it. With "... WHERE name = '" + name + "'", the name x' OR '1'='1 turns the query into WHERE name = 'x' OR '1'='1', which is true for every row. That is SQL injection: the visitor's text becomes part of your SQL, and the same trick can read or change data they should never touch. Even an honest name like Ana's mug breaks the glued query.
A ? placeholder fixes it: the text travels separately, and the database only ever compares it as a value. For example, on a route that searches a table books:
const author = req.query.author as string;
const rows = db.prepare("SELECT title FROM books WHERE author = ?").all(author);
GET /products?name=Mug → 200 [{"id": 1, "name": "Mug", "price": 12, "category": "kitchen", "stock": 10}]
GET /products?name=Gift card → 200 [{"id": 8, "name": "Gift card", "price": 50, "category": null, "stock": 999}]
GET /products?name=x' OR '1'='1 → 200 []
GET /products?name=Ana's mug → 200 []
GET /products → 200 [… all 8 products …]
Your task: let GET /products take an optional name. Without it, answer every product, as before. With it, answer only the products with exactly that name, passing the name through a ? placeholder.
Assignment
Follow the Coding Tutorial to read the name and run the right query for it.
Hint
Declare let rows: Product[]; before the if, so both branches can set it. Use === undefined to tell a request without a name apart from one with a name. In the search, the name goes to .all(name), never inside the SQL string.
Free plan: 30 tutor messages. PRO is unlimited.
