The request object

Express · Essentials · 10 min

Handlers decide what to do based on the request; knowing where each piece lives avoids reparsing by hand.

req is Node's IncomingMessage with Express additions. Besides req.params, req.query and req.body (next lessons), the commonly used members are:

  • req.method, req.path (path without query string), req.originalUrl (the full URL as received, kept intact even inside routers), req.baseUrl (where the current router is mounted).
  • req.get(name) — read a header case-insensitively: req.get("Content-Type"), req.get("Authorization").
  • req.is(type) — check the request's content type: req.is("application/json") returns the matching type or false.
  • req.accepts(types) — content negotiation: which of the types you can produce does the client prefer?
  • req.ip, req.ips, req.protocol, req.secure, req.hostname, req.host — client and connection information. Behind a proxy or load balancer these are only correct after configuring trust proxy (covered later).
  • req.cookies — only if the cookie-parser middleware is installed; Express doesn't parse cookies by itself.
  • req.app — the application, handy in modules that don't import it.

Everything on req that comes from the client is untrusted: headers can be forged, IPs spoofed through X-Forwarded-For if you trust proxies blindly, and body fields can have any shape.

Middleware commonly attaches data to `req` for later handlers, such as req.user after authentication. For values meant for templates or per-request state, Express also provides res.locals. Keep such additions few and documented; in TypeScript, declare them via module augmentation.

req is also a readable stream, which matters when you stream uploads instead of parsing them.

Example

import express from "express";
const app = express();

app.get("/whoami", (req, res) => {
  res.json({
    method: req.method,
    path: req.path,                     // /whoami
    originalUrl: req.originalUrl,       // /whoami?debug=1
    userAgent: req.get("user-agent"),   // header lookup is case-insensitive
    ip: req.ip,
    protocol: req.protocol,             // http (https behind a trusted proxy)
    wantsJson: req.accepts(["html", "json"]) === "json",
  });
});

app.post("/upload", (req, res) => {
  if (!req.is("application/json")) {
    return res.status(415).json({ error: "send application/json" });
  }
  res.sendStatus(204);
});

app.listen(3000);

Remember

  • req.get() reads headers; req.is() checks content type; req.accepts() negotiates
  • req.originalUrl keeps the full URL; req.path excludes the query
  • req.ip/req.protocol need trust proxy behind a load balancer
  • All request data is untrusted input

Watch out for

  • Expecting req.cookies to exist without installing cookie-parser.

Check yourself

  1. Inside a router mounted at /api, a request for /api/users?x=1 arrives. What is req.originalUrl?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: expressjs.com/en/api/request

The request object · Express · Topolearn