Top 30 Intermediate Python & FastAPI Interview Questions and Answers
30 intermediate multiple-choice Python & FastAPI interview questions, past the definitions: how the pieces fit together, what breaks in practice, and the trade-off behind a choice. They come from 30 bites in the Python & FastAPI library, the middle slice of the 133 Python & FastAPI interview questions in the library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
Python, Django, FastAPI, Flask, async Python
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
What mechanism triggers FastAPI to automatically validate and parse an incoming JSON request body against a schema?
Show the answer
Answer: b · Using a Pydantic model as the type hint for a route parameter
FastAPI inspects function signature type hints at runtime, so using a Pydantic model as a parameter type hint automatically triggers request parsing and validation. Manually calling json.loads inside the route is a red flag that ignores this declarative mechanism, and response_model governs response serialization, not request validation.
Read the full bite: How does FastAPI leverage Pydantic for request validation and serialization?
Question 2 of 30
When building an async execution-time decorator for FastAPI, why is omitting functools.wraps on the inner wrapper considered a red flag?
Show the answer
Answer: b · It strips the original function's metadata, which breaks FastAPI's OpenAPI schema generation and dependency injection.
functools.wraps preserves the original function's name, signature, and metadata, which FastAPI relies on to generate OpenAPI docs and resolve dependencies; omitting it exposes the wrapper's metadata instead. Distractor A is wrong because wraps has no effect on whether code runs synchronously or blocks the event loop.
Read the full bite: Write an async decorator that logs execution time for FastAPI
Question 3 of 30
Which implementation correctly minimizes total latency when a FastAPI endpoint must fetch data from two independent external APIs?
Show the answer
Answer: a · Inside an async def endpoint, pass two httpx.AsyncClient coroutines to asyncio.gather and await the result.
asyncio.gather with an async HTTP client schedules both I/O-bound coroutines concurrently on the event loop, reducing total latency to roughly the slower call. Option C is tempting because it uses async/await correctly, but sequential awaiting means the second request cannot start until the first finishes, so latencies add up.
Read the full bite: How do you structure concurrent API calls with asyncio.gather in FastAPI?
Question 4 of 30
A FastAPI endpoint declares a path parameter as item_id: int. A request arrives for /items/abc, which cannot be coerced to an integer. What happens?
Show the answer
Answer: a · FastAPI returns an automatic 422 error describing the invalid value, and the endpoint function body never executes
FastAPI validates the coerced type before your function runs, so an uncoercible value short circuits into an automatic 422 with no handler code executing. Python itself does nothing with the int annotation at runtime, which is why expecting a TypeError or manual parsing misses the point of the hint.
Read the full bite: How FastAPI uses type hints for validation
Question 5 of 30
Which FastAPI endpoint declaration identifies a user in the URL path and accepts an optional search term after the question mark?
Show the answer
Answer: a · Route /users/{user_id}/items with user_id in path and q optional
Option A correctly places the user identifier in the path template and gives q a default of None so it becomes an optional query parameter. Option B is tempting because it also makes q optional, but it omits user_id from the path so FastAPI treats it as a query parameter, violating RESTful hierarchy.
Read the full bite: What is the difference between a path parameter and a query parameter?
Question 6 of 30
An endpoint declares a query parameter as q: Optional[str] with no default value. What happens when a client omits it?
Show the answer
Answer: c · FastAPI returns a 422 Unprocessable Entity error
FastAPI derives requirement from the presence or absence of a Python signature default, not from type hints, so Optional[str] without = None is still required and omitting it triggers a 422 error. Option D is a common misconception because Optional alone does not make a parameter optional in FastAPI.
Read the full bite: How does FastAPI distinguish required optional and default query parameters
Question 7 of 30
What combination of standard and code sources enables FastAPI's automatic interactive documentation?
Show the answer
Answer: d · It dynamically builds an OpenAPI schema from type hints, Pydantic models, decorators, and docstrings
FastAPI dynamically generates an OpenAPI schema by extracting metadata from type hints, Pydantic models, decorators, and docstrings, so no manual schema file is required. Option B is wrong because maintaining a separate openapi.yaml by hand is unnecessary and contradicts FastAPI's design.
Read the full bite: What standard and code elements power FastAPI's auto-generated API docs?
Question 8 of 30
In Pydantic V2, how should you enforce a positive price and a regex-formatted SKU without writing custom validators?
Show the answer
Answer: b · Set price: float = Field(gt=0) and sku: str = Field(pattern=r'^ITEM-\d{5}$') on standard types
Field's built-in gt and pattern parameters enforce constraints natively without extra code, while @field_validator adds unnecessary boilerplate and ignores Pydantic V2's native capabilities.
Question 9 of 30
You are writing a Pydantic v2 model with a name field that must be at least 3 characters. Which implementation is correct?
Show the answer
Answer: c · Use @field_validator('name') on a classmethod that raises ValueError and returns the value.
Pydantic v2 requires single-field validators to use @field_validator on a classmethod, raise ValueError on failure, and return the value so processing continues. Option B is tempting but wrong because omitting the return breaks the model lifecycle, and D uses the deprecated v1 pattern.
Read the full bite: Implement a custom validator for a single Pydantic model field
Question 10 of 30
A FastAPI endpoint returns a UserDB model containing password_hash. Which strategy best prevents exposing the hash while keeping the API contract explicit and maintainable?
Show the answer
Answer: c · Create a separate UserOut model without password_hash and set response_model=UserOut on the endpoint.
A dedicated output model declaratively isolates the API contract from the database schema and prevents accidental leaks if new sensitive fields are added later. Option B is a tempting quick fix, but it keeps the sensitive field in the source model and hides the contract outside the type system, making it harder to maintain.
Read the full bite: How do you prevent password_hash from appearing in a FastAPI response?
Question 11 of 30
An Order model needs to hold a list of Product models. What is the idiomatic Pydantic way to ensure nested dictionaries are validated and coerced automatically?
Show the answer
Answer: b · Annotate the field as list[Product] where Product subclasses BaseModel, relying on Pydantic's recursive schema resolution.
Annotating the field as list[Product] leverages Pydantic's core schema generation to recursively validate nested items and report precise error paths automatically. Overriding __init__ to manually build Product instances is a red flag because it ignores Pydantic's built-in recursive validation machinery.
Read the full bite: Model an Order with a nested Product list in Pydantic
Question 12 of 30
A FastAPI endpoint with parameters file: UploadFile and user_id: str fails when receiving multipart form-data. What is the most likely reason?
Show the answer
Answer: a · FastAPI assumes both parameters come from the JSON body because they lack File() and Form() metadata.
Without File() or Form() metadata, FastAPI assumes parameters arrive in the JSON body, which breaks multipart form-data parsing. Distractor A reverses the memory behavior: UploadFile spools large files, while bytes loads everything into memory.
Read the full bite: Implement a FastAPI file upload endpoint with form data
Question 13 of 30
In FastAPI, which approach best implements a reusable current-user check that preserves OpenAPI docs integration and keeps endpoints testable?
Show the answer
Answer: a · Define a get_current_user dependency that uses OAuth2PasswordBearer, validates the token, returns a User model, and inject it into routes with Depends.
A dedicated get_current_user dependency keeps auth explicit in the signature, auto-documents security in OpenAPI, and enables test overrides via app.dependency_overrides. Middleware hides the dependency from the docs and complicates testing.
Read the full bite: How do you create a reusable current-user dependency in FastAPI?
Question 14 of 30
In FastAPI, what is the key benefit of declaring a Response parameter to set headers and cookies rather than returning a Response subclass directly?
Show the answer
Answer: d · FastAPI can merge the mutated headers and cookies into the final response without bypassing automatic serialization and response_model validation.
Injecting Response lets FastAPI merge your metadata into the automatically serialized final response while preserving response_model filtering and OpenAPI docs. The injected Response object handles outgoing data only; reading incoming request headers requires the Request dependency or Header parameters, not Response.
Read the full bite: How do you set a custom header and cookie in FastAPI?
Question 15 of 30
When you assign a mock to app.dependency_overrides[get_db] in FastAPI, what happens during the test and what must you do afterward?
Show the answer
Answer: b · FastAPI injects the mock exclusively, bypassing the original and its sub-dependencies, and you must manually clear overrides after the test.
FastAPI uses the replacement function exclusively and never executes the original dependency or its sub-dependencies. Option C is tempting but incorrect because sub-dependencies are fully bypassed, not preserved, and overrides persist until you manually clear them.
Read the full bite: How would you override a FastAPI dependency during testing?
Question 16 of 30
You need a FastAPI dependency that accepts roles in its constructor and validates the current user each request. Why use a callable class rather than a plain function?
Show the answer
Answer: b · The class __init__ receives configuration and sub-dependencies declaratively while __call__ handles per-request logic and OpenAPI integration
A callable class lets FastAPI resolve constructor sub-dependencies and configuration via __init__ while __call__ handles per-request execution and remains visible to OpenAPI. The tempting distractor wrongly claims you must manually instantiate the class inside the endpoint, which defeats automatic injection and is explicitly flagged as a red flag.
Read the full bite: How do you use a Python class as a FastAPI dependency?
Question 17 of 30
A FastAPI endpoint depends on get_session, which yields and depends on get_pool, which also yields. What teardown order is guaranteed after the endpoint runs?
Show the answer
Answer: d · get_session tears down first, then get_pool, managed by FastAPI's internal stack
FastAPI uses an internal stack to ensure nested yield dependencies teardown bottom-up, so get_session closes before get_pool releases connections. Distractor A incorrectly assumes teardown mirrors setup order, which would risk resource leaks.
Read the full bite: How does FastAPI execute setup and teardown in nested yield dependencies?
Question 18 of 30
In FastAPI, a database-querying dependency is injected into both a path operation and a sub-dependency. By default, what happens during a single request?
Show the answer
Answer: c · The dependency runs once and the cached value is reused only within that request's dependency tree
FastAPI defaults to use_cache=True, so it executes the dependency once per request and reuses that cached value throughout the same request's dependency tree. Option A is a common misconception: FastAPI does not independently resolve every Depends() declaration; it avoids redundant work by caching within the request lifecycle.
Read the full bite: How does FastAPI cache dependencies within a single request?
Question 19 of 30
You need to enforce authentication on every /users endpoint while leaving /items public. What is the most maintainable FastAPI approach?
Show the answer
Answer: c · Pass dependencies=[Depends(get_current_user)] to the users APIRouter and omit it from the items router, then include both in the app.
Passing dependencies to APIRouter scopes authentication to that router only while keeping other routers unaffected and preserving OpenAPI docs. Adding Depends to every route manually violates DRY and makes refactoring painful, even though it produces the same runtime behavior.
Read the full bite: How to apply a dependency to only one FastAPI router?
Question 20 of 30
Which approach best balances performance, testability, and type safety when making configuration available to FastAPI path operations?
Show the answer
Answer: b · Cache the Settings instance with lru_cache and inject it via FastAPI dependency injection
Caching with lru_cache parses config once at startup instead of on every request, and dependency injection lets tests easily override settings. Option D is tempting but wrong because a direct global import is brittle and harder to mock than an injected dependency.
Read the full bite: Manage dev, staging, and prod configs in a large FastAPI app
Question 21 of 30
Which approach best keeps FastAPI router modules decoupled and reusable when applying a shared path prefix like /api/v1?
Show the answer
Answer: a · Use relative paths in the router and apply the shared prefix via app.include_router when mounting
Defining relative paths in APIRouter and setting the prefix in include_router keeps route definitions separate from URL composition, enabling reuse. Hardcoding full paths scatters configuration, while middleware and router-level prefix arguments add unnecessary complexity.
Read the full bite: How do you apply a common path prefix across FastAPI routers?
Question 22 of 30
You need to call a legacy synchronous database driver inside an async FastAPI endpoint. Which approach prevents the event loop from freezing?
Show the answer
Answer: d · Use asyncio.to_thread to run the call in a ThreadPoolExecutor worker
asyncio.to_thread submits the blocking call to a ThreadPoolExecutor, letting the event loop run other coroutines while the sync IO completes in a worker thread. asyncio.create_task is tempting because it enables concurrent coroutine execution, but it does not offload synchronous work to another thread, so the blocking call would still freeze the event loop.
Read the full bite: How do you safely execute blocking code from an async function
Question 23 of 30
In a single-threaded asyncio program, how does the event loop switch execution from one Task to another?
Show the answer
Answer: a · The running Task must reach an await expression to yield control back to the loop
Asyncio uses cooperative multitasking, so a Task only yields control at an await boundary. Option B is tempting because the loop does poll the OS selector, but it cannot forcibly interrupt a running Task—control must be yielded voluntarily.
Read the full bite: Explain the asyncio event loop and cooperative multitasking
Question 24 of 30
You call asyncio.wait on three tasks, and one of them raises an exception. What actually happens?
Show the answer
Answer: c · wait does not raise the exception itself, it returns the task in the done set, and you must check each task's result or exception yourself
asyncio.wait never raises on a failed task, it just places that task in the done set, and you have to call its result or exception method yourself, which is why a failure can go unnoticed. That silent behavior is the opposite of gather's default, which propagates the first exception immediately.
Question 25 of 30
What is the primary risk of using threading.Lock inside an asyncio coroutine to guard shared state?
Show the answer
Answer: c · It blocks the underlying OS thread, freezing the event loop and all other tasks.
threading.Lock blocks the native OS thread via OS primitives, which prevents the event loop from scheduling any other coroutine. Option B is tempting because locks do protect shared state in threaded code, but inside a coroutine a threading.Lock halts the entire loop instead of yielding control.
Read the full bite: When should you use asyncio.Lock over threading.Lock?
Question 26 of 30
Why should get_db use yield instead of return when providing a database session to FastAPI endpoints?
Show the answer
Answer: d · Yield ensures cleanup logic in the finally block runs after the endpoint completes.
Using yield with a finally block guarantees the session closes after the endpoint runs, even if an exception occurs. Reusing a cached session across requests, as in option C, breaks thread safety and causes concurrency issues.
Read the full bite: How do you use FastAPI dependency injection for database sessions?
Question 27 of 30
Why does a synchronous database call inside an async FastAPI endpoint prevent other requests from progressing even when the underlying driver releases the GIL?
Show the answer
Answer: a · Because the single-threaded event loop never receives an await point during blocking socket calls, so it cannot interleave other requests
The event loop requires await points to switch tasks, which synchronous database calls never yield, so the thread blocks even if the GIL is released. Distractor D is tempting because it sounds like the GIL is the culprit, but the card explicitly notes that synchronous I/O blocks the loop despite releasing the GIL.
Question 28 of 30
When implementing a PATCH endpoint for partial SQLAlchemy updates, which approach prevents omitted JSON fields from overwriting existing database values?
Show the answer
Answer: a · Load the existing record, dump the update schema with exclude_unset=True, and apply fields with setattr
Using exclude_unset=True strips keys the client omitted, so setattr only modifies the fields actually provided. Option B is tempting because it uses the same dump pattern, but without exclude_unset=True missing fields become None and clobber existing data.
Read the full bite: Implement a PATCH endpoint for partial SQLAlchemy updates
Question 29 of 30
Why does a Motor or Beanie integration not need a per-request session object the way SQLAlchemy's AsyncSession does?
Show the answer
Answer: d · Motor's client maintains an internal connection pool and operations are awaited directly, with no unit-of-work or identity map to scope per request
Motor's client pools connections globally and Beanie awaits queries directly, so there is no SQLAlchemy-style session lifecycle to manage. MongoDB is not single-threaded, so that option is a misconception.
Read the full bite: MongoDB async ODM vs SQLAlchemy sessions
Question 30 of 30
Which step must occur inside the POST /token endpoint before returning an access token?
Show the answer
Answer: a · The submitted password is verified against a stored hash using a library like pwdlib
The token endpoint must verify the submitted password against a stored hash before issuing a JWT. Creating a server-side session is wrong because this flow is stateless, and get_current_user is used on subsequent protected routes, not during token creation.
Read the full bite: Implement OAuth2 Password Flow in FastAPI
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.