Skip to main content

Express Status Codes

Introduction

When developing web applications with Express.js, properly communicating the outcome of HTTP requests is crucial. HTTP status codes are standardized codes returned by a web server in response to client requests. These codes indicate whether a request was successful, encountered an error, or requires further action.

In this guide, you'll learn:

  • What HTTP status codes are and why they matter
  • The different categories of status codes
  • How to send status codes in Express.js
  • Best practices for using status codes in your applications

Understanding HTTP Status Codes

HTTP status codes are three-digit numbers grouped into five categories, each serving a specific purpose:

CategoryRangePurpose
1xx100-199Informational responses
2xx200-299Successful responses
3xx300-399Redirection messages
4xx400-499Client error responses
5xx500-599Server error responses

Let's explore each category in more detail and see how to implement them in Express.js.

Sending Status Codes in Express

Express provides several ways to send status codes in your responses:

Method 1: Using res.status()

The most common approach is using the status() method followed by another method to send the response:

javascript
app.get('/users/:id', (req, res) => {
const userId = req.params.id;

// Assuming we have a findUser function
const user = findUser(userId);

if (!user) {
// User not found - return 404 status code
return res.status(404).json({
message: "User not found"
});
}

// User found - return 200 status code with user data
res.status(200).json(user);
});

Method 2: Using res.sendStatus()

For simple responses where you just need to send the status code without a body:

javascript
app.post('/api/logout', (req, res) => {
// Log the user out
logoutUser(req.session);

// Just send a 204 (No Content) status code
res.sendStatus(204);
});

Method 3: Status code convenience methods

Express provides convenience methods for common status codes:

javascript
// These are equivalent:
res.status(200).send('Success');
res.ok('Success');

// These are equivalent:
res.status(201).send('Created');
res.created();

// These are equivalent:
res.status(404).send('Not Found');
res.notFound('Not Found');

Note that not all convenience methods are available by default in Express and may require additional packages.

Common Status Codes and Their Usage

Let's look at the most commonly used status codes in Express applications:

2xx - Success Codes

200 OK

The request succeeded. This is the standard response for successful HTTP requests.

javascript
app.get('/api/products', (req, res) => {
const products = getProducts();
res.status(200).json(products);
});

201 Created

The request succeeded and a new resource was created. Typically used with POST requests.

javascript
app.post('/api/products', (req, res) => {
const newProduct = createProduct(req.body);

// Return 201 with the location of the new resource
res.status(201)
.location(`/api/products/${newProduct.id}`)
.json(newProduct);
});

204 No Content

The server successfully processed the request but is not returning any content. Useful for DELETE operations.

javascript
app.delete('/api/products/:id', (req, res) => {
deleteProduct(req.params.id);
// Return 204 with no body
res.sendStatus(204);
});

4xx - Client Error Codes

400 Bad Request

The server cannot process the request due to a client error (e.g., malformed request syntax).

javascript
app.post('/api/users', (req, res) => {
const { username, email } = req.body;

if (!username || !email) {
return res.status(400).json({
error: 'Username and email are required'
});
}

// Process valid request...
});

401 Unauthorized

Authentication is required and has failed or has not been provided.

javascript
app.get('/api/user/profile', (req, res) => {
const token = req.headers.authorization;

if (!token) {
return res.status(401).json({
error: 'Authentication required'
});
}

// Process authenticated request...
});

403 Forbidden

The client is authenticated but does not have permission to access the requested resource.

javascript
app.delete('/api/posts/:id', (req, res) => {
const post = getPost(req.params.id);

if (!userCanDelete(req.user, post)) {
return res.status(403).json({
error: 'You do not have permission to delete this post'
});
}

// Process authorized request...
});

404 Not Found

The requested resource could not be found.

javascript
app.get('/api/products/:id', (req, res) => {
const product = getProduct(req.params.id);

if (!product) {
return res.status(404).json({
error: 'Product not found'
});
}

res.json(product);
});

5xx - Server Error Codes

500 Internal Server Error

A generic error occurred on the server.

javascript
app.get('/api/complex-calculation', (req, res) => {
try {
const result = performComplexCalculation();
res.json(result);
} catch (error) {
console.error('Calculation error:', error);
res.status(500).json({
error: 'An error occurred while processing your request'
});
}
});

503 Service Unavailable

The server is not ready to handle the request, often used for maintenance or overload scenarios.

javascript
app.get('/api/heavy-process', (req, res) => {
if (serverIsOverloaded()) {
return res.status(503)
.header('Retry-After', '30') // Try again in 30 seconds
.json({
error: 'Service temporarily unavailable, please try again later'
});
}

// Process request...
});

Practical Example: RESTful API with Status Codes

Let's put everything together in a simple RESTful API for a book management system:

javascript
const express = require('express');
const app = express();
app.use(express.json());

// In-memory database for demonstration
let books = [
{ id: '1', title: 'The JavaScript Way', author: 'John Doe' },
{ id: '2', title: 'Express Mastery', author: 'Jane Smith' }
];

// GET all books
app.get('/api/books', (req, res) => {
res.status(200).json(books);
});

// GET a specific book
app.get('/api/books/:id', (req, res) => {
const book = books.find(b => b.id === req.params.id);

if (!book) {
return res.status(404).json({
error: 'Book not found'
});
}

res.status(200).json(book);
});

// POST a new book
app.post('/api/books', (req, res) => {
const { title, author } = req.body;

// Validate input
if (!title || !author) {
return res.status(400).json({
error: 'Title and author are required'
});
}

// Create new book
const newBook = {
id: Date.now().toString(),
title,
author
};

books.push(newBook);

res.status(201)
.location(`/api/books/${newBook.id}`)
.json(newBook);
});

// PUT (update) a book
app.put('/api/books/:id', (req, res) => {
const { title, author } = req.body;

// Validate input
if (!title || !author) {
return res.status(400).json({
error: 'Title and author are required'
});
}

const bookIndex = books.findIndex(b => b.id === req.params.id);

if (bookIndex === -1) {
return res.status(404).json({
error: 'Book not found'
});
}

// Update the book
books[bookIndex] = {
id: req.params.id,
title,
author
};

res.status(200).json(books[bookIndex]);
});

// DELETE a book
app.delete('/api/books/:id', (req, res) => {
const bookIndex = books.findIndex(b => b.id === req.params.id);

if (bookIndex === -1) {
return res.status(404).json({
error: 'Book not found'
});
}

books.splice(bookIndex, 1);

// Return 204 No Content
res.sendStatus(204);
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

Best Practices for Status Codes

  1. Be Specific: Use the most specific status code applicable to the situation.
  2. Consistency: Be consistent with status codes across your API.
  3. Security Considerations: Be careful not to leak sensitive information in error responses.
  4. Documentation: Document the status codes your API returns.
  5. Error Messages: Include helpful error messages with error status codes.
  6. Don't Overuse 200: Don't return 200 OK for errors, use the appropriate error status code.
  7. Redirects: Use 301 (permanent) and 302 (temporary) redirects appropriately.

Summary

HTTP status codes are a fundamental aspect of RESTful API design in Express applications. They provide a standardized way to communicate the result of HTTP requests to clients.

Key points to remember:

  • Status codes are grouped into categories (1xx, 2xx, 3xx, 4xx, 5xx)
  • Express provides methods like res.status() and res.sendStatus() to send status codes
  • Use appropriate status codes to accurately represent the outcome of requests
  • Include helpful error messages with error status codes
  • Be consistent with status code usage across your API

By correctly implementing status codes in your Express applications, you'll create more predictable, robust, and user-friendly APIs.

Additional Resources

Exercises

  1. Create a simple Express API that returns different status codes based on query parameters.
  2. Modify the books API example to include proper validation and more specific error codes.
  3. Create middleware that logs all status codes sent by your application.
  4. Implement a "health check" endpoint that returns different status codes based on your application's status.
  5. Create a middleware that handles common errors and sets appropriate status codes.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)