What information do the `req` and `res` objects carry in Express, and what are the most common response methods?
Show answer — try answering out loud first
In each handler (req, res), req (request) represents what the client sends and res (response) is what you return to it. From req you read method, url, params, query, body, and headers. With res you respond using methods like res.json() (sends JSON), res.send() (sends text/HTML/JSON), res.status() (sets the HTTP code), and res.end() (closes without a body). res.status() returns the same res, so you can chain: res.status(201).json(...).
The req object contains everything that arrived from the client:
req.method: the HTTP verb,"GET","POST", etc.req.url: the requested URL, including the query string.req.params: the route params from the URL (/usuarios/:id→req.params.id).req.query: what comes after the?(?page=2→req.query.page).req.body: the body sent (JSON from a POST/PUT). It needsexpress.json().req.headers: the headers (req.headers["content-type"], etc.).
The res object is used to build the response. Key methods:
res.json(obj): sendsobjas JSON and sets the correctContent-Type.res.send(algo): sends text, HTML, or even an object (converting it to JSON).res.status(codigo): sets the status code (200, 201, 404, 500...). It doesn't send anything on its own, it only prepares the code; it returnsresfor chaining.res.end(): ends the response without a body (useful for a204 No Content).
Golden rule: for each request you must respond exactly once. Sending two responses (for example a res.json and then another one) throws an error.
const express = require("express");
const app = express();
// Required to be able to read req.body in JSON format
app.use(express.json());
// Shows the info that req carries
app.get("/inspeccionar/:id", (req, res) => {
// We read several pieces of the request
const info = {
metodo: req.method, // "GET"
url: req.url, // "/inspeccionar/7?debug=true"
parametro: req.params.id, // "7" (from the :id route)
query: req.query, // { debug: "true" } (after the ?)
userAgent: req.headers["user-agent"], // header sent by the client
};
// res.json sends the object as JSON with status 200 by default
res.json(info);
});
// Chaining example: set status and send JSON in one line
app.post("/usuarios", (req, res) => {
const nuevo = { id: 1, nombre: req.body.nombre };
// status(201) prepares the code and returns res; json sends the body
res.status(201).json(nuevo);
});
// res.send with plain text
app.get("/saludo", (req, res) => {
res.send("Hola mundo"); // Content-Type: text/html automatically
});
// res.status + res.end: respond without a body (204 = no content)
app.delete("/usuarios/:id", (req, res) => {
// ...here you would delete the user...
res.status(204).end();
});
app.listen(3000, () => {
console.log("Servidor en http://localhost:3000");
});
Testing with curl:
# We pass a route param (7) and a query (?debug=true)
curl "http://localhost:3000/inspeccionar/7?debug=true"
# POST with a JSON body; you should get 201 and the created user
curl -X POST http://localhost:3000/usuarios \
-H "Content-Type: application/json" \
-d '{"nombre":"Ana"}'
Believing that res.status(404) on its own sends the response. It doesn't: res.status() only sets the code and returns res; you have to chain a method that does send a body, like res.status(404).json({ error: "No encontrado" }) or res.status(404).end(). If you only call res.status(404), the request stays hanging because it was never closed. Another mistake is responding twice (res.json(...) and then another res.send(...)), which throws "Cannot set headers after they are sent".
"In each handler I have
reqandres.reqis what the client sends: from there I readmethod,url,paramsfor the route segments,queryfor what comes after the?,bodyfor the body, andheadersfor the headers.resis what I return: I useres.jsonto send JSON,res.sendfor text or HTML,res.statusto set the code, andres.endto close without a body. Something key:res.statusdoesn't send anything on its own, it only sets the code and returnsres, which is why I chainres.status(201).json(...). And I always respond exactly once per request, because sending two responses throws the headers-already-sent error."
What problem does this handler have and how do you fix it?
app.get("/usuarios/:id", (req, res) => {
const usuario = buscarUsuario(req.params.id);
if (!usuario) {
res.status(404);
}
res.json(usuario);
});
See answer
res.status(404) doesn't send a response, it only sets the code; the flow continues and reaches res.json(usuario), which will send undefined as JSON... with status 200, not 404. The condition didn't stop anything.
It's fixed by sending the body inside the if and halting the function with return:
app.get("/usuarios/:id", (req, res) => {
const usuario = buscarUsuario(req.params.id);
if (!usuario) {
return res.status(404).json({ error: "Usuario no encontrado" });
}
res.json(usuario);
});
The return prevents the res.json below from running and from trying to respond twice.