Interview preparation guide
FastAPI Interview Questions: A Tested API Exercise and Explained Answers
Prepare for FastAPI interview questions by explaining what an endpoint does and proving it with requests. This original exercise combines a typed request body, a replaceable dependency, response filtering and failure cases. It is a fictional in-memory calculation for practice, not a production service or a claim about an employer’s interview.
Start with the problem before reading the solution
Build POST /queues/{queue_id}/estimate. The JSON body contains units, a strict integer from 1 through 50, and priority, either normal or urgent with normal as the default. A dependency supplies fictional minutes-per-unit rates: queue 1 uses 4, and queue 2 uses 7. Return the queue ID, calculated minutes and priority. An unknown queue returns 404.
The priority is only echoed in this exercise; it does not change the arithmetic or scheduling. The endpoint stores nothing and includes no authentication, authorization or external service. State these limits if discussing it in an interview. Try implementing the contract yourself, then compare it with the solution and assertions below.
1. How does FastAPI know which data comes from the path and the body?
In this endpoint, queue_id matches the route placeholder and is declared as an integer. WorkRequest is a Pydantic model, so work is parsed from the request body. The model defines both fields and constraints. FastAPI’s request-body documentation explains this distinction.
A concise answer is: “I describe the API boundary in the function signature and model. Here the route identifies the queue, while the JSON body describes the requested work. I would demonstrate the distinction by sending a non-integer path value and an invalid body separately.”
Follow-up: A plain int model field may allow coercion. This exercise uses Field(strict=True) so the JSON string “3” is rejected even though the number 3 is valid. Do not claim that all type annotations automatically enforce strict input types.
2. What does a dependency buy us in this example?
get_rates supplies a mapping without embedding it in the endpoint. Depends declares that relationship. In the test, app.dependency_overrides substitutes a different rate source while exercising the same HTTP route.
A useful answer is: “The dependency makes the rate source replaceable. My test changes one rate and verifies the resulting calculation. It does not establish that a real database is correct, and dependency injection alone would not enforce permissions.” The finally block clears the override so it cannot leak into later checks.
3. Why use a response model and an HTTP exception?
Estimate defines the public output fields. The returned dictionary also contains an internal_note, but the response model filters that field from the serialized response. The first assertion checks the entire response object, so an unexpected extra field would fail the exercise.
HTTPException with status_code=404 represents the validly formed request for a queue absent from the mapping. Invalid request values produce validation responses instead. Explain that missing domain data and invalid input are different cases. Response filtering does not replace authorization; an endpoint still needs explicit access checks when it exposes protected resources.
4. Should this endpoint use def or async def?
This small calculation uses def. FastAPI runs ordinary def path operations in a thread pool. With an asynchronous client for I/O, an async def endpoint can await that client. Simply changing a function declaration does not make blocking work asynchronous.
A practice answer is: “I would choose based on the operations inside the handler. For an async database client, I would await its calls. I would not put a blocking network call directly into an async handler and assume the event loop can keep serving other work during that call.” CPU-heavy computation needs its own execution plan; async is not a general speed switch.
5. Run the complete solution and its checks
Save the following block as practice_fastapi.py in an isolated Python environment with FastAPI and HTTPX installed, then run python practice_fastapi.py. The checks use TestClient and do not start a listening web server. The expected final output is “All practice checks passed.”
This exact exercise passed on Python 3.12 with FastAPI 0.143.0, Pydantic 2.14.1, Starlette 1.8.0 and HTTPX 0.28.1. That Starlette version emitted a deprecation warning for its HTTPX adapter; the assertions still passed. Dependency versions can change, so consult the current testing documentation when preparing your own environment.
from typing import Annotated, Literal
from fastapi import Depends, FastAPI, HTTPException
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field
app = FastAPI()
class WorkRequest(BaseModel):
units: int = Field(strict=True, ge=1, le=50)
priority: Literal["normal", "urgent"] = "normal"
class Estimate(BaseModel):
queue_id: int
minutes: int
priority: str
def get_rates() -> dict[int, int]:
return {1: 4, 2: 7}
@app.post("/queues/{queue_id}/estimate", response_model=Estimate)
def estimate(
queue_id: int,
work: WorkRequest,
rates: Annotated[dict[int, int], Depends(get_rates)],
):
if queue_id not in rates:
raise HTTPException(status_code=404, detail="Queue not found")
return {
"queue_id": queue_id,
"minutes": work.units * rates[queue_id],
"priority": work.priority,
"internal_note": "Fictional practice calculation",
}
with TestClient(app) as client:
response = client.post("/queues/1/estimate", json={"units": 3})
assert response.status_code == 200
assert response.json() == {
"queue_id": 1, "minutes": 12, "priority": "normal"
}
assert client.post("/queues/1/estimate", json={"units": 0}).status_code == 422
assert client.post("/queues/1/estimate", json={"units": "3"}).status_code == 422
assert client.post("/queues/1/estimate", json={"units": 3, "priority": "rush"}).status_code == 422
assert client.post("/queues/no/estimate", json={"units": 3}).status_code == 422
assert client.post("/queues/99/estimate", json={"units": 3}).status_code == 404
app.dependency_overrides[get_rates] = lambda: {1: 10}
try:
changed = client.post("/queues/1/estimate", json={"units": 3})
assert changed.status_code == 200
assert changed.json()["minutes"] == 30
finally:
app.dependency_overrides.clear()
print("All practice checks passed.")6. Explain what the checks prove, then extend them
The valid request proves the calculation, default priority and public response shape for queue 1. Separate requests cover a value below the allowed range, a string where a strict integer is required, an invalid priority, a malformed path value and an unknown queue. The override check proves that the endpoint uses the injected rate source.
Add three checks yourself: units=50 succeeds, units=51 fails, and queue 2 with two urgent units returns 14 minutes and urgent priority. Explain why urgent does not change the calculation. Then remove internal_note from the returned dictionary and confirm that the public contract is unchanged.
For a deeper follow-up, propose how you would obtain rates from a database and test missing data without contacting that database. Discuss dependency lifetime, failure behavior and access rules before writing the implementation. The small exercise does not demonstrate persistence, concurrency safety, authentication, authorization or production performance.
Questions, answered
Do I need to memorize every FastAPI decorator for an interview?
Understanding request parsing, validation, dependencies, response behavior and tests is more useful than reciting decorator options. Practice explaining a small endpoint and checking its failure cases.
Does async def automatically make an API faster?
No. It allows cooperative asynchronous work when the operations inside it can be awaited. Blocking calls and CPU-heavy work require deliberate handling; changing the declaration alone does not solve them.
Can this example be deployed as a complete application?
It is a limited teaching exercise. It has no persistence, authentication, authorization, operational monitoring or real service-rate logic. Extend those concerns deliberately for an actual product.
Sources and examples
ResumizeAI team. Examples are fictional teaching material, not customer results. Replace sample details with your own facts.
Your experience. A complete resume.
Build in Resumize with ATS-friendly templates, guided editing and a live preview. Start free, then upgrade when you need more.
Free account required. Free-plan PDF exports include a watermark.