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.
Method | Use Case | Example |
| Retrieve data |
|
| Create new data |
|
| Replace a resource entirely |
|
| Partially update a resource |
|
| Delete a resource |
|
Common HTTP Status Codes
Here are some commonly used HTTP status codes in API development:
200 OK
– Request Successful201 Created
– A resource was successfully created204 No Content
– Success, but no data returned400 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 found409 Conflict
– Resource state conflict422 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"}
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
Try sending invalid input like:
{"title": "Book", "pages": "not-a-number"}
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"}
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}
How it works
When a client sends an invalid request,
{
"title": "Purple Hibiscus",
"pages": "not-a-number"
}
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"
}
}
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
from fastapi import status
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied"
)
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).