Request and Response
Every route handler gets two objects: req, describing what the client sent, and res, the tools to answer. Knowing their most useful properties makes handlers short and clear.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Read params, query, body and headers from req
- Send JSON, text, files and redirects with res
- Set status codes and headers
- Set and read cookies
Explanation#
req.params (route segments), req.query (query string), req.body (parsed body, needs express.json), req.get("Header") / req.headers, req.ip, req.method, req.path.
res.status(code) sets the status; res.json(obj) sends JSON; res.send(text) sends text or HTML; res.sendStatus(204) sends only a status; res.end() finishes with no body.
res.set("Header", value) or res.setHeader adds headers; res.location(url) sets Location for 201 responses; res.redirect(302, url) redirects.
res.cookie("name", value, { httpOnly: true, secure: true, sameSite: "lax", maxAge }) sets a cookie; res.clearCookie clears it. Reading cookies needs the cookie-parser middleware (or parsing req.headers.cookie).
Send exactly one response per request — return after res.json/res.send in branches.
Syntax#
app.post('/api/orders/:shopId', (req, res) => {
const { shopId } = req.params;
const { coupon } = req.query;
const { items } = req.body;
res.status(201).location('/api/orders/7').json({ id: 7 });
});
Code example: Reading everything from req, answering with res#
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/shops/:shopId/orders', (req, res) => {
const order = {
shop: req.params.shopId,
coupon: req.query.coupon ?? null,
items: req.body.items ?? [],
language: req.get('accept-language') ?? 'en',
};
res
.status(201)
.location(`/api/shops/${order.shop}/orders/1001`)
.set('X-Request-Source', 'tutorial')
.cookie('lastShop', order.shop, { httpOnly: true, sameSite: 'lax', maxAge: 7 * 24 * 3600 * 1000 })
.json({ id: 1001, ...order });
});
app.get('/old-catalog', (req, res) => res.redirect(301, '/catalog'));
app.delete('/api/cart', (req, res) => res.sendStatus(204));
app.get('/robots.txt', (req, res) => res.type('text/plain').send('User-agent: *\nAllow: /'));
const server = app.listen(3014, async () => {
const base = 'http://localhost:3014';
const res = await fetch(base + '/api/shops/pune-1/orders?coupon=SAVE10', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept-Language': 'hi-IN' },
body: JSON.stringify({ items: ['Pen', 'Notebook'] }),
});
console.log(res.status, res.headers.get('location'));
console.log('cookie:', res.headers.get('set-cookie').split(';')[0]);
console.log(await res.text());
const redirect = await fetch(base + '/old-catalog', { redirect: 'manual' });
console.log(redirect.status, '→', redirect.headers.get('location'));
console.log((await fetch(base + '/api/cart', { method: 'DELETE' })).status);
console.log(JSON.stringify(await (await fetch(base + '/robots.txt')).text()));
server.close();
});
201 /api/shops/pune-1/orders/1001
cookie: lastShop=pune-1
{"id":1001,"shop":"pune-1","coupon":"SAVE10","items":["Pen","Notebook"],"language":"hi-IN"}
301 → /catalog
204
"User-agent: *\nAllow: /"This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- req.params, req.query, req.body and req.get read the four main input sources.
- res methods chain: status, location, set, cookie and finally json.
- The cookie is httpOnly, so browser JavaScript cannot read it.
- res.redirect sends a 301 with a Location header.
- sendStatus(204) answers with no body; res.type sets the Content-Type before send.
Real-world use case#
A login endpoint reads credentials from req.body, sets a secure session cookie with res.cookie, and answers 204; a logout endpoint calls res.clearCookie and redirects to the home page.
Common mistakes#
express.json() is missing or the client did not send Content-Type: application/json.
Two res.json calls on one path cause “Cannot set headers after they are sent”. Return after responding.
Session cookies without httpOnly, secure and sameSite are easier to steal or misuse.
Best practices#
- Destructure what you need from req
- Chain res calls and send once
- Use httpOnly, secure, sameSite cookies
- Set Location for 201 responses
Remember this#
req: params · query · body · get(header).
res: status → json/send/sendStatus/redirect.
One request, one response.
Practice exercise#
Your task: Write GET /api/greet that reads ?name= (default "guest"), sets the header X-Greeting-Version: 1 and returns { message: "Hello, <name>" }.
Need a hint?
Show solution
import express from 'express';
const app = express();
app.get('/api/greet', (req, res) => {
const name = req.query.name ?? 'guest';
res.set('X-Greeting-Version', '1').json({ message: `Hello, ${name}` });
});
const server = app.listen(3015, async () => {
const res = await fetch('http://localhost:3015/api/greet?name=Asha');
console.log(res.headers.get('x-greeting-version'), await res.text()); // 1 {"message":"Hello, Asha"}
server.close();
});
Mini quiz#
Which call sends only a status code with its default text?
Want more? Practise all Node.js MCQs · Node.js interview questions
My notes#
Saved in this browser.