Suggest an editImprove this articleRefine the answer for “What are the req and res objects in Express.js?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`req`** and **`res`** are the request and response objects Express passes to every route handler. `req` holds incoming data: URL params (`req.params`), query strings (`req.query`), headers, and body. `res` sends the reply: `res.json()` for APIs, `res.status()` to set codes, `res.redirect()` for redirects. ```js app.get('/user/:id', (req, res) => { res.status(200).json({ userId: req.params.id }); }); ``` **Key rule:** register `express.json()` before routes, or `req.body` will be `undefined`.Shown above the full answer for quick recall.Answer (EN)Image**`req`** and **`res`** are the two objects Express passes into every route handler. `req` holds all incoming HTTP data. `res` gives you the tools to send a reply. ## Theory ### TL;DR - `req` = incoming data: URL params, query string, headers, body - `res` = reply toolkit: `.json()`, `.status()`, `.redirect()`, `.send()` - `req` is read-only by convention; `res` is write-only by design - Body parsing: `express.json()` must come before routes, or `req.body` is `undefined` - Send a response once per request, always `return` on early exits ### Quick example ```js const express = require('express'); const app = express(); app.use(express.json()); // populates req.body app.get('/user/:id', (req, res) => { const id = req.params.id; // "123" from URL segment const name = req.query.name; // "Alice" from ?name=Alice const token = req.get('Authorization'); // request header value res.status(200).json({ id, name }); // sends JSON response }); app.listen(3000); // GET /user/123?name=Alice → { "id": "123", "name": "Alice" } ``` `req` pulls three separate pieces of data from one URL. `res` sends one structured reply. That split is the whole model. ### What req holds `req` is built on Node's `http.IncomingMessage`, but Express adds parsed properties on top. The properties you'll use in most handlers: - `req.params` - URL segments matched by the route pattern (`/user/:id` → `req.params.id`) - `req.query` - query string as an object (`?page=2&limit=10` → `req.query.page`) - `req.body` - parsed request payload, available after `express.json()` or `express.urlencoded()` - `req.headers` / `req.get('Name')` - incoming headers - `req.method`, `req.path`, `req.protocol`, `req.ip` - request metadata Middleware can also attach custom properties. Passport.js sets `req.user`, Multer sets `req.file`, and you can assign your own inside any custom middleware function. ### What res does `res` is built on Node's `http.ServerResponse`, extended with Express helpers. Core methods: - `res.json(data)` - sends JSON with `Content-Type: application/json` - `res.send(text)` - sends text or HTML, auto-detects content type - `res.status(code)` - sets HTTP status, returns `res` for chaining - `res.redirect('/path')` - sends a 302 redirect; use `res.redirect(301, '/path')` for permanent - `res.sendFile('/abs/path')` - streams a file to the client - `res.set('Header', 'value')` - sets a response header Most `res` methods return `res` itself, so chaining works: `res.status(201).json({ ok: true })`. `res.locals` is a plain object that lives for one request cycle. Middleware writes data there, route handlers read it: ```js app.use((req, res, next) => { res.locals.requestId = crypto.randomUUID(); next(); }); app.get('/profile', (req, res) => { res.json({ requestId: res.locals.requestId }); }); ``` ### When to use what - POST or PATCH data → `req.body` (after body-parser middleware) - Resource IDs in URL → `req.params` - Filters, sorting, pagination → `req.query` - Auth tokens → `req.get('Authorization')` - JSON API response → `res.json()` - Error responses → `res.status(400).json({ error: '...' })` - Redirects → `res.redirect('/path')` ### Common mistakes **Accessing `req.body` without a body parser** ```js // Wrong: req.body is undefined app.post('/login', (req, res) => { console.log(req.body); // undefined }); // Fix: register before routes app.use(express.json()); ``` **Missing `return` on early response calls** ```js // Wrong: sends two responses, throws "Cannot set headers after they are sent" app.get('/user/:id', (req, res) => { if (!req.params.id) res.status(400).send('No ID'); res.json({ ok: true }); // always runs }); // Fix app.get('/user/:id', (req, res) => { if (!req.params.id) return res.status(400).send('No ID'); res.json({ ok: true }); }); ``` This is the most common Express bug I see in code reviews. The first response goes out fine, but the handler keeps running and crashes on the second `res` call. **Calling `res.json()` after `res.write()`** Once you start streaming with `res.write()`, headers are already sent. Calling `res.json()` afterward throws an error. Finish streaming with `res.end()` only. **Logging full `req.body` in production** ```js // Leaks passwords and PII to your logs console.log(req.body); // Log only what you need console.log({ email: req.body.email }); ``` ### Real-world usage - Stripe webhooks: read event from `req.body`, reply with `res.status(200).end()` immediately to avoid webhook timeout - Passport.js: read `req.user` (attached by the auth middleware), then `res.redirect('/dashboard')` - File uploads with Multer: access `req.file.path` after the upload middleware runs - Session cookies: read `req.cookies.sessionId` with cookie-parser, set a new one via `res.cookie('token', value, { httpOnly: true })` ### Follow-up questions **Q:** What is the difference between `req.params`, `req.query`, and `req.body`? **A:** `req.params` comes from named URL segments like `/user/:id`. `req.query` comes from the query string `?key=val`. `req.body` comes from the POST or PUT request payload and needs a parser middleware to be available. **Q:** What happens if you call `res.send()` twice? **A:** Express throws `ERR_HTTP_HEADERS_SENT`. The first call closes the response stream. Always `return` after any `res` call that ends the handler. **Q:** How does `express.json()` populate `req.body` internally? **A:** It listens to the raw `data` and `end` events on `req`, collects chunks into a buffer, then calls `JSON.parse()` on the result. The default size limit is 100kb, which prevents memory exhaustion from large payloads. **Q:** How do you get the real client IP when Express sits behind an Nginx proxy? **A:** Set `app.set('trust proxy', 1)`, then read `req.ip`. Without that setting, Express reads the proxy server's own address instead of the `X-Forwarded-For` header value. ## Examples ### Product lookup: params and query together ```js const express = require('express'); const app = express(); app.get('/products/:id', (req, res) => { const productId = req.params.id; const currency = req.query.currency || 'USD'; // In real code, fetch from DB here res.json({ productId, currency }); // GET /products/42?currency=EUR → { "productId": "42", "currency": "EUR" } }); app.listen(3000); ``` Clean GET pattern: `req.params` for the resource identifier, `req.query` for options, `res.json()` for the reply. ### Login handler: body validation with early returns ```js app.use(express.json()); app.post('/login', (req, res) => { const { email, password } = req.body; if (!email || !password) { return res.status(400).json({ error: 'Missing credentials' }); } if (email === 'user@example.com' && password === 'secret') { return res.json({ token: 'jwt-token', user: { email } }); } res.status(401).json({ error: 'Invalid credentials' }); }); ``` Every early exit uses `return`. Without it, Node tries to send a second response after the if-block exits, which crashes the request with the headers-already-sent error.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.