Open-Source Wikis

/

Express

/

Systems

/

Response

expressjs/express

Response

Active contributors: dougwilson, ulisesgascon, wesleytodd

Purpose

lib/response.js defines the res prototype attached to outgoing responses. It builds on http.ServerResponse.prototype and provides the bulk of the user-visible response API: status codes, body senders, JSON helpers, file streaming, redirects, content negotiation, cookie helpers, and view rendering.

At ~1,047 lines, it is the largest file in core.

Directory layout

lib/
└── response.js   # this file

Key abstractions

Status and metadata

Method What it does
res.status(code) Sets statusCode. Throws TypeError if not an integer, RangeError if outside [100, 999]. Express 5 strict mode.
res.sendStatus(code) Status + the standard statuses.message[code] body, with text/plain content type.
res.links(links) Builds the Link header from { rel: url } (supports arrays for multiple links per rel — added in 5.1).
res.set(field, val) / res.header Header setter. Accepts an object form res.set({a: 1, b: 2}). Auto-injects charset on Content-Type. Arrays for Content-Type throw.
res.get(field) getHeader shortcut.
res.append(field, val) Appends to a header value, building an array when there's already a previous value.
res.type(type) / res.contentType Sets Content-Type. Routes through mime.contentType() when no / is present; falls back to application/octet-stream.
res.attachment(filename?) Sets Content-Disposition: attachment; filename=..., plus the type from the extension when a filename is given.
res.vary(field) Adds to the Vary header (delegates to the vary package).
res.location(url) Sets Location, encoding via encodeUrl.

Bodies

Method What it does
res.send(body) Sends a string/Buffer/object/boolean/number. Computes Content-Length, optionally generates ETag (when no existing ETag and etag fn set), respects req.fresh (becomes 304), and short-circuits to JSON for plain objects. Supports Uint8Array (added in 5.1).
res.json(obj) Stringifies with json escape / json replacer / json spaces settings, sets Content-Type: application/json, calls res.send.
res.jsonp(obj) JSON with a callback wrapper from req.query[jsonp callback name]. Adds X-Content-Type-Options: nosniff, escapes \u2028/\u2029, prepends /**/ to mitigate Rosetta Flash.
res.sendFile(path, opts?, cb?) Streams a file via the send package. Throws TypeError if path is missing/non-string or relative without opts.root. Honours the app's 'etag' setting via opts.etag. (5.1 added explicit etag option.)
res.download(path, name?, opts?, cb?) Sets Content-Disposition (via content-disposition) and delegates to sendFile.

Redirects and rendering

Method What it does
res.redirect([status,] url) Default status 302. Emits a text/plain body for text accept, an HTML body for HTML accept, or empty otherwise. undefined URL or non-string URL triggers a depd deprecation warning (5.2).
res.render(view, opts?, cb?) Calls req.app.render with _locals = res.locals. If no callback, sends the rendered string; otherwise passes it through.
res.format({ ... }) Content negotiation: matches a key against req.accepts(keys), sets the matching Content-Type, calls the matched function. Adds Vary: Accept. Falls back to default callback or next(createError(406, { types: ... })).

Cookies

Method What it does
res.cookie(name, value, opts?) Serialises via the cookie package. Supports signed: true (requires req.secret), object values (prefixed j: then JSON-stringified), and maxAgeexpires translation. Defaults path to /.
res.clearCookie(name, opts?) Sets a cookie with expires set to the past. Strips user-provided maxAge (Express 5 behaviour).

Internal helpers

  • sendfile(res, file, options, callback) — wires send's event stream to the response, handles directory, error, aborted, finish events with double-fire protection.
  • stringify(value, replacer, spaces, escape)JSON.stringify plus optional HTML-escape pass for <, >, &.

How it works

res.send decision tree

graph TD
    Send["res.send body"] --> Type{"typeof body"}
    Type -- string --> Encoding["encoding=utf8;<br/>set Content-Type with charset<br/>or default to html"]
    Type -- bool/num/null --> AsIs[treat as text-ish]
    Type -- object/Buffer --> ObjBuf{"is ArrayBuffer view?"}
    ObjBuf -- yes --> Bin["set type bin if no Content-Type"]
    ObjBuf -- no --> ToJson["res.json body"]
    Encoding --> Length[set Content-Length]
    AsIs --> Length
    Bin --> Length
    Length --> ETag{"etagFn?<br/>and no ETag yet"}
    ETag -- yes --> SetETag[res.set ETag]
    ETag -- no --> Fresh{"req.fresh?"}
    SetETag --> Fresh
    Fresh -- yes --> Status304[status 304]
    Fresh -- no --> CheckCode{"204 / 304 / 205?"}
    Status304 --> CheckCode
    CheckCode -- 204/304 --> Strip[strip body and Content-* headers]
    CheckCode -- 205 --> SetZero[Content-Length 0, no Transfer-Encoding]
    CheckCode -- other --> EndBody{"HEAD?"}
    Strip --> EndBody
    SetZero --> EndBody
    EndBody -- yes --> EndNoBody[res.end]
    EndBody -- no --> EndWithBody[res.end chunk]

res.sendFile flow

sequenceDiagram
    participant Caller
    participant Res as res.sendFile
    participant Send as send package
    participant File as fs stream
    participant Sock as response socket

    Caller->>Res: res.sendFile(path, opts, cb)
    Res->>Res: validate path + opts.root
    Res->>Res: opts.etag = app.enabled('etag')
    Res->>Send: send(req, encodeURI(path), opts)
    Send->>File: open + stat
    File->>Send: streamable
    Send->>Res: emit 'file' / 'stream' / 'directory' / 'error'
    Res->>Sock: file.pipe(res)
    Sock-->>Res: onFinished -> onfinish
    Res->>Caller: cb(err?) — guarded by `done` flag

Content negotiation (res.format)

graph TD
    Format[res.format obj] --> Keys[keys = Object.keys without default]
    Keys --> Vary[res.vary 'Accept']
    Vary --> Match[req.accepts keys]
    Match --> Found{match?}
    Found -- yes --> SetType[set Content-Type from normalizeType key]
    SetType --> Call[obj key req,res,next]
    Found -- no --> Default{obj.default?}
    Default -- yes --> Run[obj.default req,res,next]
    Default -- no --> Err[next createError 406, types]

Integration points

  • Imports: content-disposition, http-errors, depd, encodeurl, escape-html, node:http, on-finished, mime-types, node:path, statuses, cookie-signature, ./utils (normalizeType, normalizeTypes, setCharset), cookie, send, vary, node:buffer (Buffer).
  • Exposed via: lib/express.js exports it as express.response. Each app gets a per-app copy with .app set on it, attached to res on each request by app.handle.
  • Reads from app.settings: etag fn, json escape, json replacer, json spaces, jsonp callback name, 'etag' (boolean shorthand for sendFile).
  • Used by: Every handler that produces a response.

Entry points for modification

  • New body helper → mirror res.send/res.json. Decide whether to call res.send at the end (so ETag/freshness/HEAD are handled) or to write headers and end manually.
  • New file/streaming behaviour → modify res.sendFile or the sendfile helper. Be careful with the done flag — multiple events from the send package can race.
  • Cookie option → extend res.cookie. The bulk of validation is in the cookie package itself.

Key source files

File Purpose
lib/response.js The res prototype
lib/utils.js Content-type and charset helpers consumed here
lib/application.js Wires app.response and provides app.render used by res.render

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Response – Express wiki | Factory