Stop by Stop

Backend line

FastAPI request lifecycle

Every click on a website follows one path, like an order through a restaurant, so you know where problems hide.

Words to know

Stops explain each step. The film plays the whole ride.

Explain it
Route
Front-desk teamCustomerOrders from the siteHost at the doorTakes the slipManagerRescues big mishapsSecurity deskChecks you in and outGuest relationsExplains errors politelySeating hostPicks the right chefOrder deskChecks the formChefCooks the dishCourierSlow extras afterwards
  • Order going in
  • Side note
  • Dish coming back
  • Something went wrong
Stop 1 of 12

A customer places an order

The customer asks the website for item 42. The host at the door, a server, takes the order slip and reads it.

Next stop: The host hands it to the manager

All stops

The everyday version

Think of the front of house at a busy restaurant. Every layer has a twin there.

  • The customeris the Client

    Walks in and asks for a dish.

  • The host at the dooris the Uvicorn

    Greets you, takes the order slip, and passes it inside.

  • The manageris the ServerErrorMiddleware

    Stays alert and handles any kitchen fire so the whole place does not stop.

  • The security deskis the Your middleware

    Checks you in on the way in, and hands your things back on the way out.

  • Guest relationsis the ExceptionMiddleware

    Says “sorry, we are out of that” instead of leaving you confused.

  • The seating hostis the Router

    Reads your order and sends it to the right chef.

  • The order deskis the Dependencies

    Checks the order form is filled in properly before any cooking starts.

  • The chefis the Your function

    Receives a clean, checked order, cooks the dish, and plates only the promised parts.

  • The courieris the BackgroundTasks

    Delivers the receipt after you have already been served and left happy. It never makes you wait.

  • A kitchen fireis a server error

    The chef cannot cope. The manager steps in, and the customer only hears “something went wrong”.

Interview questions

Say the short answer first. Go deeper only if they ask.

What is ASGI, and how does Uvicorn relate to FastAPI?
Short answer

ASGI is the async interface between a server and a Python app. Uvicorn is a server that calls your app.

If they dig deeper

Uvicorn turns HTTP bytes into an ASGI scope plus receive/send awaitables, then calls await app(scope, receive, send). FastAPI, through Starlette, is that callable. WSGI is sync-only and cannot do WebSockets or lifespan.

Answer that loses points

“FastAPI is the web server” or “Uvicorn is a framework”.

In what order do middlewares run?
Short answer

The request goes outside-in in stack order, and the response goes inside-out.

If they dig deeper

The stack is ServerErrorMiddleware, then your middleware, then ExceptionMiddleware, then the router. Among yours, the last add_middleware call becomes outermost, which surprises people. Adding CORS last makes it wrap auth failures too.

Answer that loses points

“Middleware runs in the order I added it, both ways” or forgetting the two built-in layers.

What does def vs async def change?
Short answer

def runs in a threadpool. async def runs on the event loop.

If they dig deeper

Use async def only when everything inside is awaited without blocking. A blocking call there stalls every concurrent request. A def handler with blocking I/O is safe because the loop stays free, limited by the threadpool size. Dependencies follow the same rule on their own.

Answer that loses points

“async def is always faster” or “FastAPI is multi-threaded, so blocking is fine”.

Where does validation happen, and what happens when it fails?
Short answer

It happens before your function runs. A failure returns 422 automatically.

If they dig deeper

Pydantic validates params and body during dependency solving. Errors raise RequestValidationError with loc, msg and type per field. Override it with @app.exception_handler(RequestValidationError). The handler runs without ever entering your function.

Answer that loses points

“Validation happens inside my function” or “it returns 400”.

How do yield dependencies work, and when does cleanup run?
Short answer

Code before yield is setup and code after is teardown. By default in current FastAPI, teardown runs after the response is sent.

If they dig deeper

Current docs say exit code of default scope="request" dependencies runs after the response is sent, while Depends(dep, scope="function") runs it before. Behaviour changed across versions (0.106 to 0.117 ran it before), so check yours. Re-raise exceptions you catch.

Answer that loses points

“Teardown always happens before the client sees anything”, or swallowing exceptions in except.

How do BackgroundTasks differ from Celery?
Short answer

BackgroundTasks run in-process after the response. Celery runs in separate workers behind a broker.

If they dig deeper

BackgroundTasks have no retries, persistence or queue. If the process dies, the task is lost, and a long sync task occupies a threadpool thread. Use them for tiny fire-and-forget work like an email, and Celery or ARQ for durable or heavy work.

Answer that loses points

“They are the same thing” or “background tasks run in a separate process”.

Cheat-sheet

Commands you will actually type.

uvicorn app.main:app --reload

Dev server that restarts on every code change. Not for production.

uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4

Multi-process production run. Workers do not share memory.

fastapi dev app/main.py
fastapi run

The FastAPI CLI: dev mode with reload, then production mode.

@asynccontextmanager
async def lifespan(app: FastAPI):
    pool = await create_pool()
    yield
    await pool.close()

app = FastAPI(lifespan=lifespan)

Startup before `yield`, shutdown after it.

async def get_db():
    async with Session() as s:
        yield s

A yield dependency: setup, hand over the resource, then teardown.

background_tasks.add_task(send_email, to)

Run this after the response is sent. No retries.

@app.exception_handler(RequestValidationError)

Customize the 422 response your clients see.

app.add_middleware(CORSMiddleware, allow_origins=[...])

Adds CORS. The last middleware added is the outermost.

Sources