Skip to main content

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():

javascript
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():

javascript
app.get('/api/user', (req, res) => {
const user = {
id: 1,
name: 'John Doe',
email: '[email protected]'
};

res.json(user);
});

This will send:

json
{
"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:

javascript
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:

javascript
app.get('/unauthorized', (req, res) => {
res.sendStatus(401); // Will send "Unauthorized"
});

HTML and Template Responses

Sending HTML

For simple HTML responses:

javascript
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:

javascript
// 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():

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

  1. Basic Responses

    • res.send() for text/HTML
    • res.json() for JSON data
    • res.status() for setting HTTP status codes
  2. HTML Responses

    • Direct HTML through res.send()
    • Template rendering with res.render()
  3. File Responses

    • res.sendFile() for serving files
    • res.download() for downloadable files
  4. Advanced Responses

    • Header manipulation with res.set()
    • Redirects with res.redirect()
    • Method chaining for concise code
    • Stream responses for efficient data transfer

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

Exercises

  1. 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
  2. Create a middleware that adds custom headers to all your responses.

  3. Implement a REST API for a library with books and authors, using appropriate response types and status codes for different operations.

  4. 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! :)