The Request Object
Express builds req on Node’s http.IncomingMessage.prototype, preserving the Node HTTP request object as its base.
It exists to give handlers a single request surface for negotiation, address resolution, route parameters, and other request-derived state. The supplied source shows these concerns being assembled from small imported modules and application settings.
Sources: lib/request.js:30, lib/request.js:16, lib/request.js:17, lib/request.js:18, lib/request.js:19, lib/request.js:20, lib/request.js:21, lib/request.js:22, lib/request.js:23
Core concepts
The request prototype
The Express request object is created with Node’s http.IncomingMessage.prototype as its prototype.
Sources: lib/request.js:30
Content negotiation
Content negotiation selects a server-supported representation from candidate types using the request’s Accept header. The test shows req.accepts returning text/html for Accept: */html when given JSON and HTML candidates.
Sources: test/req.accepts.js:112-122
Proxy-aware addresses
The values of req.ip and req.ips depend on the configured trust proxy behavior and the forwarded-address chain.
Sources: test/req.ip.js:9-37
Route and query state
Route parameters are exposed through req.params, while the supplied source only shows how the application configures a query parser, not the later population of req.query.
The request module imports these names; the import lines alone do not establish each name’s internal responsibility.
| Identifier | What the shown source establishes |
|---|---|
accepts | Imported from the accepts package |
isIP | Assigned from node:net.isIP |
typeis | Imported from the type-is package |
http | Imported from node:http |
fresh | Imported from the fresh package |
parseRange | Imported from the range-parser package |
parse | Imported from the parseurl package |
proxyaddr | Imported from the proxy-addr package |
defineGetter exposes a property by calling Object.defineProperty with configurable, enumerable, and getter settings.
Sources: test/app.router.js:16-36, lib/application.js:363-369, lib/request.js:16, lib/request.js:17, lib/request.js:18, lib/request.js:19, lib/request.js:20, lib/request.js:21, lib/request.js:22, lib/request.js:23, lib/request.js:521-527
How the request object is assembled
This architecture view shows the construction boundary and the imported request-related modules without assigning unsupported behavior to those imports.
Evidence
- request-objectlib/request.js:30
- incoming-messagelib/request.js:30
- accepts-importlib/request.js:16
- proxyaddr-importlib/request.js:23
The concrete construction evidence is Object.create(http.IncomingMessage.prototype), while the request module separately imports accepts and proxyaddr.
defineGetter provides the property-definition mechanism used by the request module, but the supplied excerpt does not identify which individual request properties use it.
Sources: lib/request.js:16, lib/request.js:23, lib/request.js:30, lib/request.js:521-527
How req.accepts() chooses a representation
A handler passes candidate representations to req.accepts, and the test demonstrates the resulting choice from the request’s Accept header.
In the example, the request advertises * /html as Accept—shown in the source as */html—and the candidate list is ['application/json', 'text/html']; the handler receives text/html.
The supplied excerpts do not show the internal algorithm used to compare header values, quality weights, or aliases. They establish the observable candidate-selection behavior, not the implementation details of the external package.
res.format consumes the same request-facing decision: it removes default, passes the remaining keys to req.accepts, invokes the selected handler, and otherwise uses default or passes a 406 error to next.
Sources: test/req.accepts.js:115-122, test/req.accepts.js:112-122, lib/response.js:573-597
How addresses and route state reach a handler
The address distinction is observable in the tests. With trust proxy enabled and X-Forwarded-For: client, p1, p2, req.ip returns client, while req.ips returns ["client","p1","p2"].
With app.set('trust proxy', 2), the same forwarded chain produces p1 for req.ip and ["p1","p2"] for req.ips, stopping at the first untrusted address.
Changing trust proxy causes the application to compile and store trust proxy fn, which connects address behavior to application configuration.
This flow summarizes the tested difference between the single resolved address and the retained forwarded list.
Diagram omitted: missing
Route parameters are populated by route matching before the handler reads them: a route registered as /user/:id exposes req.params.id as 1 to the surrounding handlers.
A mounted router temporarily sees a different parameter view: the test observes undefined inside the router, then confirms that the outer handlers still see 1 after the router returns.
The resource example reads several captured values directly from req.params, including a, b, format, and id.
For query state, app.set('query parser', val) compiles and stores query parser fn. The supplied excerpts do not show the parser being invoked or req.query being assigned, so the complete query-population path cannot be established here.
Sources: test/req.ip.js:9-23, test/req.ips.js:9-23, test/req.ip.js:25-37, test/req.ips.js:25-37, lib/application.js:359-372, test/app.router.js:16-36, test/app.router.js:25-36, examples/resource/index.js:13-24, lib/application.js:363-369
How it connects
An HTTP server uses the Express application function as its callback, providing the entry boundary for incoming requests. The surrounding startup path is described in Application Lifecycle, and handler dispatch is described in App Routing & Request Dispatch.
Route matching, router parameter scope, and restoration connect to Routing Architecture.
The request’s negotiation result is consumed by response formatting, which connects this page to Response: Sending Data.
The trust proxy and query parser settings are configured through the application settings system described in App Configuration & Settings.
Sources: lib/application.js:577-594, lib/response.js:573-597
Key takeaways
reqis created from http.IncomingMessage.prototype.- req.accepts chooses among supplied candidates based on the request’s advertised type; the shown test returns
text/html. - req.ip exposes one resolved address, while req.ips exposes the tested forwarded list.
- Numeric
trust proxychanges where address resolution stops. - The excerpts show route parameters reaching handlers through req.params, but do not show the full req.query population path.
Sources: lib/request.js:30, test/req.accepts.js:115-122, test/req.ip.js:9-37, test/req.ip.js:25-37, test/req.ips.js:25-37, lib/application.js:363-369