DEV Community

Cover image for # HTTP Response Status Codes Explained: A Complete Guide for Developers
sudip khatiwada
sudip khatiwada

Posted on

# HTTP Response Status Codes Explained: A Complete Guide for Developers

Building APIs without understanding HTTP status codes is like driving without traffic signals—chaotic and error-prone. Every HTTP response your Node.js server sends includes a status code that tells the client exactly what happened with their request. Whether you're debugging a mysterious 500 error or designing a REST API, mastering these codes is non-negotiable.

This guide breaks down HTTP status codes into digestible categories with practical Node.js examples, helping you communicate effectively between client and server.

Meta Description: Complete developer guide to HTTP response status codes covering 1xx-5xx ranges. Learn how to implement proper status codes in Node.js REST APIs with ES6 examples, common HTTP errors, and best practices for API response handling.

Tags: #nodejs #javascript #webdev #api #http

Why HTTP Status Codes Matter

HTTP status codes are three-digit numbers that indicate the outcome of a client's request. They're standardized across the web, making them a universal language between browsers, APIs, and servers.

Understanding these codes helps you:

  • Debug issues faster by identifying whether problems are client-side or server-side
  • Build better APIs with clear, predictable responses
  • Improve user experience through appropriate error handling

Let's explore each category and see them in action.

1xx Informational Responses

These codes indicate that the request was received and the process is continuing. They're rarely used in typical REST API development but are important for protocol-level operations.

Common Codes:

  • 100 Continue: Server has received request headers; client should send the body
  • 101 Switching Protocols: Server is switching protocols as requested (e.g., WebSocket upgrade)
// Rarely implemented manually, but here's the concept
import http from 'node:http';

const server = http.createServer((req, res) => {
  if (req.headers.expect === '100-continue') {
    res.writeContinue();
  }
  // Process request body
});
Enter fullscreen mode Exit fullscreen mode

2xx Success Codes

The request was successfully received, understood, and accepted. These are the happy path responses you want to see.

Essential Success Codes:

  • 200 OK: Standard success response
  • 201 Created: Resource successfully created (POST requests)
  • 204 No Content: Success with no response body (DELETE operations)
import express from 'express';
const app = express();

app.use(express.json());

// 200 OK - Retrieving data
app.get('/users/:id', (req, res) => {
  const user = { id: req.params.id, name: 'John Doe' };
  res.status(200).json(user);
});

// 201 Created - Creating new resource
app.post('/users', (req, res) => {
  const newUser = { id: 'abc123', ...req.body };
  res.status(201).json(newUser);
});

// 204 No Content - Successful deletion
app.delete('/users/:id', (req, res) => {
  // Delete user from database
  res.status(204).send();
});
Enter fullscreen mode Exit fullscreen mode

3xx Redirection Codes

The client must take additional action to complete the request. These manage URL changes and resource locations.

Key Redirection Codes:

  • 301 Moved Permanently: Resource permanently moved to new URL
  • 302 Found: Temporary redirect
  • 304 Not Modified: Cached version is still valid (used with conditional requests)
// 301 Permanent Redirect
app.get('/old-endpoint', (req, res) => {
  res.redirect(301, '/new-endpoint');
});

// 302 Temporary Redirect
app.get('/maintenance', (req, res) => {
  res.redirect(302, '/temporary-page');
});

// 304 Not Modified - Efficient caching
app.get('/static-resource', (req, res) => {
  const lastModified = 'Wed, 21 Oct 2024 07:28:00 GMT';

  if (req.headers['if-modified-since'] === lastModified) {
    return res.status(304).send();
  }

  res.set('Last-Modified', lastModified);
  res.json({ data: 'resource content' });
});
Enter fullscreen mode Exit fullscreen mode

4xx Client Error Codes

The request contains incorrect syntax or cannot be fulfilled. These indicate problems on the client side.

