DEV Community

Jane for Mastering Backend

Posted on • Originally published at masteringbackend.com on

HTTP Status Codes for Clear API Responses

title

Learn how to use HTTP status codes effectively in your FastAPI projects for clear, consistent API responses.

Introduction

APIs (Application Programming Interfaces) are essential for software, enabling communication between clients and servers. Most web APIs, especially RESTful APIs, operate over the HTTP protocol, which defines how data is transmitted across the internet. HTTP not only facilitates data exchange but also includes status codes, which tell clients what happened on the server. The HTTP status codes are three-digit codes that summarize the result of a request.

Whether you’re building a backend with FastAPI or consuming an external service, understanding and using the right HTTP status codes helps ensure clear communication, better debugging, and a professional API interface.

HTTP Methods in APIs

HTTP methods define the type of operation a client wants to perform on a resource. Pairing them with the correct status codes improves clarity.

example of http method

Common HTTP Status Codes

Here are some commonly used HTTP status codes in API development:

  • 200 OK - Request Successful
  • 201 Created - A resource was successfully created
  • 204 No Content - Success, but no data returned
  • 400 Bad Request - Validation errors (Client sent invalid input)
  • 401 Unauthorized - Authentication failure (Missing or invalid credentials)
  • 403 Forbidden - Access denied (Not allowed)
  • 404 Not Found - Resource not found
  • 409 Conflict - Resource state conflict
  • 422 Unprocessable Entity - Validation failed (common with Pydantic)
  • 500 Internal Server Error - Server crashed or encountered an unexpected error

Using HTTPException for Custom Errors

FastAPI allows you to raise exceptions with specific status codes using HTTPException :

from fastapi import FastAPI, HTTPException 

app = FastAPI() 

@app.get("/books/{book_id}") 
async def read_book(book_id: int): 
        # Simulate checking a database for the book 
     if book_id != 1: 
     # Raise a 404 if the book is not found 
          raise HTTPException(status_code=404, detail="Book not found") 
      return {"book_id": book_id, "title": "The Hobbit"}
Enter fullscreen mode Exit fullscreen mode

In this example, when a client requests a specific book, the server checks if it exists (in this case, only book with ID 1 exists). If it doesn’t, we raise a 404 Not Found, letting the client know the resource doesn't exist. This is clearer than returning a generic 200 OK with a confusing response.

Handling Validation Errors (422)

FastAPI uses Pydantic for input validation. If the input doesn’t meet the model’s expected structure or data types, FastAPI automatically returns a 422 status code. This helps you avoid manually checking data types in every route.

from pydantic import BaseModel 

class Book(BaseModel): 
    title: str # Title must be a string 
    pages: int # Pages must be an integer 
@app.post("/books") 
def create_book(book: Book): 
     return book
Enter fullscreen mode Exit fullscreen mode

Try sending invalid input like:

{"title": "Book", "pages": "not-a-number"}
Enter fullscreen mode Exit fullscreen mode

FastAPI will respond with a _422: Unprocessable entity _ error.

Returning Custom Status Codes

To customize the status code in a response, use the status_code parameter:

from fastapi import status 

@app.post("/books", status_code=status.HTTP_201_CREATED) 
def add_book(book: Book): 
     return {"message": "Book created successfully"}
Enter fullscreen mode Exit fullscreen mode

Using 201 Created tells the client that a new resource was successfully created, which is more specific than 200 OK.

Custom Exception Handlers

By default, FastAPI will return a standard error structure when input validation fails. But in some cases (e.g., when building an API for a frontend app), you may want to customize the error response to fit your frontend’s expected structure.

You can define a handler for RequestValidationError , returning a structured JSON with a human-readable message ("Validation failed") and additional details.

from fastapi import FastAPI, Request 
from fastapi.responses import JSONResponse 
from fastapi.exceptions import RequestValidationError 
from pydantic import BaseModel 

app = FastAPI() 

# Custom Exception Handler 
@app.exception_handler(RequestValidationError) 
async def validation_exception_handler(request: Request, exc: RequestValidationError): 
     return JSONResponse( 
          status_code=422, 
          content={ 
               "message": "Validation failed", 
                "errors": exc.errors(), 
                 "body": exc.body, 
        }, 
     ) 

# Pydantic Model 
 class Book(BaseModel): 
      title: str 
       pages: int 

# Route expecting valid input 
@app.post("/books") 
async def create_book(book: Book): 
      return {"message": "Book created", "book": book}
Enter fullscreen mode Exit fullscreen mode

How it works

When a client sends an invalid request,

{ 
"title": "Purple Hibiscus", 
"pages": "not-a-number" 
}
Enter fullscreen mode Exit fullscreen mode

FastAPI will:

  • Detect the invalid pages value (should be an int)
  • Trigger RequestValidationError
  • Use your custom validation_exception_handler to return a structured error.

Example of Custom Response

{ 
   "message": "Validation failed", 
   "errors": [ 
     { 
        "type": "int_parsing", 
         "loc": [ 
            "body", 
            "pages" 
        ], 
        "msg": "Input should be a valid integer, unable to parse string as an integer", 
        "input": "A string" 

      } 
    ], 
    "body": { 
       "title": "string", 
       "pages": "A string" 

     } 
   }
Enter fullscreen mode Exit fullscreen mode

Using status Module for Clean Code

Avoid hardcoding status codes. Use the fastapi.status module for improved readability. FastAPI provides a built-in status module that contains named constants for all standard HTTP status codes. Instead of writing "magic numbers" like 404 or 403 directly in your code, you can use readable constants like:

status.HTTP_404_NOT_FOUND 
status.HTTP_403_FORBIDDEN 
status.HTTP_201_CREATED
Enter fullscreen mode Exit fullscreen mode
from fastapi import status 

raise HTTPException( 
                 status_code=status.HTTP_403_FORBIDDEN, 
                 detail="Access denied" 
                 )
Enter fullscreen mode Exit fullscreen mode

FAQ: HTTP Status Codes in FastAPI

Q: What status code should I return when data is created?

A: Use 201 Created to indicate that a resource was successfully created.

Q: What does 422 Unprocessable Entity mean?

A: It means the input was syntactically valid but semantically incorrect-often used when validation fails.

Q: How do I raise a 404 error in FastAPI?

A: Use raise HTTPException(status_code=404, detail="Not found").

Q: What’s the difference between 401 and 403?

A: 401 Unauthorized means no or invalid credentials; 403 Forbidden means valid credentials but no permission.

Conclusion

Using the right HTTP status codes in your API makes your application more predictable, user-friendly, and easier to debug. FastAPI makes it easy to handle errors the right way:

  • Use standard status codes consistently.
  • Prefer descriptive errors over vague responses.
  • Add custom error handlers for better control.
  • Use the status module to avoid magic numbers.

For production-ready APIs, also consider logging, monitoring, and documenting your error responses consistently.

TL;DR

  • Use HTTPException to raise clear, standard errors.
  • Customize responses with status_code, detail, or exception handlers.
  • Let Pydantic and FastAPI handle validation automatically (422).

References

Have a great one !!!

Author: Jane Nkwor


Thank you for being a part of the community

Before you go:

Whenever you’re ready

There are 4 ways we can help you become a great backend engineer:

  • The MB Platform: Join thousands of backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.
  • The MB Academy: The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.
  • Join Backend Weekly: If you like posts like this, you will absolutely enjoy our exclusive weekly newsletter, sharing exclusive backend engineering resources to help you become a great Backend Engineer.
  • Get Backend Jobs: Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board.

Originally published at https://masteringbackend.com on June 24, 2025.


Top comments (0)