Python for JS Devs · FastAPI

Params & response models

FastAPI decides path vs query vs body from your signature. And response_model guarantees what leaves your API — including hiding secrets.

Lesson 13Time ~13 min Win Shape an output & strip a password fieldPrereq Lesson 12

1 · How FastAPI classifies a parameter

No req.params/req.query/req.body juggling. FastAPI infers the source from three rules:

@app.put("/users/{user_id}")
def update(user_id: int, notify: bool = False, body: UserUpdate):
    # user_id → path   notify → query (?notify=true)   body → JSON body
    ...

You can add validation/metadata with Path(...), Query(...) — e.g. q: str = Query(min_length=3). Same constraint vocabulary as Pydantic Field.

2 · response_model — the output contract

Returning a dict works, but declaring response_model makes FastAPI validate, filter, and document the response. The killer use: your DB object has a password_hash; your response model doesn't — so it's stripped automatically.

class UserOut(BaseModel):
    id: int
    email: EmailStr
    name: str
    # note: no password_hash field

@app.get("/users/{user_id}", response_model=UserOut)
def get_user(user_id: int):
    return db.fetch_user(user_id)   # may include password_hash…
    # …but UserOut filters it out of the actual response
Why this is safer than JS habits In Express you manually pick fields ({ id, email }) and one forgotten spread leaks a secret. Here the type is the guarantee: anything not on UserOut cannot be serialized out, and the shape is enforced and documented. Input model (UserCreate) and output model (UserOut) being separate is the standard pattern.

3 · Status codes & the pattern

@app.post("/users", response_model=UserOut, status_code=201)
def create_user(payload: UserCreate):
    ...

Declare the success status inline. (Error statuses come via HTTPException — Lesson 15.) The three-model rhythm — UserCreate in, DB object in the middle, UserOut out — is how real FastAPI apps are shaped.

🎯 Your win

Make a fake user dict that includes "password_hash". Define UserOut without that field, add response_model=UserOut to a GET route that returns the dict, and confirm in /docs that the response has no password. Watching the secret get stripped by the type alone is the win.

Check yourself

Q1. A Pydantic-model parameter is read from the:
Models map to the request body; scalars map to path (if named) or query.
Q2. Setting response_model on a route will:
It validates and filters the response to exactly the model's fields — stripping anything extra, like secrets.
Q3. The standard way to hide a password from output is to:
Use a separate output model without the field; FastAPI won't serialize what isn't declared.
Primary source FastAPI — Response Model and Query Parameters.
💬 Ask your teacher: when should I use response_model_exclude_none or model aliases (camelCase JSON)? Common in real APIs consumed by JS frontends.