FastAPI Response Models and Status Codes

A response model controls exactly what your API sends back to the client. A status code tells the client whether the request succeeded, failed, or needs further action. Together they make your API predictable and easy to use.

Why Response Models Matter

Imagine your database stores user records with a password field. Without a response model, you might accidentally send the password to the client. A response model acts as a filter — it only passes through the fields you explicitly allow.

Database record:
{
  "id": 1,
  "name": "Meera",
  "email": "m@example.com",
  "password": "hashed_secret"    ← never send this
}

Response model output (password removed):
{
  "id": 1,
  "name": "Meera",
  "email": "m@example.com"
}

Defining a Response Model

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class UserIn(BaseModel):    ← what client sends
    name: str
    email: str
    password: str

class UserOut(BaseModel):   ← what client receives
    id: int
    name: str
    email: str

@app.post("/users", response_model=UserOut)
def create_user(user: UserIn):
    # Save user to database (password included internally)
    # Return object — FastAPI strips fields not in UserOut
    return {"id": 42, "name": user.name, "email": user.email, "password": user.password}

Even though the returned dictionary contains password, FastAPI removes it because password is not in UserOut. The client never sees it.

Response Model as a Contract

Input model (UserIn)        Output model (UserOut)
┌─────────────────┐         ┌──────────────────┐
│ name: str       │         │ id: int          │
│ email: str      │  API    │ name: str        │
│ password: str   │ ──────▶ │ email: str       │
└─────────────────┘         └──────────────────┘

FastAPI enforces the output shape.
No extra fields escape accidentally.

HTTP Status Codes

Every HTTP response carries a three-digit number that signals the result:

Range    Meaning          Examples
──────────────────────────────────────────────────
2xx      Success          200 OK, 201 Created, 204 No Content
3xx      Redirect         301 Moved, 302 Found
4xx      Client error     400 Bad Request, 401 Unauthorized,
                          403 Forbidden, 404 Not Found,
                          422 Unprocessable Entity
5xx      Server error     500 Internal Server Error

Setting Status Codes in FastAPI

@app.post("/items", status_code=201)   ← 201 Created
def create_item():
    ...

@app.delete("/items/{id}", status_code=204)  ← 204 No Content
def delete_item(id: int):
    return None

Using status_code in the Swagger docs shows the expected response for that route automatically.

Using the status Module for Readable Code

Hard-coding numbers like 201 is error-prone. Use FastAPI's built-in status constants instead:

from fastapi import status

@app.post("/orders", status_code=status.HTTP_201_CREATED)
def place_order():
    return {"order": "placed"}

@app.delete("/orders/{id}", status_code=status.HTTP_204_NO_CONTENT)
def cancel_order(id: int):
    return None

Response Model with a List

Return a list of objects by wrapping the model in List:

from typing import List

@app.get("/users", response_model=List[UserOut])
def get_users():
    return [
        {"id": 1, "name": "Meera", "email": "m@example.com", "password": "x"},
        {"id": 2, "name": "Raj",   "email": "r@example.com", "password": "y"},
    ]

FastAPI filters password from every object in the list.

Excluding Unset Fields from the Response

Use response_model_exclude_unset=True to only return fields that were actually set — useful for PATCH endpoints:

@app.patch("/users/{id}", response_model=UserOut, response_model_exclude_unset=True)
def partial_update(id: int, user: UserOut):
    ...

Key Points

  • The response_model parameter filters the output to only include specified fields.
  • Use separate input and output models to prevent sensitive data leaks.
  • HTTP status codes signal success (2xx), client errors (4xx), or server errors (5xx).
  • Use fastapi.status constants for readable, self-documenting status codes.
  • Response models appear in your API docs, giving clients a clear contract.

Leave a Comment

Your email address will not be published. Required fields are marked *