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:
1from typing import Literal2from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator34class Message(BaseModel):5 model_config = ConfigDict(str_strip_whitespace=True)6 role: Literal["system", "user", "assistant"]7 content: str89class ChatRequest(BaseModel):10 model_config = ConfigDict(extra="forbid")11 messages: list[Message] = Field(min_length=1)12 temperature: float = Field(0.7, ge=0.0, le=2.0)13 max_tokens: int = Field(512, gt=0)1415 @field_validator("messages")16 @classmethod17 def last_is_user(cls, v: list[Message]) -> list[Message]:18 if v[-1].role != "user":19 raise ValueError("last message must come from the user")20 return v2122 @model_validator(mode="after")23 def fits_budget(self) -> "ChatRequest":24 prompt_chars = sum(len(m.content) for m in self.messages)25 if prompt_chars // 4 + self.max_tokens > 8000: # rough: 4 characters per token26 raise ValueError("prompt plus max_tokens exceeds the 8k context")27 return selfReal results:
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| Tool | Use it for |
|---|---|
Field(...) | Limits and metadata: ge, le, min_length, pattern, description, examples |
Literal[...] | A closed set of allowed values |
@field_validator | A 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
1from pydantic_settings import BaseSettings, SettingsConfigDict23class Settings(BaseSettings):4 model_config = SettingsConfigDict(env_prefix="APP_")5 llm_api_key: str6 max_concurrency: int = 16With 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 v1 | Pydantic v2 |
|---|---|
class Config: inside the model | model_config = ConfigDict(...) |
@validator / @root_validator | @field_validator / @model_validator |
.dict(), .json() | .model_dump(), .model_dump_json() |
parse_obj, parse_raw | model_validate, model_validate_json |
orm_mode = True | from_attributes=True |
BaseSettings in pydantic | BaseSettings 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"andmode="after"validators?" —beforeruns on the raw input, before type conversion (useful to clean data);afterruns 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.