Express Response Types
Introduction
When building web applications with Express.js, how you respond to client requests is just as important as how you handle incoming data. Express provides various methods to send different types of responses back to clients. Understanding these response types allows you to build more flexible and powerful web applications that properly communicate with clients.
In this guide, we'll explore the various types of responses you can send from your Express.js application, including text, JSON, HTML, files, and more. We'll cover when to use each type and provide practical examples to illustrate their usage.
Basic Response Methods
Sending Text Responses
The simplest way to respond to a request is by sending plain text using res.send()
:
app.get('/hello', (req, res) => {
res.send('Hello, Express!');
});
When a user visits /hello
, they will see:
Hello, Express!
The send()
method automatically sets the appropriate Content-Type header (in this case, 'text/html').
Sending JSON Responses
For API development, JSON responses are essential. Express makes this easy with res.json()
:
app.get('/api/user', (req, res) => {
const user = {
id: 1,
name: 'John Doe',
email: '[email protected]'
};
res.json(user);
});
This will send:
{
"id": 1,
"name": "John Doe",
"email": "[email protected]"
}
The json()
method automatically converts the JavaScript object to a JSON string and sets the Content-Type header to 'application/json'.
Sending Status Codes
You can explicitly set HTTP status codes:
app.get('/not-found', (req, res) => {
res.status(404).send('Resource not found');
});
app.get('/error', (req, res) => {
res.status(500).json({ error: 'Internal server error' });
});
You can also use named status codes:
app.get('/unauthorized', (req, res) => {
res.sendStatus(401); // Will send "Unauthorized"
});
HTML and Template Responses
Sending HTML
For simple HTML responses:
app.get('/html-example', (req, res) => {
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Express HTML Example</title>
</head>
<body>
<h1>Hello from Express!</h1>
<p>This is a simple HTML response.</p>
</body>
</html>
`;
res.send(html);
});
Rendering Templates
For more complex HTML, template engines like EJS, Pug, or Handlebars are recommended:
// First, set up your template engine
app.set('view engine', 'ejs');
app.set('views', './views');
// Then render a template
app.get('/profile', (req, res) => {
const user = {
name: 'John Doe',
email: '[email protected]',
skills: ['JavaScript', 'Node.js', 'Express']
};
res.render('profile', { user });
});
This assumes you have a profile.ejs file in your views directory with appropriate template markup.
File Responses
Sending Files
To send files as responses, use res.sendFile()
:
app.get('/document', (req, res) => {
res.sendFile('/path/to/document.pdf', { root: __dirname });
});
Express automatically sets the Content-Type based on the file extension.
File Downloads
To prompt a file download in the browser:
app.get('/download', (req, res) => {
res.download('/path/to/file.pdf', 'user-manual.pdf', (err) => {
if (err) {
// Handle error, but keep in mind the response may be partially-sent
console.error('Error downloading file:', err);
if (!res.headersSent) {
res.status(500).send('Error downloading file');
}
}
});
});
This will prompt the browser to download the file with the name 'user-manual.pdf'.
Advanced Response Techniques
Setting Headers
Custom headers can provide additional information or control behavior:
app.get('/custom-header', (req, res) => {
res.set('X-Custom-Header', 'Hello from Express');
res.send('Check the response headers!');
});
// Or all at once
app.get('/multiple-headers', (req, res) => {
res.set({
'Content-Type': 'text/plain',
'X-Powered-By': 'My Express App',
'Cache-Control': 'no-cache'
});
res.send('Response with custom headers');
});
Chaining Response Methods
Many Express response methods can be chained together:
app.get('/chained', (req, res) => {
res.status(201)
.set('X-Created-By', 'Express Tutorial')
.json({ message: 'Resource created successfully' });
});
Redirects
Redirecting to another URL is common in web applications:
app.get('/old-page', (req, res) => {
res.redirect('/new-page'); // 302 redirect by default
});
app.get('/permanent-redirect', (req, res) => {
res.redirect(301, '/new-location'); // 301 (permanent) redirect
});
// Relative redirects
app.get('/products', (req, res) => {
res.redirect('./categories'); // Redirects to /products/categories
});
Streaming Responses
For large files or real-time data, streaming can be more efficient:
const fs = require('fs');
app.get('/stream-video', (req, res) => {
const videoPath = './videos/sample.mp4';
const stat = fs.statSync(videoPath);
res.writeHead(200, {
'Content-Type': 'video/mp4',
'Content-Length': stat.size
});
const videoStream = fs.createReadStream(videoPath);
videoStream.pipe(res);
});
Real-world Application: REST API
Let's build a simple REST API for a todo list that uses different response types:
const express = require('express');
const app = express();
app.use(express.json());
// In-memory database
let todos = [
{ id: 1, title: 'Learn Express', completed: false },
{ id: 2, title: 'Build an API', completed: false }
];
// Get all todos
app.get('/api/todos', (req, res) => {
res.json(todos);
});
// Get a single todo
app.get('/api/todos/:id', (req, res) => {
const todo = todos.find(t => t.id === parseInt(req.params.id));
if (!todo) {
return res.status(404).json({
error: 'Todo not found'
});
}
res.json(todo);
});
// Create a new todo
app.post('/api/todos', (req, res) => {
if (!req.body.title) {
return res.status(400).json({
error: 'Title is required'
});
}
const newTodo = {
id: todos.length + 1,
title: req.body.title,
completed: false
};
todos.push(newTodo);
res.status(201).json(newTodo);
});
// Update a todo
app.put('/api/todos/:id', (req, res) => {
const todo = todos.find(t => t.id === parseInt(req.params.id));
if (!todo) {
return res.status(404).json({
error: 'Todo not found'
});
}
todo.title = req.body.title || todo.title;
todo.completed = req.body.completed !== undefined ? req.body.completed : todo.completed;
res.json(todo);
});
// Delete a todo
app.delete('/api/todos/:id', (req, res) => {
const index = todos.findIndex(t => t.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({
error: 'Todo not found'
});
}
todos.splice(index, 1);
res.status(204).end(); // No content response
});
app.listen(3000, () => console.log('Server running on port 3000'));
This API demonstrates:
- JSON responses for listing and reading resources
- Appropriate status codes (200, 201, 204, 400, 404)
- Empty responses when appropriate (204 No Content for DELETE)
- Error handling with descriptive messages
Summary
Express.js offers a variety of response methods to handle different types of HTTP responses effectively:
-
Basic Responses
res.send()
for text/HTMLres.json()
for JSON datares.status()
for setting HTTP status codes
-
HTML Responses
- Direct HTML through
res.send()
- Template rendering with
res.render()
- Direct HTML through
-
File Responses
res.sendFile()
for serving filesres.download()
for downloadable files
-
Advanced Responses
- Header manipulation with
res.set()
- Redirects with
res.redirect()
- Method chaining for concise code
- Stream responses for efficient data transfer
- Header manipulation with
Understanding these various response types allows you to build more robust Express applications that communicate effectively with clients. Choose the appropriate response type based on your specific use case and client requirements.
Additional Resources and Exercises
Resources
- Express.js Official Documentation on Response Methods
- MDN Web Docs: HTTP Response Status Codes
- Best Practices for REST API Design
Exercises
-
Build a small Express application that serves different types of content:
- Plain text at
/text
- JSON data at
/api/data
- An HTML page at
/html
- A downloadable file at
/download
- Plain text at
-
Create a middleware that adds custom headers to all your responses.
-
Implement a REST API for a library with books and authors, using appropriate response types and status codes for different operations.
-
Build an image gallery app that streams image files on demand and provides proper error handling when images don't exist.
By practicing with these different response types, you'll gain confidence in building expressive and efficient web applications with Express.js.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)