Mastering the API Response π€
Crafting a good API response is more than just sending data. A high-quality response includes a clear status code indicating the outcome, appropriate headers providing context, and a well-formatted body containing the data. The Express response (res) object provides a rich set of helper methods to make this process simple and expressive.
Sending Data: res.json() vs. res.send()
While both methods can send data, res.json() is the standard choice for building REST APIs.
res.json([body]): This method is specifically designed to send a JSON response. It automatically:- Serializes a JavaScript object or array into a JSON string.
- Sets the
Content-Typeheader toapplication/json.
res.send([body]): This is a more versatile, general-purpose method. It can send strings, objects, arrays, or Buffers. It intelligently tries to set theContent-Typeheader based on the data, but for APIs,res.json()is more explicit and conventional.
Best Practice: When building an API, always use res.json() to ensure your responses are consistent.
app.get("/api/user", (req, res) => {
const user = { id: 1, name: "Alice", role: "admin" };
// This is the standard way to send JSON data.
res.json(user);
});Setting the Status: res.status() and res.sendStatus()
Using the correct HTTP status code is crucial for a well-behaved API.
res.status(code): This method sets the HTTP status code. It is chainable, meaning you can call another response method right after it. This is the most common way to set a status.res.sendStatus(code): This method sets the status code AND sends the default text representation as the response body (e.g.,404sends βNot Foundβ). It ends the response cycle immediately.
Common Status Codes:
200: OK201: Created (after a successfulPOST)400: Bad Request (e.g., invalid user input)404: Not Found500: Internal Server Error
app.get("/api/items/:id", (req, res) => {
const item = findItemById(req.params.id); // A fictional function
if (item) {
// Chain .status() with .json() for a successful response
res.status(200).json(item);
} else {
// Chain .status() with .json() for an error response
res.status(404).json({ error: "Item not found" });
}
});Setting Headers: res.set()
The res.set() (or res.header()) method allows you to set custom HTTP response headers.
app.get("/api/data", (req, res) => {
res.set("X-Request-ID", "some-unique-id-123");
res.set("Cache-Control", "no-store"); // Tell the browser not to cache this
res.status(200).json({ data: "This is some sensitive data" });
});Prompting File Downloads: res.download()
This utility method is used to prompt the client to download a file. It automatically sets the necessary headers, like Content-Disposition, which tells the browser to open a βSave Asβ¦β dialog.
res.download(path, [filename], [callback]):path: The path to the file on the server.filename(optional): The name you want the file to have when downloaded.callback(optional): A function to call after the transfer is complete or if an error occurs.
const path = require("path");
app.get("/download-report", (req, res) => {
const filePath = path.join(__dirname, "reports", "report-2025.pdf");
// This will trigger a download prompt in the browser for 'report-2025.pdf'
res.download(filePath, (err) => {
if (err) {
// Handle errors, like if the file doesn't exist
res.status(404).send("Report not found.");
}
});
});β¨ Summary
- Use
res.json()as the standard for sending API data. - Always set the correct HTTP status code using the chainable
res.status()method. - Use
res.set()to add custom or standard headers to your response. - Use
res.download()to easily trigger a file download on the client. - Remember that every route handler must end the request-response cycle by calling one of these response-sending methods.