← Back to FastAPI map
FastAPI · HTTP layer

Responses

Using response_model to drop fields you do not want to send, setting the status code, and picking a response type.

output

Overview

What a handler returns is only part of the response. response_model decides which fields leave the server: FastAPI validates the return value against it and drops anything not declared, so a password hash cannot leak just because the handler returned a whole user object. For full control - custom headers, files, redirects, streams - return a Response subclass directly.

Key concepts

Output filtering
The return value passes through response_model. Extra fields are dropped; a missing required field is a server-side error, not something the client sees silently.
Return annotations
Annotating the handler with -> UserOut works like response_model in recent FastAPI versions.
exclude_unset / exclude_none
Send only the fields that were actually set, or skip nulls - useful for sparse and PATCH-style responses.
Response classes
JSONResponse, RedirectResponse, FileResponse, and StreamingResponse bypass response_model - you are responsible for what they contain.

Best practices

  • Declare a response model for every endpoint that returns database objects.
  • Use status constants such as status.HTTP_201_CREATED rather than bare numbers.
  • Stream large or slow outputs - files, LLM tokens - with StreamingResponse instead of building them in memory.

Response model

response_model - filter output

Core
# response_model strips fields not in UserOut # even if the handler returns a UserIn object @app.post("/users", response_model=UserOut, status_code=201) async def create_user(user: UserIn): return user # password auto-stripped by response_model # Strip None and unset fields @app.get( "/items/{id}", response_model=Item, response_model_exclude_none=True, response_model_exclude_unset=True, response_model_exclude={"internal_id"}, # remove specific fields response_model_include={"name", "price"}, # or include only these ) async def get_item(id: int): ...

Status codes + response types

Responses
from fastapi import status from fastapi.responses import ( JSONResponse, HTMLResponse, PlainTextResponse, RedirectResponse, FileResponse, StreamingResponse ) # Common patterns @app.post("/items", status_code=status.HTTP_201_CREATED) async def create(item: Item): return item @app.delete("/items/{id}", status_code=status.HTTP_204_NO_CONTENT) async def delete(id: int): return # no body # Custom JSON with headers @app.get("/custom") async def custom(): return JSONResponse( content={"msg": "ok"}, headers={"X-Custom": "value"} ) # Redirect @app.get("/old") async def old(): return RedirectResponse("/new", status_code=301) # File download @app.get("/download/{name}") async def download(name: str): return FileResponse(path=f"files/{name}", filename=name) # Streaming (AI output, large data) async def gen(): for chunk in ["Hello", " World"]: yield chunk @app.get("/stream") async def stream(): return StreamingResponse(gen(), media_type="text/plain")

Watch out: FileResponse(path=f"files/{name}") trusts the client-supplied name. Reject names containing ".." or "/" before serving, or a request can read files outside the folder.

Comments

Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.

Loading comments...