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:
Category | Range | Purpose |
---|---|---|
1xx | 100-199 | Informational responses |
2xx | 200-299 | Successful responses |
3xx | 300-399 | Redirection messages |
4xx | 400-499 | Client error responses |
5xx | 500-599 | Server 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:
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:
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:
// 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.
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.
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.
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).
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.
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.
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.
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.
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.
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:
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
- Be Specific: Use the most specific status code applicable to the situation.
- Consistency: Be consistent with status codes across your API.
- Security Considerations: Be careful not to leak sensitive information in error responses.
- Documentation: Document the status codes your API returns.
- Error Messages: Include helpful error messages with error status codes.
- Don't Overuse 200: Don't return 200 OK for errors, use the appropriate error status code.
- 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()
andres.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
- MDN Web Docs: HTTP response status codes
- Express.js Documentation
- HTTP Status Dogs - A fun way to memorize status codes
- HTTP Cats - Another fun resource for status codes
Exercises
- Create a simple Express API that returns different status codes based on query parameters.
- Modify the books API example to include proper validation and more specific error codes.
- Create middleware that logs all status codes sent by your application.
- Implement a "health check" endpoint that returns different status codes based on your application's status.
- 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! :)