Node.js · Web Servers

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.

Intermediate 5 min Lesson 22 of 37Examples target Node.js 22 LTS.
Before you start:Routing
0/37 in Node.js
On this page · 5 min · Intermediate

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#

JavaScript Illustrative
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#

JavaScriptreq-res.js Illustrative
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();
});
Expected output
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#

  1. req.params, req.query, req.body and req.get read the four main input sources.
  2. res methods chain: status, location, set, cookie and finally json.
  3. The cookie is httpOnly, so browser JavaScript cannot read it.
  4. res.redirect sends a 301 with a Location header.
  5. 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#

req.body is undefined

express.json() is missing or the client did not send Content-Type: application/json.

Sending twice

Two res.json calls on one path cause “Cannot set headers after they are sent”. Return after responding.

Insecure cookies

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?
res.set(...).json(...).
Show solution
JavaScript Illustrative
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#

Request and Response quizMultiple choice Question 1 of 3

Which call sends only a status code with its default text?

Score so far: 0/0

Want more? Practise all Node.js MCQs · Node.js interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.