Express.js Request and Response Objects

Every route handler in Express receives two powerful objects: req (the request) and res (the response). The request object holds all information the client sent to your server. The response object gives you tools to send data back. Mastering these two objects gives you full control over every interaction between your server and the outside world.

The Hotel Reception Analogy

Think of your Express server as a hotel reception desk. A guest walks in (the browser sends a request). The receptionist gets a clipboard with all the guest's details — name, room preference, loyalty number, arrival date (this is the req object). The receptionist then prepares the response: a room key, a welcome message, a printed receipt (this is the res object).

Guest arrives (request)          Receptionist responds
─────────────────────           ─────────────────────
req.body       → form data       res.send()    → text/html
req.params     → URL segments    res.json()    → JSON data
req.query      → search filters  res.status()  → status code
req.headers    → meta info       res.redirect()→ new location
req.cookies    → stored data     res.sendFile()→ file download

The Request Object (req)

The req object contains everything the client sent. Here are its most important properties:

req.params — URL Parameters

URL parameters are named segments in the route path. Define them with a colon prefix:

app.get('/users/:id/posts/:postId', (req, res) => {
  console.log(req.params);
  // { id: '42', postId: '7' }
});

When someone visits /users/42/posts/7, Express extracts 42 and 7 and puts them in req.params.

req.query — Query String Parameters

Query strings appear after the ? in a URL. Use them for filters, search terms, and pagination:

// URL: /products?category=shoes&sort=price&page=2

app.get('/products', (req, res) => {
  console.log(req.query);
  // { category: 'shoes', sort: 'price', page: '2' }
});

req.body — Request Body Data

POST and PUT requests carry data in the request body. You need middleware to parse it before accessing it:

app.use(express.json());         // Parses JSON bodies
app.use(express.urlencoded({ extended: true })); // Parses form data

app.post('/login', (req, res) => {
  console.log(req.body);
  // { username: 'alice', password: 'secret123' }
});

req.headers — Request Headers

Headers carry metadata about the request — the content type, authentication tokens, browser information:

app.get('/profile', (req, res) => {
  const authToken = req.headers['authorization'];
  const contentType = req.headers['content-type'];
  console.log(authToken);  // 'Bearer eyJhbGci...'
});

req.method — HTTP Method Used

app.all('/data', (req, res) => {
  console.log(req.method); // 'GET', 'POST', 'PUT', etc.
});

req.url and req.path — The Request URL

// For request to: /products?sort=asc

req.url   // '/products?sort=asc'  (includes query string)
req.path  // '/products'           (path only)

req.ip — Client IP Address

app.get('/info', (req, res) => {
  console.log(req.ip); // '192.168.1.5'
});

Visual Map of the Request Object

Browser sends: GET /shop/shoes?color=red&size=10
               Headers: { Authorization: 'Bearer token123' }
               Body: (empty for GET)

                    ┌──────────────────────────────┐
                    │         req object           │
                    │                              │
                    │ req.method  = 'GET'          │
                    │ req.path    = '/shop/shoes'  │
                    │ req.params  = { }            │
                    │ req.query   = { color: 'red',│
                    │                size: '10' }  │
                    │ req.headers = { authorization│
                    │    : 'Bearer token123' }     │
                    │ req.body    = {}             │
                    └──────────────────────────────┘

The Response Object (res)

The res object holds methods for sending responses back to the client. Each method below sends the response and ends the communication for that request.

res.send() — Send Text or HTML

res.send('Hello World');               // Plain text
res.send('

Hello World

'); // HTML res.send(Buffer.from([0x00, 0x01])); // Binary data

res.json() — Send JSON

res.json({ status: 'ok', count: 42 });

Express automatically sets the Content-Type header to application/json when you use res.json().

res.status() — Set HTTP Status Code

res.status(200).json({ message: 'OK' });
res.status(201).json({ message: 'Created' });
res.status(400).json({ error: 'Bad Request' });
res.status(401).json({ error: 'Unauthorized' });
res.status(404).json({ error: 'Not Found' });
res.status(500).json({ error: 'Internal Server Error' });

res.redirect() — Send to Another URL

res.redirect('/dashboard');              // Relative redirect
res.redirect('https://example.com');     // Absolute redirect
res.redirect(301, '/new-page');          // Permanent redirect

res.sendFile() — Send a File

const path = require('path');

app.get('/download', (req, res) => {
  res.sendFile(path.join(__dirname, 'files', 'report.pdf'));
});

res.set() — Set Response Headers

res.set('Content-Type', 'text/plain');
res.set('X-Custom-Header', 'MyValue');
res.send('Response with custom headers');

res.cookie() and res.clearCookie()

res.cookie('username', 'alice', { httpOnly: true, maxAge: 86400000 });
res.clearCookie('username');

Common HTTP Status Codes Reference

┌────────────────────────────────────────────────────────────┐
│              HTTP Status Codes in Express                  │
├───────────┬────────────────────────────────────────────────┤
│ 200       │ OK — Request succeeded                         │
│ 201       │ Created — New resource created                 │
│ 204       │ No Content — Success, nothing to return        │
│ 301       │ Moved Permanently — Permanent redirect         │
│ 302       │ Found — Temporary redirect                     │
│ 400       │ Bad Request — Client sent invalid data         │
│ 401       │ Unauthorized — Not logged in                   │
│ 403       │ Forbidden — Logged in but not allowed          │
│ 404       │ Not Found — Resource does not exist            │
│ 409       │ Conflict — Duplicate data                      │
│ 500       │ Internal Server Error — Server bug             │
└───────────┴────────────────────────────────────────────────┘

A Complete Request-Response Example

app.use(express.json());

app.post('/api/login', (req, res) => {
  const { username, password } = req.body;

  // Check credentials
  if (username === 'alice' && password === 'secret') {
    res
      .status(200)
      .cookie('session', 'abc123', { httpOnly: true })
      .json({ success: true, message: 'Welcome, Alice!' });
  } else {
    res
      .status(401)
      .json({ success: false, message: 'Invalid credentials' });
  }
});

This example reads the username and password from req.body, checks them, sets a cookie on success, and sends an appropriate JSON response with a matching status code.

One Response Per Request

Express allows only one response per request. Calling two response methods causes an error: "Cannot set headers after they are sent to the client." Always use return before a response to prevent the function from continuing after it sends:

app.get('/check', (req, res) => {
  if (!req.query.token) {
    return res.status(400).json({ error: 'Token required' });
    // Code below this line never runs when token is missing
  }
  res.json({ status: 'Token received' });
});

Summary

The req object contains everything the client sent: URL parameters in req.params, query strings in req.query, form or JSON data in req.body, and headers in req.headers. The res object provides tools to send responses: res.send() for text, res.json() for data, res.status()res.redirect() for redirects. Always send exactly one response per request, and use return before early responses to prevent function execution from continuing after the response is sent.

Leave a Comment

Your email address will not be published. Required fields are marked *