Critical Client Error Codes:

  • 400 Bad Request: Malformed request syntax
  • 401 Unauthorized: Authentication required
  • 403 Forbidden: Server understood but refuses to authorize
  • 404 Not Found: Resource doesn't exist
  • 422 Unprocessable Entity: Valid syntax but semantic errors (validation failures)
// 400 Bad Request - Invalid input
app.post('/validate', (req, res) => {
  if (!req.body.email) {
    return res.status(400).json({ 
      error: 'Email is required' 
    });
  }
  res.json({ message: 'Valid input' });
});

// 401 Unauthorized - Missing authentication
app.get('/protected', (req, res) => {
  const token = req.headers.authorization;

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

// 403 Forbidden - Insufficient permissions
app.delete('/admin/users/:id', (req, res) => {
  const userRole = req.user?.role;

  if (userRole !== 'admin') {
    return res.status(403).json({ 
      error: 'Insufficient permissions' 
    });
  }
  res.status(204).send();
});

// 404 Not Found - Resource doesn't exist
app.get('/users/:id', async (req, res) => {
  const user = await findUserById(req.params.id);

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

// 422 Unprocessable Entity - Validation errors
app.post('/users', (req, res) => {
  const errors = validateUser(req.body);

  if (errors.length > 0) {
    return res.status(422).json({ 
      errors: errors 
    });
  }
  res.status(201).json({ message: 'User created' });
});
Enter fullscreen mode Exit fullscreen mode

5xx Server Error Codes

The server failed to fulfill a valid request. These indicate problems on the server side.

Common Server Error Codes:

  • 500 Internal Server Error: Generic server error
  • 502 Bad Gateway: Invalid response from upstream server
  • 503 Service Unavailable: Server temporarily unavailable (maintenance/overload)
  • 504 Gateway Timeout: Upstream server didn't respond in time
// 500 Internal Server Error - Unexpected failures
app.get('/risky-operation', async (req, res) => {
  try {
    const result = await performComplexOperation();
    res.json(result);
  } catch (error) {
    console.error('Operation failed:', error);
    res.status(500).json({ 
      error: 'Internal server error' 
    });
  }
});

// 503 Service Unavailable - Maintenance mode
const isMaintenanceMode = true;

app.use((req, res, next) => {
  if (isMaintenanceMode) {
    return res.status(503).json({ 
      error: 'Service temporarily unavailable',
      retryAfter: 3600 
    });
  }
  next();
});

// Global error handler
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ 
    error: 'Something went wrong!' 
  });
});
Enter fullscreen mode Exit fullscreen mode

Status Code Quick Reference

Range Category Meaning Example
1xx Informational Request received, continuing process 100 Continue
2xx Success Request successfully processed 200 OK, 201 Created
3xx Redirection Further action needed 301 Moved, 304 Not Modified
4xx Client Error Client request has errors 400 Bad Request, 404 Not Found
5xx Server Error Server failed to fulfill request 500 Internal Error

Best Practices for REST API Status Codes

Use appropriate codes for CRUD operations:

  • GET: 200 (OK) or 404 (Not Found)
  • POST: 201 (Created) or 400 (Bad Request)
  • PUT/PATCH: 200 (OK) or 404 (Not Found)
  • DELETE: 204 (No Content) or 404 (Not Found)

Always include meaningful error messages:

// Good
res.status(404).json({ 
  error: 'User not found',
  userId: req.params.id 
});

// Bad
res.status(404).send();
Enter fullscreen mode Exit fullscreen mode

Distinguish between 401 and 403:

  • Use 401 when authentication is missing or invalid
  • Use 403 when user is authenticated but lacks permissions

Conclusion: Building Clear API Communication

HTTP status codes are your API's voice—they communicate success, failure, and everything in between. By implementing proper status codes in your Node.js applications, you create predictable, debuggable, and professional REST APIs.

Remember: 2xx means success, 4xx means client problems, 5xx means server issues. Master these fundamentals, and you'll spend less time debugging mysterious errors and more time building features.

Start auditing your existing APIs today—are you using the right status codes? Your future self (and your API consumers) will thank you.

Top comments (0)