Handling Errors and HTTP Status Codes in APIs

Throw errors like a pro

Last updated: 3/5/2025

1 hour
Medium

Handling Errors and HTTP Status Codes in APIs

🌍 Introduction

In a RESTful API, error handling is crucial for providing clear and useful feedback to clients.
When something goes wrong (e.g., invalid input, unauthorized access, server issues), the API should:

  • Return a meaningful error message.
  • Use the correct HTTP status code.
  • Follow a consistent error response format.

In this lesson, you'll learn:

  • Common HTTP status codes for success and errors.
  • How to handle client-side vs. server-side errors.
  • Best practices for structuring error responses.

πŸ“Œ 1. Understanding HTTP Status Codes

HTTP status codes indicate the result of a request.
They are divided into different categories:

Code RangeTypeDescription
2xxβœ… SuccessRequest was successful.
3xxπŸ”€ RedirectionClient needs to follow another URL.
4xx⚠️ Client ErrorsSomething is wrong with the request.
5xxπŸ”₯ Server ErrorsSomething is wrong with the server.

βœ… Common HTTP Status Codes

CodeNameMeaning
200OKSuccessful request.
201CreatedResource created successfully.
400Bad RequestThe request is invalid (e.g., missing required fields).
401UnauthorizedAuthentication is required.
403ForbiddenUser doesn’t have permission.
404Not FoundThe resource does not exist.
409ConflictData conflict (e.g., duplicate username).
500Internal Server ErrorSomething went wrong on the server.

πŸ“Œ 2. Client Errors (4xx)

Client errors occur when the request is incorrect.
Example: A user tries to fetch a non-existent user.

❌ Bad Example (No Proper Error Handling)

app.get('/users/:id', (req, res) => { const user = null; // Simulating user not found res.json(user); // ❌ This will return null instead of an error });

βœ… Good Example (Proper Error Handling)

app.get('/users/:id', (req, res) => { const user = null; // Simulating user not found if (!user) { return res.status(404).json({ error: "User not found", message: "The user with the given ID does not exist." }); } res.json(user); });

πŸ”Ή Best Practices:

βœ” Always return a meaningful error message.
βœ” Use the correct status code (400, 404, etc.).
βœ” Include details about what went wrong.


πŸ“Œ 3. Server Errors (5xx)

Server errors occur when something goes wrong on the backend.
Example: A database failure causes an API request to fail.

❌ Bad Example (No Error Handling)

app.get('/users', (req, res) => { throw new Error("Database failure"); // ❌ This will crash the server });

βœ… Good Example (Handling Server Errors)

app.get('/users', (req, res, next) => { try { throw new Error("Database failure"); // Simulated server error } catch (error) { next(error); // Pass error to global error handler } }); // Global Error Handler Middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: "Internal Server Error", message: "Something went wrong on our end." }); });

πŸ”Ή Best Practices:

βœ” Always catch unexpected errors.
βœ” Use a global error handler to handle errors consistently.
βœ” Never expose sensitive server details in error responses.


πŸ“Œ 4. Structuring API Error Responses

A consistent error response format makes it easier for clients to handle errors.

βœ… Example of a Good Error Response Format

{ "error": "Bad Request", "message": "Email is required", "statusCode": 400 }

βœ… Example of a More Detailed Error Response

{ "error": "Validation Error", "message": "Invalid input data", "details": [ { "field": "email", "message": "Email is required" }, { "field": "password", "message": "Password must be at least 8 characters" } ], "statusCode": 400 }

πŸ“Œ 5. Implementing a Global Error Handler in Express.js

Instead of handling errors individually, a global error handler ensures consistency.

πŸš€ Example: Express.js Global Error Handler

const express = require('express'); const app = express(); app.use(express.json()); // Example Route with Error Handling app.get('/users/:id', (req, res, next) => { try { const user = null; // Simulating user not found if (!user) { throw { status: 404, message: "User not found" }; } res.json(user); } catch (error) { next(error); // Pass error to the error handler } }); // Global Error Handling Middleware app.use((err, req, res, next) => { res.status(err.status || 500).json({ error: err.status ? "Client Error" : "Server Error", message: err.message || "Something went wrong" }); }); app.listen(3033, () => console.log('Server running on port 3033'));

🎯 Summary

  • Use the correct HTTP status codes to indicate the result of a request.
  • Client errors (4xx) happen when requests are incorrect (e.g., 404 Not Found).
  • Server errors (5xx) happen when something goes wrong on the backend (e.g., 500 Internal Server Error).
  • Always return clear and structured error messages.
  • Use a global error handler for better error management.

βœ… Next Lesson: Introduction to CRUD Operations in REST APIs

In the next lesson, you'll learn how to perform CRUD (Create, Read, Update, Delete) operations using RESTful APIs. You’ll see how each HTTP method maps to a CRUD action! πŸš€