Skip to content

07 Response Model

DodaTech 4 min read

title: Response Models in FastAPI REST APIs weight: 17 date: 2026-06-28 lastmod: 2026-06-28 description: Master FastAPI response_model for automatic serialization, field filtering, response status codes, response headers, and custom response types with Pydantic models. tags: [api-development, fastapi]


FastAPI response_model defines the shape of API responses using Pydantic models, automatically filtering out excluded fields, serializing data, and generating OpenAPI response schemas for documentation.

```mermaid
flowchart TD
  A[response_model] --> B[Serialization]
  A --> C[Field Filtering]
  A --> D[OpenAPI Schema]
  B --> E[Convert to dict/JSON]
  C --> F[Exclude secrets]
  C --> G[Show only allowed fields]
  D --> H[Response documentation]
  style A fill:#e1f5fe
  style B fill:#c8e6c9
  style C fill:#fff9c4

The response_model parameter in route decorators tells FastAPI to filter and serialize the returned data through a Pydantic model. This ensures the response matches the expected schema, excludes sensitive fields (like passwords), and generates accurate OpenAPI docs.

Think of response_model like a privacy filter for a document. You have a complete document (database model), but you show only certain sections (response model) to the public. The employee record includes salary info, but the public profile only shows name and title.

Example: Basic Response Model

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from datetime import datetime

app = FastAPI()

# Internal model (has password)
class UserInDB(BaseModel):
    id: int
    username: str
    email: str
    password: str
    role: str
    created_at: datetime

# Public model (no password)
class UserPublic(BaseModel):
    id: int
    username: str
    email: str
    role: str
    created_at: datetime

# Create model
class UserCreate(BaseModel):
    username: str
    email: str
    password: str

@app.post("/api/users", response_model=UserPublic, status_code=201)
def create_user(user: UserCreate):
    """Password is automatically excluded from response."""
    db_user = UserInDB(
        id=1,
        username=user.username,
        email=user.email,
        password=user.password,
        role="user",
        created_at=datetime.now()
    )
    return db_user  # Only fields in UserPublic are returned

Example: Multiple Response Models

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class ItemBase(BaseModel):
    name: str
    description: Optional[str] = None

class ItemCreate(ItemBase):
    price: float
    stock: int

class ItemResponse(ItemBase):
    id: int
    price: float
    stock: int
    owner_id: int

class ItemList(BaseModel):
    items: list[ItemResponse]
    total: int
    page: int

@app.post("/api/items", response_model=ItemResponse, status_code=201)
def create_item(item: ItemCreate):
    return {"id": 1, **item.model_dump(), "owner_id": 123}

@app.get("/api/items", response_model=ItemList)
def list_items(page: int = 1, limit: int = 10):
    return {"items": [], "total": 0, "page": page}

Example: Response Model with Status Codes

from fastapi import FastAPI, status
from pydantic import BaseModel

app = FastAPI()

class Message(BaseModel):
    message: str
    detail: Optional[str] = None

@app.delete(
    "/api/items/{item_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    response_class=Response
)
def delete_item(item_id: int):
    return None  # No content

@app.post(
    "/api/items",
    status_code=status.HTTP_201_CREATED,
    response_model=ItemResponse,
    responses={
        400: {"model": Message, "description": "Bad request"},
        409: {"model": Message, "description": "Conflict"}
    }
)
def create_item(item: ItemCreate):
    if item.name == "exists":
        from fastapi import HTTPException
        raise HTTPException(
            status_code=409,
            detail=Message(message="Item already exists").model_dump()
        )
    return {"id": 1, **item.model_dump(), "owner_id": 123}

Common Mistakes

  1. Not using response_model — Without response_model, all fields from the returned object are exposed, including sensitive fields like password.
  2. Mixing response_model with manual serialization — If you manually call .model_dump(), FastAPI's response_model serialization applies again. Return the model instance, not a dict.
  3. Forgetting to set status_code — POST returns 200 by default. Set status_code=201 or use status.HTTP_201_CREATED.
  4. Using the same model for input and output — Create separate models for input (with password) and output (without password). Never reuse the same schema.
  5. Not handling 204 responses — Status 204 returns no content. Ensure the handler returns None (not an empty dict) for 204.

Practice Questions

  1. What is the purpose of response_model in FastAPI?
  2. How do you exclude sensitive fields from the response?
  3. What status code should a POST endpoint use?
  4. How do you add custom error response schemas to OpenAPI docs?
  5. Challenge: Create a user management API with three response models: UserPublic (no sensitive data), UserPrivate (includes email), and UserAdmin (includes all fields including password hash). Apply the appropriate model based on the authenticated user's role.

FAQ

What is the difference between response_model and returning a dict?

response_model filters and serializes the response. Returning a dict bypasses serialization but you lose automatic documentation and filtering.

Can I have different response models for success and error?

Yes, use the responses parameter in the decorator to document error response schemas. The actual error response is raised via HTTPException.

How do I return a list with response_model?

Use response_model=list[ItemResponse]. FastAPI serializes each item in the list through the model.

What is the exclude parameter in response_model?

response_model_exclude and response_model_include allow you to dynamically exclude or include fields without creating new models.

Does response_model affect performance?

The overhead is minimal. FastAPI serializes the response through Pydantic, which is highly optimized in v2. The benefit of automatic docs and filtering outweighs the cost.

Mini Project

Create a blog API with separate request and response models for each resource. Include: UserCreate/UserResponse (exclude password), PostCreate/PostResponse (include author name, exclude internal_id), CommentCreate/CommentResponse (include post title). Use status codes, error response schemas, and response_model_exclude for admin endpoints.

What's Next

Now learn about status codes in Building REST APIs with FastAPI.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro