Learn / Frameworks / FastAPI / Models, Responses and Errors

FastAPI · Lesson 3 of 5

Models, Responses and Errors

Response models, status codes and raising HTTP errors.

  • Intermediate
  • 15 min read
  • 3 objectives

Before this lessonLesson 2: Path, Query and Body Parameters

What you will learn

  • Declare response_model
  • Set status codes
  • Raise HTTPException

How an API replies matters as much as what it accepts: the right shape, the right status code and helpful errors. FastAPI makes each of these explicit.

Response models

Declaring a response_model filters the output to exactly the fields you specify. This is how you avoid accidentally leaking secrets, such as a password hash.

from pydantic import BaseModel

class UserIn(BaseModel):
    username: str
    password: str

class UserOut(BaseModel):
    id: int
    username: str

@app.post("/users", response_model=UserOut, status_code=201)
def create_user(user: UserIn):
    saved = {"id": 1, "username": user.username, "password": "hashed..."}
    return saved            # password is removed by UserOut

Status codes

  • 200 OK: success (default).
  • 201 Created: a resource was created (POST).
  • 204 No Content: success with nothing to return (DELETE).
  • 400 / 422: bad input. 401 / 403: not authenticated / not allowed. 404: not found. 409: conflict.

Raising errors

from fastapi import HTTPException, status

users = {1: {"id": 1, "username": "ada"}}

@app.get("/users/{user_id}", response_model=UserOut)
def get_user(user_id: int):
    if user_id not in users:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    return users[user_id]

@app.delete("/users/{user_id}", status_code=204)
def delete_user(user_id: int):
    if users.pop(user_id, None) is None:
        raise HTTPException(404, "User not found")
Output
// GET /users/99
{"detail":"User not found"}

Custom exception handlers

from fastapi.responses import JSONResponse

class OutOfStock(Exception):
    def __init__(self, item): self.item = item

@app.exception_handler(OutOfStock)
def out_of_stock_handler(request, exc: OutOfStock):
    return JSONResponse(status_code=409, content={"error": f"{exc.item} is out of stock"})

Lists and pagination

from typing import List

@app.get("/users", response_model=List[UserOut])
def list_users(skip: int = 0, limit: int = 20):
    return list(users.values())[skip: skip + limit]
# Write your solution here
Up next · Lesson 4Dependency Injection and AuthShare logic with Depends, and protect routes with tokens.