FastAPI Essentials

Course Content

FastAPI Essentials

1 sections · 32 lessons

Explain the role of Pydantic in FastAPI


What you need to know

The basics — Pydantic validates requests, serialises responses and generates JSON Schema — are covered in the earlier Pydantic question. Here the interviewer usually wants to hear that you can use the toolkit. Here is a chat request for an LLM endpoint:

Python
from typing import Literalfrom pydantic import BaseModel, ConfigDict, Field, field_validator, model_validatorclass Message(BaseModel):    model_config = ConfigDict(str_strip_whitespace=True)    role: Literal["system", "user", "assistant"]    content: strclass ChatRequest(BaseModel):    model_config = ConfigDict(extra="forbid")    messages: list[Message] = Field(min_length=1)    temperature: float = Field(0.7, ge=0.0, le=2.0)    max_tokens: int = Field(512, gt=0)    @field_validator("messages")    @classmethod    def last_is_user(cls, v: list[Message]) -> list[Message]:        if v[-1].role != "user":            raise ValueError("last message must come from the user")        return v    @model_validator(mode="after")    def fits_budget(self) -> "ChatRequest":        prompt_chars = sum(len(m.content) for m in self.messages)        if prompt_chars // 4 + self.max_tokens > 8000:     # rough: 4 characters per token            raise ValueError("prompt plus max_tokens exceeds the 8k context")        return self

Real results:

Text
content "  Hi  "                 -> 'Hi'  (whitespace stripped)last message from assistant      -> ('messages',) Value error, last message must come from the usermax_tokens 9000                  -> () Value error, prompt plus max_tokens exceeds the 8k context"temprature": 0.1 (typo)         -> ('temprature',) Extra inputs are not permitted
ToolUse it for
Field(...)Limits and metadata: ge, le, min_length, pattern, description, examples
Literal[...]A closed set of allowed values
@field_validatorA custom rule on one field
@model_validator(mode="after")A rule that needs several fields together
model_config = ConfigDict(...)Behaviour: extra="forbid", strict=True, from_attributes=True
model_dump() / model_dump_json()Model to dict or JSON
model_validate() / model_validate_json()Dict or JSON text to a validated model

Note that model_config applies only to the model where it is written. That is why str_strip_whitespace sits on Message, not on ChatRequest.

Settings and LLM output

Python
from pydantic_settings import BaseSettings, SettingsConfigDictclass Settings(BaseSettings):    model_config = SettingsConfigDict(env_prefix="APP_")    llm_api_key: str    max_concurrency: int = 16

With APP_LLM_API_KEY=sk-test and APP_MAX_CONCURRENCY=32 in the environment, Settings() gives llm_api_key='sk-test' max_concurrency=32: typed, validated, and the app refuses to start if the key is missing.

For structured output, Answer.model_validate_json(llm_reply) turned the model's reply {"answer": "...", "sources": [3, "7"]} into sources=[3, 7], and it would raise a clear error if the model left out answer.

Moving from v1 to v2

Pydantic v1Pydantic v2
class Config: inside the modelmodel_config = ConfigDict(...)
@validator / @root_validator@field_validator / @model_validator
.dict(), .json().model_dump(), .model_dump_json()
parse_obj, parse_rawmodel_validate, model_validate_json
orm_mode = Truefrom_attributes=True
BaseSettings in pydanticBaseSettings in the separate pydantic-settings package

A real-life example

An insurance company's claims assistant sends the whole chat history to an LLM with an 8k-token context. Clients sometimes asked for max_tokens: 8000 on top of a long history, and the provider rejected the call after a 2-second round trip. The team added the fits_budget model validator. Over-budget requests now fail in under a millisecond with a message that says exactly what to change, and wasted provider calls dropped to zero.

The same ChatRequest model is imported by the evaluation scripts, so offline tests and the live API follow identical rules.

Follow-up questions to expect

  • "What is the difference between mode="before" and mode="after" validators?" — before runs on the raw input, before type conversion (useful to clean data); after runs on the typed, validated values.
  • "How do you return an ORM object from a route?" — Set model_config = ConfigDict(from_attributes=True) on the response model so Pydantic reads attributes, not dict keys.
  • "Why did v2 get faster?" — Validation moved into pydantic-core, written in Rust; the Python classes describe the schema, and the core runs it.