Sending Responses
1. Sending Text Response
| Input | Behavior |
| String | Content-Type: text/html |
| Object/Array | Calls res.json() internally |
| Buffer | Content-Type: application/octet-stream |
| null/undefined | Empty body |
Example: res.send variants
res.send("<h1>Hello</h1>"); // text/html
res.send({ ok: true }); // application/json
res.send(Buffer.from("binary")); // octet-stream
res.type("text/plain").send("plain");
2. Sending JSON Response
| API | Detail |
res.json(obj) | JSON body, Content-Type set |
res.jsonp(obj) | JSONP wrapped in callback |
Setting json spaces | Pretty-print indentation |
Setting json replacer | JSON.stringify replacer fn |
Example: JSON with status
res.status(201).json({ id, createdAt: new Date().toISOString() });
3. Setting Response Status
| Code | Meaning |
| 200 OK | Default success |
| 201 Created | POST successful, resource created |
| 204 No Content | Success, no body (DELETE) |
| 301/302 | Redirect (permanent / temporary) |
| 304 Not Modified | Cached resource |
| 400 Bad Request | Validation failure |
| 401 Unauthorized | Missing/invalid auth |
| 403 Forbidden | Authenticated but not allowed |
| 404 Not Found | Resource missing |
| 409 Conflict | Duplicate / version mismatch |
| 422 Unprocessable | Semantic validation |
| 429 Too Many Requests | Rate-limited |
| 500/502/503 | Server errors |
4. Chaining Status and Response
Example: Fluent chain
return res.status(404).json({ error: "Not found" });
return res.status(204).end();
return res.status(303).location("/login").end();
5. Redirecting Requests
Example: Redirect variants
res.redirect("/login"); // 302 default
res.redirect(301, "/new-url"); // permanent
res.redirect("back"); // Referer header or "/"
res.redirect(303, "/orders/" + id); // POST→GET pattern
| Status | Use |
| 301 Moved Permanently | SEO-safe permanent URL change |
| 302 Found | Temporary (default) |
| 303 See Other | POST/PUT → GET (PRG pattern) |
| 307/308 | Method-preserving redirects |
6. Rendering Views
Example: Template rendering
res.render("user-profile", { user, csrfToken: req.csrfToken() }, (err, html) => {
if (err) return next(err);
res.send(html);
});
| Argument | Purpose |
view | Template path relative to views dir |
locals | Data merged with app.locals + res.locals |
callback | Optional (err, html) handler |
7. Sending Files
| Option | Default | Purpose |
root | — | Required if path is relative |
maxAge | 0 | Cache-Control max-age |
headers | — | Custom headers map |
dotfiles | ignore | Hidden file behavior |
acceptRanges | true | HTTP range requests |
Example: Send + handle errors
res.sendFile("invoice.pdf", { root: "private" }, (err) => {
if (err) next(err.status === 404 ? new HttpError(404) : err);
});
8. Downloading Files
Example: Forced download with custom name
res.download("/private/report.pdf", `report-${date}.pdf`, {
headers: { "X-Doc-Id": id }
});
| API | Effect |
res.download(path, filename?, opts?, cb?) | Sets Content-Disposition: attachment |
res.attachment(filename?) | Just sets disposition header (use with send) |
res.set("X-Frame-Options", "DENY");
res.set({ "X-Custom": "1", "X-Trace": req.id });
res.header("Cache-Control", "no-store");
| API | Description |
res.set(name, value) | Set single header |
res.set(obj) | Set multiple |
res.header() | Alias of set |
res.get(name) | Read response header |
res.removeHeader(name) | Remove (Node API) |
10. Setting Content Type
Example: res.type()
res.type("json"); // application/json
res.type("html"); // text/html
res.type(".png"); // image/png
res.type("application/xml");
Example: Multi-value Set-Cookie
res.append("Set-Cookie", "lang=en; Path=/");
res.append("Set-Cookie", "theme=dark; Path=/");
res.append("Vary", "Accept-Encoding");
| set vs append | Behavior |
res.set | Replaces existing value |
res.append | Adds another value (array) |
12. Sending Status-Only Response
| API | Equivalent |
res.sendStatus(204) | res.status(204).send("No Content") |
res.sendStatus(404) | res.status(404).send("Not Found") |
13. Ending Response
Example: Manual end (streaming)
res.writeHead(200, { "Content-Type": "text/plain" });
res.write("chunk 1\n");
res.write("chunk 2\n");
res.end(); // Mandatory — closes the response stream
Warning: Calling any response method twice (e.g., res.json() after res.send()) throws ERR_HTTP_HEADERS_SENT.