70 FastAPI Interview Questions and Answers (2026)

FastAPI has quietly become the default for shipping Python APIs and AI/ML backends. That means more companies run it in production, and interviewers now expect real fluency — not just "I read the docs once." Walk in shaky on async, dependency injection, or the request lifecycle and you'll lose the offer to someone who didn't.
This guide gives you 70 questions with concise, interview-ready answers and code where it actually helps. We work Junior to Mid to Senior, so you build from fundamentals up to the deep stuff — ASGI internals, validation, security, testing, and performance. Work through it and you'll have an answer ready for whatever they throw at you.
Q1.What is FastAPI and what are the three main technologies it is built upon?
FastAPI and what are the three main technologies it is built upon?FastAPI is a modern, high-performance Python web framework for building APIs, using standard type hints to give automatic validation, serialization, and interactive docs. It stands on three core technologies.
Starlette
The ASGI toolkit underneath: routing, middleware, requests/responses, WebSockets, and the async machinery.
Pydantic
Data validation and serialization driven by Python type hints; defines request/response models.
Python type hints
Standard annotations power parameter parsing, validation, editor autocompletion, and OpenAPI schema generation.
On top of these, FastAPI auto-generates OpenAPI docs (Swagger UI and ReDoc).
Q2.What is an ASGI server, and which one is most commonly used with FastAPI?
ASGI server, and which one is most commonly used with FastAPI?An ASGI server is the process that implements the ASGI protocol: it owns the event loop, accepts network connections, and translates raw HTTP/WebSocket traffic into ASGI events your FastAPI app handles. Uvicorn is the most common choice.
What it does
Runs the event loop, manages connections, and calls your app with scope/receive/send.
FastAPI itself is just the app; it does not listen on a socket.
Common servers
Uvicorn: built on uvloop and httptools, the default pairing for FastAPI.
Often run under Gunicorn with Uvicorn workers, or alternatives like Hypercorn.
Q3.What is the fundamental difference between FastAPI, Flask, and Django?
FastAPI, Flask, and Django?All three are Python web frameworks, but they differ in concurrency model and scope: Django is a batteries-included synchronous framework, Flask is a minimal synchronous microframework, and FastAPI is an async, type-driven API framework.
Django
Full-stack: ORM, admin, auth, templates included. Primarily synchronous (async support added gradually).
Best for large server-rendered apps needing built-in tooling.
Flask
Minimal WSGI microframework: you assemble extensions yourself. Synchronous by default.
Best for small apps or when you want full control of the stack.
FastAPI
Async ASGI framework focused on APIs; type hints drive validation, serialization, and auto docs.
Best for high-concurrency I/O APIs and modern JSON services.
Q4.How does FastAPI use Pydantic for data validation and serialization?
FastAPI use Pydantic for data validation and serialization?FastAPI uses Pydantic models to declare the shape of request and response data: incoming JSON is parsed and validated against the model, and outgoing objects are serialized back to JSON according to it.
Request validation
Declaring a parameter typed as a Pydantic model makes FastAPI parse the body, coerce types, and raise a 422 error with details if validation fails.
Serialization
Returned models are converted to JSON-compatible data, handling types like datetime and UUID automatically.
Documentation
Each model's fields become part of the OpenAPI schema, driving the interactive docs.
Q5.Explain the difference between Path parameters and Query parameters and when to use each.
Path parameters are part of the URL path itself and identify a specific resource; query parameters come after the ? and refine, filter, or paginate a request. Use path params for required resource identity, query params for optional modifiers.
Path parameters
Embedded in the route, e.g. /users/{user_id}; always required.
Best for identifying a specific entity in a hierarchy.
Query parameters
Appended as ?limit=10&active=true; can be optional with defaults.
Best for filtering, sorting, pagination, and search.
How FastAPI decides
A function arg whose name matches a {placeholder} in the path is a path param; other scalar args become query params.
Q6.Explain the difference between a Path parameter, a Query parameter, and a Body parameter in terms of how FastAPI parses them.
FastAPI parses them.FastAPI distinguishes the three by where it reads the value from: path params come from the URL template, query params from the URL query string, and body params from the (usually JSON) request body. It decides based on the parameter's name, type, and declared markers.
Path parameter
Matched because the arg name appears in the route as {name}; parsed from the path string and validated/coerced to the type.
Query parameter
A scalar arg (int, str, bool) not in the path; read from the query string and coerced.
Body parameter
A Pydantic model (or value marked with Body()) is read from the request body and JSON-parsed.
The defaulting rule
In the path, it's a path param; a Pydantic model, it's body; otherwise it's a query param.
You can override with explicit markers: Path(), Query(), Body().
Q7.How do you extract data from Headers and Cookies in a FastAPI path operation?
FastAPI path operation?You declare them like any other parameter, but mark them with the Header() and Cookie() functions so FastAPI reads from the request headers and cookies instead of the path or query string. They get the same validation and docs treatment as other params.
Headers with Header()
By default underscores in the parameter name convert to hyphens: user_agent reads User-Agent.
Disable with Header(convert_underscores=False) for nonstandard header names.
Declare a list[str] to capture repeated headers.
Cookies with Cookie()
Works the same way; the parameter name matches the cookie name.
Optional vs required
Give a default (e.g. None) to make it optional, or ... to require it.
Q8.How do you add validation constraints (like minimum length or numeric ranges) to query and path parameters using Query and Path?
Query and Path?You declare the parameter's default as a Query() or Path() object and pass validation keywords to it: FastAPI enforces them and reflects the rules in the OpenAPI schema.
String constraints
min_length, max_length, and pattern (a regex) validate text length and format.
Numeric constraints
ge/gt and le/lt set inclusive/exclusive bounds on int and float values.
Path params are always required
Use Path(...) only to attach validation/metadata; they can't be optional since they're part of the URL.
Metadata for docs
title, description, and example enrich the generated docs without affecting validation.
On failure FastAPI returns a 422 with a clear JSON error body automatically.
Q9.How do you set a custom HTTP status code for a FastAPI response?
FastAPI response?Set status_code on the path operation decorator for the default success code, or mutate/return a Response object for dynamic codes.
Static per-route code
Pass status_code=201 (or status.HTTP_201_CREATED) to @app.post(...); this is the documented success status.
Dynamic code at runtime
Inject response: Response and set response.status_code while still returning your normal data.
Returning a Response directly
Return e.g. JSONResponse(content=..., status_code=...) for full control.
Errors
Raise HTTPException(status_code=404, ...) for error responses.
Use the status module constants for readability over magic numbers.
Q10.What is an APIRouter in FastAPI, and how does it help you structure a large application?
APIRouter in FastAPI, and how does it help you structure a large application?An APIRouter is a mini-FastAPI app: a group of related routes you define in a separate module and then plug into the main app with include_router(), keeping large codebases modular.
Modular organization
Split endpoints by domain (users, items, auth) into their own files, each with its own router.
Shared configuration
Set prefix, tags, dependencies, and responses once for the whole group instead of per route.
Reusable and testable
Routers can be developed, tested, and even versioned independently (e.g. mount under /v1 and /v2).
Same decorators
You use @router.get(...) exactly like @app.get(...).
Q11.How does FastAPI generate its interactive API documentation (Swagger/ReDoc) automatically?
FastAPI generate its interactive API documentation (Swagger/ReDoc) automatically?FastAPI introspects your type hints, Pydantic models, and path operation parameters to build an OpenAPI (JSON) schema at startup, then serves Swagger UI and ReDoc that render that schema interactively.
OpenAPI schema is the source of truth
Generated from your routes, parameters, request/response models, and status codes; served at /openapi.json.
Built from type hints
Pydantic models become JSON Schema definitions; Query/Path metadata and docstrings enrich descriptions.
Two UIs out of the box
Swagger UI at /docs (interactive, lets you try requests) and ReDoc at /redoc (reference style).
Customizable
Override via tags, summary, description, and response_model; you can disable docs by setting docs_url=None.
Q12.How do you write tests for FastAPI endpoints using TestClient?
FastAPI endpoints using TestClient?Use FastAPI's TestClient (built on requests/httpx) to make in-process HTTP calls against your app and assert on status codes and JSON, typically driven by pytest.
Construct it from the app
client = TestClient(app) then call client.get(...), client.post(...); it runs the ASGI app without a live server.
Assert on the response
Check response.status_code and response.json().
Isolate dependencies
Override DB/auth with app.dependency_overrides so tests hit fakes, not real services.
Async note
TestClient is synchronous (it manages the loop for you); for fully async tests use httpx.AsyncClient with an ASGI transport.
Q13.Explain the difference between ASGI and WSGI. Why does FastAPI specifically require an ASGI server like Uvicorn?
ASGI and WSGI. Why does FastAPI specifically require an ASGI server like Uvicorn?WSGI is a synchronous gateway interface (one thread per request) while ASGI is its async successor that supports concurrent in-flight requests and long-lived connections. FastAPI is built on async foundations, so it needs an ASGI server like Uvicorn to actually run its coroutines.
WSGI is synchronous
It calls a callable and waits for a full response; one request blocks one worker until done. No native support for WebSockets or streaming.
ASGI is asynchronous
Defined around async callables with scope/receive/send, so a worker can await I/O and handle many requests concurrently.
Also supports WebSockets and server-sent events that WSGI can't.
Why FastAPI needs ASGI
FastAPI uses async def handlers built on Starlette; a WSGI server cannot drive coroutines or the event loop.
Uvicorn (often behind Gunicorn) provides that event loop and the ASGI protocol implementation.
Q14.What are the main features that make FastAPI 'fast' compared to other Python frameworks?
FastAPI 'fast' compared to other Python frameworks?"Fast" refers to both runtime performance (async on ASGI, on par with Node and Go for I/O work) and developer speed (type hints eliminate boilerplate). Both come from its foundations.
Runtime performance
Async/ASGI via Starlette and Uvicorn lets one worker handle many concurrent I/O-bound requests.
Pydantic v2 validates with a compiled Rust core, making serialization fast.
Developer speed
Type hints give automatic validation, serialization, and editor autocompletion, so less code and fewer bugs.
Automatic OpenAPI docs remove manual documentation work.
Caveat
Performance gains assume non-blocking code; a blocking call in async def stalls the event loop.
Q15.What are the tradeoffs of using FastAPI vs Flask or Django?
FastAPI vs Flask or Django?FastAPI wins on async performance, validation, and auto-generated docs, but it is API-focused and assumes comfort with async and type hints; Flask and Django trade some of that for maturity, simplicity, or built-in features.
FastAPI advantages
Native async, automatic Pydantic validation, and free OpenAPI docs reduce boilerplate.
FastAPI tradeoffs
No built-in ORM, admin, or templating: you assemble those yourself.
Async correctness matters; blocking code can hurt performance.
Younger ecosystem than Django/Flask, fewer mature plugins.
Flask tradeoffs
Simple and mature, but synchronous and needs add-ons for validation and docs.
Django tradeoffs
Everything included (ORM, admin, auth) but heavier and less suited to pure async high-throughput APIs.
Q16.Explain the concept of "non-blocking" code in the context of an ASGI server like Uvicorn.
ASGI server like Uvicorn.Non-blocking code means an operation yields control back to the event loop while it waits (instead of holding the thread), letting the single-threaded loop make progress on other requests. On Uvicorn, this is what makes one worker serve many concurrent connections.
The event loop
Uvicorn runs one loop per worker; await on async I/O suspends a coroutine and frees the loop to run others.
Non-blocking vs blocking
Non-blocking: async DB drivers, httpx awaits that return the loop during network waits.
Blocking: time.sleep, a sync DB call, or CPU-heavy work holds the loop and stalls every request on that worker.
The rule
Use await with async libraries inside async def; offload unavoidable blocking work to a threadpool (plain def handlers or run_in_executor).
Q17.What are the main trade-offs between FastAPI and Flask for a small-scale project?
FastAPI and Flask for a small-scale project?For a small project, the choice is mostly about whether you value FastAPI's built-in validation and async support over Flask's minimalism and larger ecosystem maturity.
FastAPI strengths
Built-in data validation via Pydantic, automatic OpenAPI/Swagger docs, and native async support out of the box.
Type hints give editor autocompletion and fewer runtime surprises.
Flask strengths
Extremely simple and unopinionated: less to learn for a tiny app.
Huge, mature ecosystem of extensions and abundant tutorials.
Trade-off for small scale
FastAPI's structure pays off as the API grows; for a trivial endpoint it can feel like overhead.
Flask needs add-ons (e.g. for validation/docs) that FastAPI bundles, so you assemble more yourself.
Rule of thumb: choose FastAPI if you want async, validation, and docs for free; choose Flask for maximum simplicity or a sync, plugin-driven workflow.
Q18.In 2026, why might you choose FastAPI over Django for an AI-driven microservice?
FastAPI over Django for an AI-driven microservice?For an AI-driven microservice, FastAPI's async I/O, lightweight footprint, and first-class typed validation fit model-serving workloads better than Django's full batteries-included stack.
Async for I/O-bound AI calls
Inference often means awaiting external model APIs or GPU services; async def lets one worker handle many concurrent requests.
Native support for streaming responses (token-by-token LLM output) and WebSockets.
Lightweight microservice fit
Django bundles ORM, admin, templates, and auth that a single-purpose inference service rarely needs.
FastAPI starts small and is easy to containerize and scale horizontally.
Validation and contracts
Pydantic models validate request/response schemas (prompts, parameters) and auto-generate OpenAPI docs consumed by clients.
When Django still wins
If the service also needs a rich relational data layer, admin UI, and tightly coupled web app, Django's integration saves time.
Q19.What is the response_model parameter in a route decorator, and why is it important for security?
response_model parameter in a route decorator, and why is it important for security?response_model declares the schema FastAPI uses to filter and serialize the response: it shapes the output and, crucially, prevents leaking fields that aren't in the declared model.
What it does
Validates and serializes the returned object against the given Pydantic model, dropping any extra attributes.
Documents the response schema in OpenAPI.
Why it matters for security
You can return a full DB object (with hashed_password, internal flags) but expose only the safe fields, avoiding accidental data leaks.
A dedicated output model enforces a strict response contract independent of the input model.
Helpful options
response_model_exclude_unset and similar flags fine-tune which fields appear.
Q20.Explain the difference between a Pydantic model and a standard Python dataclass in the context of FastAPI.
Pydantic model and a standard Python dataclass in the context of FastAPI.Both describe structured data with typed fields, but a Pydantic model validates and coerces data at runtime, while a standard dataclass is just a typed container with no validation.
Validation
Pydantic enforces types and runs validators, raising errors on bad data; a dataclass stores whatever you give it (type hints are not enforced).
Serialization
Pydantic has built-in model_dump()/JSON conversion; dataclasses need manual handling for complex types.
FastAPI integration
Pydantic models drive request validation, response shaping, and OpenAPI docs out of the box.
FastAPI does support dataclasses, but converts them to Pydantic internally; you lose the richer validation features.
When to use a dataclass
Pure internal data structures where you don't need validation or serialization.
Q21.How does FastAPI use Python type hints to perform both data validation and documentation generation simultaneously?
FastAPI use Python type hints to perform both data validation and documentation generation simultaneously?FastAPI reads the type hints on your handler's parameters once and uses them for both jobs: it builds validators from them at startup and emits the same type information into the OpenAPI schema that powers the docs.
Hints as the single source of truth
A parameter like item_id: int tells FastAPI to coerce/validate to int and to document it as an integer.
Validation side
Hints are compiled into Pydantic validators; invalid input returns an automatic 422 with field-level errors.
Documentation side
The same hints generate the OpenAPI/JSON Schema, rendered as interactive Swagger UI and ReDoc.
Source of parameters
FastAPI infers location (path, query, body) from the hint and signature, so one declaration covers parsing, validation, and docs together.
Q22.How would you implement data validation against an external resource like a database or third-party API using Pydantic's validation system?
Pydantic's validation system?Pydantic validators should stay pure and side-effect-free, so validation against a database or external API is best done in a FastAPI dependency rather than inside the model. Pydantic can enforce shape and basic constraints, but I/O-bound checks belong outside the model so they can be async and use injected resources.
Why not inside a validator
Pydantic validators are synchronous and have no access to your DB session or app dependencies, so awaiting I/O there is awkward or impossible.
Validators are meant to be deterministic and fast: hitting a network resource makes them slow and hard to test.
Preferred approach: a dependency
Validate the payload shape with the Pydantic model, then run the external check in a Depends() that can be async and raise HTTPException.
This keeps DB/API concerns in the request layer where sessions and clients are already injected.
If you must do it in Pydantic
Use a field_validator only for stateless rules, and reserve resource checks for a service/dependency.
Q23.How do you manage application configuration and environment variables using Pydantic's BaseSettings?
Pydantic's BaseSettings?Define a class inheriting from BaseSettings (now in pydantic-settings for v2) with typed fields; Pydantic automatically reads values from environment variables (and optionally a .env file), validates and coerces them, and gives you a single typed config object.
Automatic env loading
Each field maps to an environment variable by name (case-insensitive by default), with type coercion and validation applied.
Provide defaults for optional settings; omit them to make a variable required.
Configuration source
Use model_config = SettingsConfigDict(env_file=".env") to also read a dotenv file, with env vars taking precedence.
Use it as a dependency
Wrap creation in an @lru_cache function so it's built once and injectable via Depends(), which also makes overriding in tests easy.
Benefit
Fail fast: misconfigured or missing env vars raise a clear error at startup, not deep in a request.
Q24.How do you define custom validators in a Pydantic model, and when would you use field versus model validators?
Pydantic model, and when would you use field versus model validators?Use @field_validator to validate or transform a single field, and @model_validator to validate the whole model when a rule depends on multiple fields together. (In Pydantic v1 these were @validator and @root_validator.)
Field validators
Decorate a classmethod with @field_validator("name"); it receives that field's value and returns the cleaned value or raises ValueError.
Use mode="before" to run before type coercion, mode="after" (default) to run after.
Model validators
Decorate with @model_validator(mode="after") to check cross-field invariants (e.g. password == password_confirm).
When to choose which
One field's value/format: field validator.
A rule spanning two or more fields: model validator (it sees the whole object).
Q25.What does 'orm_mode' (from_attributes) do in a Pydantic model, and why is it useful when working with ORMs?
orm_mode' (from_attributes) do in a Pydantic model, and why is it useful when working with ORMs?It tells Pydantic to populate a model by reading attributes off an arbitrary object (like an ORM instance) instead of requiring a dict. In Pydantic v2 it's from_attributes=True (v1 called it orm_mode = True), enabling Model.model_validate(orm_obj).
The problem it solves
ORM rows (e.g. SQLAlchemy objects) expose data as attributes (user.name), not as dict keys; without this Pydantic can't read them.
How to enable it
Set model_config = ConfigDict(from_attributes=True) on the schema.
Why it matters in FastAPI
Lets you return an ORM object directly from a route and have it serialized through a response_model, which also strips out fields not declared in the schema.
Q26.What is the purpose of jsonable_encoder in FastAPI?
jsonable_encoder in FastAPI?jsonable_encoder converts arbitrary Python objects (Pydantic models, ORM objects, datetime, Decimal, UUID, etc.) into JSON-compatible primitives (dicts, lists, strings, numbers) that json.dumps can handle. FastAPI uses it internally when building responses.
What it produces
Not a JSON string, but a structure of native types ready to be serialized: e.g. a datetime becomes an ISO-8601 string.
Common manual use
Before storing data in a JSON-only store, or passing it to something that can't handle complex types directly.
Often paired with updating records: encode a Pydantic model to a plain dict.
Why it exists
It respects model config (aliases, exclusions) and knows how to encode types the stdlib JSON encoder rejects.
Q27.What does response_model_exclude_unset (and related options) do, and why would you use them?
response_model_exclude_unset (and related options) do, and why would you use them?response_model_exclude_unset tells FastAPI to leave out fields the client/model never explicitly set, so the response contains only meaningful data instead of every default. Related flags trim None values and default values.
response_model_exclude_unset=True
Omits fields that were never assigned a value, even if they have a default: useful so clients can distinguish "not provided" from a default.
response_model_exclude_none=True
Drops any field whose value is None, cleaning up nullable optional fields.
response_model_exclude_defaults=True
Omits fields still equal to their declared default value.
Why use them
Smaller, clearer payloads; and critically for PATCH-style APIs, exclude_unset lets you apply only the fields the client actually sent.
Q28.Explain the concept of Dependency Injection in FastAPI and why it is useful.
FastAPI and why it is useful.Dependency Injection (DI) in FastAPI is a way to declare what a route needs (a DB session, the current user, settings) and let the framework build and supply it: you call Depends() and FastAPI resolves it for you.
How it works
A dependency is any callable (function or class); declare it as a parameter default with Depends(get_db).
FastAPI inspects its signature, resolves its own params (including query/path params and sub-dependencies), and injects the result.
Why it is useful
Reuse: share logic (auth, pagination, DB session) across many routes without duplication.
Separation of concerns: handlers stay focused on business logic.
Testability: dependencies can be swapped via overrides.
It still participates in validation and OpenAPI docs (a dependency's params show up in the schema).
Q29.How do Sub-dependencies (nested dependencies) work in FastAPI?
FastAPI?Sub-dependencies are dependencies that themselves depend on other dependencies: FastAPI builds the whole tree, resolving the deepest ones first and passing their results upward.
Chaining
A dependency declares Depends() on another dependency in its own parameters, forming a graph.
FastAPI resolves the graph in order and injects each result where it is needed.
Why it matters
Lets you compose small, focused pieces (e.g. get_current_user depends on get_token).
Shared sub-dependencies are cached per request by default, so they run once even if referenced multiple times.
Q30.How does the yield keyword work within a FastAPI dependency?
yield keyword work within a FastAPI dependency?A dependency that uses yield instead of return provides a value and then runs teardown code after the response is sent: it is FastAPI's way of doing setup/cleanup (like a context manager).
Lifecycle
Code before yield runs at request time (setup); the yielded value is injected.
Code after yield runs after the response (teardown), even if an exception occurred.
Typical use
Open a DB session, yield it, then close it; wrap in try/finally to guarantee cleanup.
Notes
Works with both def and async def generators.
Teardown runs after the response, so raising there won't change an already-sent response.
Q31.What is the benefit of using Annotated when defining dependencies?
Annotated when defining dependencies?Annotated lets you attach Depends() metadata to a type rather than putting it in the parameter default, which makes dependencies reusable, type-safe, and free of the awkward default-value pattern.
Reusable aliases
Define DbSession = Annotated[Session, Depends(get_db)] once and reuse it across many routes.
Cleaner signatures
The real default stays available (you can give the param an actual default value), unlike the old x = Depends(...) style.
Better tooling
Type checkers and editors see the real type; it is the FastAPI-recommended modern style.
Q32.How does FastAPI's dependency injection system simplify the process of writing unit and integration tests?
FastAPI's dependency injection system simplify the process of writing unit and integration tests?DI makes testing easy because dependencies are declared, not hard-coded: FastAPI exposes app.dependency_overrides so you can swap real dependencies for fakes (test DB, mock user) without touching the route code.
Override mechanism
Map the original dependency to a replacement: app.dependency_overrides[get_db] = get_test_db.
All routes using that dependency now receive the test version.
Benefits
Isolate units: replace external services (DB, payment, auth) with stubs.
No monkeypatching of globals; the seam is explicit and clean.
Clear cleanup: reset overrides after each test (app.dependency_overrides.clear()).
Q33.What is the difference between async def and def in a FastAPI route handler, and when should you use each?
async def and def in a FastAPI route handler, and when should you use each?Use async def for non-blocking I/O with async libraries; use def for blocking or CPU-bound work: FastAPI runs each so neither freezes the event loop.
async def runs on the event loop
Ideal when you await async I/O (async DB drivers, httpx); many requests share one worker.
def (sync) is run by FastAPI in a threadpool
A blocking call there doesn't freeze the loop.
The trap: a blocking call (time.sleep, a sync DB driver) inside async def blocks every request on that worker.
Rule of thumb: async library available, use async def; only sync/blocking code, use plain def.
Q34.What happens if you use a blocking I/O call (like a synchronous database driver) inside an async def route?
async def route?The blocking call stalls the entire event loop: while that one request waits on the synchronous driver, no other request on that worker can make progress, so throughput collapses under concurrency.
Why it hurts
An async def handler runs directly on the single event loop thread; a blocking call never yields control back to the loop.
All other in-flight coroutines on that worker are frozen until the call returns, even unrelated requests.
Symptoms
Latency spikes and timeouts that worsen as concurrency rises, often misdiagnosed as a slow database.
Fixes
Use an async driver and await it, or
Move the blocking call off the loop with run_in_threadpool / asyncio.to_thread, or just use a plain def handler so FastAPI threadpools it for you.
Q35.How does FastAPI handle concurrency for synchronous def functions compared to asynchronous async def ones?
FastAPI handle concurrency for synchronous def functions compared to asynchronous async def ones?FastAPI runs async def handlers directly on the event loop (cooperative concurrency via await), while def handlers are dispatched to a bounded threadpool so their blocking work doesn't stall the loop.
async def: event-loop concurrency
One thread interleaves many requests; concurrency only happens at await points where I/O yields.
Scales to thousands of concurrent I/O-bound requests cheaply.
def: threadpool concurrency
Starlette runs sync handlers in an AnyIO threadpool (default 40 worker threads).
Concurrency is capped by that pool size; exhaust it and further requests queue.
Practical implication
Async favors high-fan-out I/O; sync threadpool is fine for moderate blocking work but won't match async scale and is limited by the GIL for CPU work.
Q36.What are "Lifespan" events, and why were they introduced to replace the old @app.on_event("startup")?
@app.on_event("startup")?Lifespan events let you run setup code before the app starts serving and teardown code after it stops, defined in a single async context manager passed to the app. They replaced the separate @app.on_event("startup") / "shutdown" hooks, which are now deprecated.
What they do
Code before yield runs once at startup (open DB pools, load ML models); code after yield runs at shutdown (close connections).
Why they're better than on_event
Single function keeps startup and matching shutdown together, so shared state (a pool created at start) is in scope to clean up.
You can yield state into the app rather than relying on globals.
It aligns with the underlying Starlette/ASGI lifespan protocol; on_event was a thinner legacy wrapper.
Q37.How would you handle global exceptions in FastAPI to ensure a consistent API error response?
Register exception handlers with @app.exception_handler(...) (or add_exception_handler) so every matching error is converted into a uniform JSON response in one place, instead of repeating try/except in each route.
Custom exception classes
Define domain errors (e.g. class NotFoundError(Exception)) and a handler that maps them to a consistent error shape.
Override built-in handlers
Register handlers for HTTPException and RequestValidationError to reshape FastAPI's default bodies into your standard envelope.
Catch-all safety net
A handler for Exception returns a generic 500 (logging the detail) so internals never leak to clients.
Consistency
Return a fixed schema (code, message, details) for all errors so clients parse one format.
Q38.Explain the concept of Middleware in FastAPI. When would you use a Middleware versus a Dependency for cross-cutting concerns like logging or authentication?
Middleware wraps the entire request/response cycle: it runs before the route is matched and after the response is produced, for every request. A dependency runs inside route handling and can be scoped to specific endpoints. Use middleware for truly global, request-wide concerns; use dependencies when you need per-route control, parameters, or values injected into the handler.
Middleware
Runs around the whole pipeline; sees the raw Request and final Response.
Best for cross-cutting global behavior: request logging/timing, CORS, GZip, adding headers.
Can't easily target specific routes or feed values into a handler's signature.
Dependency
Declared via Depends(); runs per route (or per router/app) and can raise HTTPException.
Best for auth/authorization that varies by endpoint, and for injecting parsed values (current user, DB session).
Integrates with OpenAPI docs and validation.
Choosing for logging vs auth
Logging/timing every request: middleware.
Authentication that returns the user object to handlers and differs per route: dependency.
Q39.What is the purpose of Middleware in FastAPI, and can you give an example of when to use it?
Middleware is code that runs on every request before it reaches your route and on every response before it's sent back, letting you apply behavior globally without touching each handler.
How it works
You receive the request and a call_next function; you await call_next(request) to get the response, then can modify it.
Common uses
Logging and request timing, adding headers, CORS, GZip compression, correlation IDs.
Example need
Add an X-Process-Time header measuring how long each request took, applied uniformly across the app.
Q40.How does FastAPI's HTTPException differ from a standard Python exception, and how does the framework's global exception handler work?
HTTPException differ from a standard Python exception, and how does the framework's global exception handler work?HTTPException is a FastAPI/Starlette exception you raise to short-circuit a request into a proper HTTP error response (status code + JSON body), whereas a plain Python exception signals a program error and, if unhandled, becomes a generic 500. FastAPI ships a built-in handler that catches HTTPException and serializes it for you.
HTTPException
Carries status_code, detail, and optional headers; raising it stops the handler immediately.
Intended as a normal control-flow tool for expected error conditions (404, 403, etc.).
Standard Python exception
Represents an unexpected failure; uncaught, it triggers the catch-all 500 handler and logs a traceback.
How the global handler works
FastAPI registers default handlers that convert HTTPException into {"detail": ...} with the given status, and RequestValidationError into a 422.
You can override these with @app.exception_handler(HTTPException) to customize the body globally.
Q41.Explain the flow of OAuth2 with Password flow and Bearer tokens as implemented in FastAPI, and how does the Security dependency work?
OAuth2 with Password flow and Bearer tokens as implemented in FastAPI, and how does the Security dependency work?In the OAuth2 password flow, the client posts username/password to a token endpoint, gets back a bearer token, then sends that token in the Authorization: Bearer <token> header on every subsequent request. FastAPI implements this with OAuth2PasswordBearer, and Security() is a specialized Depends() that also carries scope metadata.
Token issuance (the login step)
Client posts form data to a token URL using OAuth2PasswordRequestForm (fields: username, password).
Server verifies credentials and returns {"access_token": ..., "token_type": "bearer"}, typically a signed JWT.
Token use on protected routes
OAuth2PasswordBearer(tokenUrl="token") is a dependency that extracts the token from the Authorization header.
If the header is missing it raises 401; otherwise it hands you the raw token to decode/validate.
How Security works
Security(dependency, scopes=[...]) behaves like Depends but registers required scopes and feeds OpenAPI so Swagger UI renders the auth flow.
FastAPI aggregates scopes across the dependency tree and exposes them via a SecurityScopes object you can check.
Q42.How does FastAPI handle CORS (Cross-Origin Resource Sharing), and why is it necessary?
FastAPI handle CORS (Cross-Origin Resource Sharing), and why is it necessary?CORS is a browser security mechanism that blocks JavaScript on one origin from reading responses from a different origin unless the server explicitly opts in via response headers. FastAPI handles it with CORSMiddleware, which adds those headers and answers preflight requests.
Why it's necessary
The browser's same-origin policy stops a page at site-a.com from reading an API at api-b.com unless the API allows it.
It's enforced by the browser, not the server: tools like curl ignore CORS entirely.
Preflight requests
For non-simple requests (custom headers, PUT/DELETE) the browser first sends an OPTIONS request to check what's allowed.
CORSMiddleware responds with Access-Control-Allow-* headers automatically.
Key options
allow_origins, allow_methods, allow_headers, and allow_credentials.
You can't combine allow_credentials=True with allow_origins=["*"]; list explicit origins instead.
Q43.How do you handle file uploads in FastAPI, and what is the difference between File and UploadFile?
FastAPI, and what is the difference between File and UploadFile?File uploads use multipart form data declared with File() or UploadFile: File() reads the whole file into memory as bytes, while UploadFile streams via a spooled file object that handles large files efficiently.
bytes with File()
Entire file is loaded into RAM: fine for small files, dangerous for large ones.
UploadFile
Spooled file: stays in memory up to a threshold, then rolls to disk, so memory stays bounded.
Exposes metadata (.filename, .content_type) and async methods (await file.read(), .write(), .seek(), .close()).
Requires python-multipart
Must be installed for form/file parsing to work.
Rule of thumb
Prefer UploadFile by default; use bytes only for known-small payloads.
Q44.What are the different Response types in FastAPI (JSONResponse, StreamingResponse, FileResponse), and when would you use each?
FastAPI (JSONResponse, StreamingResponse, FileResponse), and when would you use each?FastAPI returns JSONResponse by default, but you can return specialized Response classes when you need streaming, files, or other content types.
JSONResponse
The default: serializes returned dicts/models to JSON. Use ORJSONResponse for faster serialization.
StreamingResponse
Sends data incrementally from a generator or file-like object: ideal for large files, generated CSVs, or server-sent events without loading everything into memory.
FileResponse
Efficiently serves a file from disk, setting Content-Type, Content-Length, and supporting range requests automatically.
Others
PlainTextResponse, HTMLResponse, and RedirectResponse cover text, HTML, and redirects.
Declare response_class on the decorator so docs reflect the actual content type.
Q45.Explain how you would implement a custom Dependency Provider that changes behavior based on the environment such as testing versus production.
Define a dependency function whose return value (or the object it builds) is chosen by configuration, then swap that choice per environment via settings or app.dependency_overrides during tests.
Drive behavior from settings, not hardcoded branches
Read an env value (e.g. ENV) via a pydantic BaseSettings object and decide which implementation to provide.
Keep the dependency's return type/interface identical across environments so handlers don't change.
Two override mechanisms
Runtime: the provider itself inspects settings and returns the right object (real DB vs in-memory).
Test-time: register app.dependency_overrides[get_db] = fake_db so tests inject fakes without touching production code.
Why this is clean
FastAPI resolves dependencies per request, so swapping is centralized and decoupled.
Use lru_cache on the settings getter so it's read once.
Q46.What are the possible places where a FastAPI API can get slow?
FastAPI API can get slow?Slowness usually comes from blocking the event loop, slow I/O, or heavy serialization, not from FastAPI itself: profile to find which layer dominates before optimizing.
Event-loop blocking
A synchronous/CPU-bound call inside async def (e.g. time.sleep, a sync DB driver) stalls every concurrent request.
Database layer
Missing indexes, N+1 queries, small connection pools, or unawaited blocking drivers.
External I/O
Slow upstream APIs without timeouts or connection pooling; create one shared httpx.AsyncClient.
Serialization/validation
Large pydantic response models or huge payloads spend real CPU on validation/JSON encoding.
Middleware and dependencies
Heavy per-request dependencies or chatty middleware add latency to every call.
Deployment/concurrency
Too few Uvicorn workers for CPU-bound load, or an undersized threadpool for sync routes.
Q47.How does FastAPI integrate with databases like SQLAlchemy, and what considerations apply to managing async database sessions?
FastAPI integrate with databases like SQLAlchemy, and what considerations apply to managing async database sessions?FastAPI has no built-in ORM; you wire in SQLAlchemy yourself, providing a session per request via a dependency and ensuring the session's sync/async nature matches your route handlers.
Session per request via a dependency
A dependency yields a session and closes it after the response, giving clean per-request lifecycle.
Use yield so cleanup runs even on errors.
Sync vs async paths
Sync SQLAlchemy Session in a plain def route (runs in the threadpool, won't block the loop).
Or AsyncSession with an async engine (asyncpg) in async def routes; never mix a blocking driver into async def.
Key considerations
Sessions are not thread-safe or shareable across requests: one per request.
Tune the connection pool to your worker count.
With AsyncSession, remember to await commits/queries and beware lazy-loading after commit.
Q48.How does FastAPI support WebSockets, and how do they differ from regular HTTP endpoints?
FastAPI support WebSockets, and how do they differ from regular HTTP endpoints?FastAPI supports WebSockets through Starlette: you decorate a handler with @app.websocket(...), accept the connection, then send/receive messages over a single long-lived, bidirectional connection rather than the one-shot request/response of HTTP.
Basic flow
await websocket.accept() to complete the handshake, then loop on receive_text()/send_text() until disconnect.
Catch WebSocketDisconnect to clean up.
How they differ from HTTP endpoints
Persistent and full-duplex: server can push without the client asking, unlike request/response HTTP.
No automatic pydantic body validation or OpenAPI docs like normal routes; you parse messages yourself.
State lives for the connection's lifetime, so you manage connection registries for broadcast.
Use cases
Chat, live notifications, dashboards, streaming updates.
Q49.What happens internally from the moment a request hits a FastAPI endpoint until the response is sent?
FastAPI endpoint until the response is sent?A request flows through the ASGI server, Starlette's routing and middleware, dependency resolution and validation, your handler, then back out as a serialized response.
1. Server receives it
Uvicorn parses the HTTP request into an ASGI scope and passes it to the app.
2. Middleware and routing
Starlette runs the middleware stack, then matches the path/method to a route handler.
3. Dependencies and validation
FastAPI resolves Depends(), then parses and validates path/query/body params via Pydantic; invalid input returns a 422 before your code runs.
4. Handler execution
async def runs on the event loop; plain def runs in a threadpool.
5. Response serialization
The return value is encoded (via the response_model if set) to JSON and sent back through middleware to the client.
Q50.Can you explain the async lifecycle in FastAPI and how it handles async def vs regular def functions?
FastAPI and how it handles async def vs regular def functions?FastAPI runs on an ASGI event loop: async def handlers execute directly on the loop and yield during await, while plain def handlers are dispatched to a threadpool so blocking work doesn't freeze the loop.
async def path
Coroutine runs on the event loop; at each await it suspends, letting the worker serve other requests.
Best when using async libraries (async DB drivers, httpx).
def (sync) path
FastAPI offloads it to an external threadpool (via AnyIO), so blocking calls run off the loop.
Lifecycle hooks
Startup/shutdown logic uses the lifespan context manager to set up and tear down resources (DB pools, model loading).
The classic trap
A blocking call (time.sleep, a sync driver) inside async def blocks the whole loop and stalls every request on that worker.
Q51.What are the major conceptual differences between Pydantic v1 and v2 that affect FastAPI performance and validation logic?
Pydantic v1 and v2 that affect FastAPI performance and validation logic?Pydantic v2 rewrote its core validation engine in Rust (pydantic-core), making it dramatically faster, and changed several APIs and semantics that affect how FastAPI validates and serializes.
Performance
v2's Rust core validates and serializes many times faster than v1's pure-Python implementation.
API changes
.dict() and .json() became .model_dump() and .model_dump_json().
validator became field_validator, and Config class became model_config.
Validation semantics
Stricter, more consistent type coercion and a clearer strict vs lax mode.
Separation of validation logic from serialization logic with explicit serializers.
FastAPI impact
Recent FastAPI versions support v2 natively; migrating yields faster request/response handling but may require updating model code.
Q52.How does FastAPI handle validation errors internally before they even reach your path operation function?
FastAPI handle validation errors internally before they even reach your path operation function?FastAPI validates and parses the incoming request against your declared types/models before your handler runs; if validation fails it never calls your function and instead returns an automatic 422 Unprocessable Entity response.
Request parsing pipeline
FastAPI inspects your path operation's type hints and Pydantic models to build a schema, then extracts path, query, header, and body values.
It feeds these into Pydantic, which coerces and validates them.
On failure
Pydantic raises a ValidationError, which FastAPI catches and converts into a RequestValidationError.
The built-in exception handler serializes it to a structured JSON body with loc, msg, and type for each error, and returns 422.
Your handler stays clean
By the time your function runs, parameters are already valid, typed Python objects: no manual checking needed.
Customizable
Override with @app.exception_handler(RequestValidationError) to reshape the error response.
Q53.Explain how Pydantic validation actually works under the hood.
Pydantic validation actually works under the hood.Q54.What are "dependency overrides" and when would you use them in a production environment?
Q55.What is the Depends system in FastAPI, and how does it differ from traditional class-based dependency injection found in Java or C#?
Depends system in FastAPI, and how does it differ from traditional class-based dependency injection found in Java or C#?Q56.How does FastAPI's dependency injection system handle sub-dependencies and dependency caching?
FastAPI's dependency injection system handle sub-dependencies and dependency caching?Q57.How do you structure service wiring outside of FastAPI's Depends?
Depends?Q58.When should you use async def versus a regular def for a path operation in FastAPI, and what happens if you use a blocking I/O call inside an async def function?
async def versus a regular def for a path operation in FastAPI, and what happens if you use a blocking I/O call inside an async def function?Q59.How would you handle a CPU-bound task in a FastAPI application to ensure the event loop remains responsive?
FastAPI application to ensure the event loop remains responsive?Q60.In a high-concurrency environment, what are the potential pitfalls of using a database driver that does not support async/await?
async/await?Q61.When comparing FastAPI to Go or Node.js for microservices, where does Python's Global Interpreter Lock (GIL) still pose a bottleneck?
FastAPI to Go or Node.js for microservices, where does Python's Global Interpreter Lock (GIL) still pose a bottleneck?Q62.What is the impact of the Python Global Interpreter Lock (GIL) on a FastAPI application, and how do multiple workers help mitigate this?
GIL) on a FastAPI application, and how do multiple workers help mitigate this?Q63.How does Middleware work in FastAPI, and what are the trade-offs of using it for every request?
Q64.Explain how to maintain state across different requests in FastAPI without using a traditional session object.
Q65.How do you handle idempotency in FastAPI endpoints, especially for POST requests in a distributed system?
FastAPI endpoints, especially for POST requests in a distributed system?Q66.How can you implement and use Security Scopes in FastAPI's OAuth2 system for fine-grained authorization?
Security Scopes in FastAPI's OAuth2 system for fine-grained authorization?Q67.What are the trade-offs of using the Request object directly in a path operation versus using Pydantic models?
Request object directly in a path operation versus using Pydantic models?Q68.What is the difference between BackgroundTasks provided by FastAPI and a dedicated task queue like Celery or Arq, and when would you choose one over the other?
BackgroundTasks provided by FastAPI and a dedicated task queue like Celery or Arq, and when would you choose one over the other?Q69.What are the strategies for implementing rate limiting in FastAPI, and what are the trade-offs of doing it at the application level versus the proxy level?
FastAPI, and what are the trade-offs of doing it at the application level versus the proxy level?Q70.Explain the performance trade-offs of using FastAPI compared to a traditional framework like Flask or Django in a high-concurrency environment.
FastAPI compared to a traditional framework like Flask or Django in a high-concurrency environment.