What is routing in Express and how do you define routes with dynamic parameters like `/usuarios/:id`?
Show answer — try answering out loud first
Routing is deciding which code responds based on the HTTP method and the URL of the request. In Express you define routes with methods like app.get, app.post, app.put, and app.delete, passing them a route and a handler function (req, res) => {}. For dynamic parts of the URL you use route params with a colon, for example /usuarios/:id, and you read them from req.params.id.
A route in Express has three pieces:
- The HTTP method:
app.get(read),app.post(create),app.put(update),app.delete(delete). - The path (the URL): a string like
"/usuarios"or"/usuarios/:id". - The handler: the
(req, res) => {}function that runs when that combination matches.
About route params:
- A segment that starts with
:is a wildcard that captures whatever comes there. - In
/usuarios/:id, if someone requests/usuarios/42, thenreq.params.idequals"42". - Watch out: params always arrive as a string, even if they look like numbers.
- You can have several:
/usuarios/:userId/posts/:postIdgivesreq.params.userIdandreq.params.postId.
Express evaluates routes in the order you declare them and uses the first one that matches.
const express = require("express");
const app = express();
// Middleware needed to read JSON from the body in the POST (we use it further down)
app.use(express.json());
// In-memory "database" for the example
let usuarios = [
{ id: 1, nombre: "Ana" },
{ id: 2, nombre: "Luis" },
];
// GET /usuarios -> returns ALL users
app.get("/usuarios", (req, res) => {
res.json(usuarios);
});
// GET /usuarios/:id -> returns ONE user based on the id in the URL
app.get("/usuarios/:id", (req, res) => {
// req.params.id arrives as a string, we convert it to a number
const id = Number(req.params.id);
const usuario = usuarios.find((u) => u.id === id);
// If it doesn't exist, we respond with 404
if (!usuario) {
return res.status(404).json({ error: "Usuario no encontrado" });
}
res.json(usuario);
});
// POST /usuarios -> creates a new user with the data from the body
app.post("/usuarios", (req, res) => {
const nuevo = {
id: usuarios.length + 1,
nombre: req.body.nombre,
};
usuarios.push(nuevo);
// 201 = "Created", the correct response when creating a resource
res.status(201).json(nuevo);
});
app.listen(3000, () => {
console.log("Servidor en http://localhost:3000");
});
You can test the routes with curl:
# Fetch all users
curl http://localhost:3000/usuarios
# Fetch the user with id 1
curl http://localhost:3000/usuarios/1
# Create a new user (sending JSON in the body)
curl -X POST http://localhost:3000/usuarios \
-H "Content-Type: application/json" \
-d '{"nombre":"Marta"}'
Confusing the order of the routes or thinking that req.params.id is a number. Two typical mistakes:
- Comparing
req.params.id === 1(number) when it's actually"1"(string). Always convert it withNumber(...)before comparing. - Declaring a specific route after a generic one. For example, if you put
/usuarios/:idbefore/usuarios/nuevo, the request to/usuarios/nuevowill fall into:idwithid = "nuevo". Fixed, specific routes go before dynamic ones.
"Routing is associating an HTTP method plus a URL with a function that responds. In Express I use
app.get,app.post,app.put, andapp.delete, passing them the path and a handler(req, res). For dynamic parts of the URL I use route params with a colon, like/usuarios/:id, and I read them fromreq.params.id. Something important: params always arrive as strings, so if I need to compare against a numeric id I convert it withNumber. I also watch the order: Express uses the first route that matches, so specific routes go before dynamic ones."
You have these two routes declared in this order:
app.get("/productos/:id", (req, res) => res.send("dinámica"));
app.get("/productos/ofertas", (req, res) => res.send("ofertas"));
If someone requests GET /productos/ofertas, what does it respond and why? How do you fix it?
See answer
It responds "dinámica". Since Express evaluates routes in order and uses the first one that matches, /productos/:id captures ofertas in req.params.id before reaching the specific route. The second route never runs.
It's fixed by declaring the specific route before the dynamic one:
app.get("/productos/ofertas", (req, res) => res.send("ofertas"));
app.get("/productos/:id", (req, res) => res.send("dinámica"));