Skip to content
Aabha AI Academy

Stage 1 · L03

Follow HTTP through Uvicorn, ASGI, FastAPI and routing

Core · original Session 1 plus essential local Git/Docker setup

HTTP is the wire-level request and response contract. Uvicorn accepts the TCP connection, parses HTTP and invokes the ASGI application. ASGI presents a scope describing the connection and receive/send callables for events. FastAPI builds on Starlette to match routes, validate declared input, invoke a handler and serialize a response. SQLAlchemy and PostgreSQL are not part of this first request yet.

Trace GET /equipment/1: the path matches /equipment/{equipment_id}; FastAPI converts the path text to the declared integer; get_equipment searches the synthetic catalogue; the returned mapping becomes JSON with status 200. GET /equipment/word matches the same route shape but fails input validation, so the handler never sees an integer. GET /missing matches no route and returns 404. POST /equipment matches an existing path with an unsupported method and returns 405.

Route order matters when shapes overlap. /equipment/search is registered before /equipment/{equipment_id}. If you register the parameter route first, the literal search can be consumed as equipment_id and fail validation. This is an observable 422, not a missing database record. Keep a fixed route ahead of the broad parameter route, or choose distinct path shapes.

Ordinary def handlers are run in FastAPI's worker-thread facility; async def handlers execute on the event loop and must not block it. The stage-01 handlers perform tiny in-memory operations, so ordinary def is clear and valid. Do not convert a blocking database call to async merely by changing the function keyword. Later lessons distinguish an async HTTP integration from an async database driver.

A package groups importable modules; equipment/__init__.py marks this package, and equipment/api.py is its api module. The dotted import equipment.api:app means load that module and obtain its app attribute. Import code executes once per process and must not unexpectedly create tables or make network calls. Run from the snapshot root so Python can find equipment; do not fix an import error by editing unrelated global paths.

APIRouter groups related operations with a prefix and documentation tags. Its @router.get path is relative to that prefix; /search under /equipment composes /equipment/search. app.include_router(router) copies those registered operations into the application. A router left unregistered is not served. The first checkpoint actually uses this grouping; it preserves static search before the integer parameter route.

Exercise the grouping before adding storage: inspect the registered OpenAPI paths, request search and a numeric ID, then temporarily omit include_router in a copied learner app and observe404. Restore it before the baseline. This changes routing registration only; it does not create a separate server or microservice.

GET /equipment/search → fixed route; GET /equipment/1 → integer route; GET /equipment/word → 422; GET /equipment/999 → 404; POST /equipment → 405; Fixed search route is registered; first.
GET /equipment/search → fixed route; GET /equipment/1 → integer route; GET /equipment/word → 422; GET /equipment/999 → 404; POST /equipment → 405; Fixed search route is registered; first.

Follow the running code

Focused lesson example; see the end-of-stage capstone for the cumulative app · stage 01

from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter(prefix='/equipment', tags=['Equipment'])
@router.get('/search')
def search(name: str = ''):
    return {'name': name}
@router.get('/{equipment_id}')
def read(equipment_id: int):
    return {'id': equipment_id}
app.include_router(router)

Predict and observe this focused example using the concepts explained above. Its boundary is stated in the focused answer.

Guided lab

  1. Read the explanation and predict the focused example’s outcome.
  2. Explain the composed path, then predict /equipment/search, /equipment/7 and /equipment/word. What happens if include_router is omitted?
  3. Compare the observed outcome with the focused answer and state its boundary.

Expected: The prefix and local path compose /equipment/search and /equipment/{equipment_id}. Search returns its declared query value; 7 becomes integer 7; word fails conversion with 422. Without include_router the router's operations are absent from the app and requests return 404. Register search first.

  • Route-order experiment can turn search into 422; unknown item is a handler-level 404; unknown path is a router-level 404.

Focused exercise and answer

Complete this focused exercise before reading its answer. The full native transfer is introduced only at the end of the stage.

Your transfer task: Explain the composed path, then predict /equipment/search, /equipment/7 and /equipment/word. What happens if include_router is omitted?

  1. Explain the composed path, then predict /equipment/search, /equipment/7 and /equipment/word. What happens if include_router is omitted?
Inspect the matching answer

This answer addresses the focused exercise above; the cumulative implementation is shown only after the stage prerequisites.

The prefix and local path compose /equipment/search and /equipment/{equipment_id}. Search returns its declared query value; 7 becomes integer 7; word fails conversion with 422. Without include_router the router's operations are absent from the app and requests return 404. Register search first.

Check your reasoning

Does ASGI make a blocking SQL query asynchronous?

Show the explanation

No. The handler declaration, driver and resource lifetime must support the chosen execution model.

Reading progress

54 lessons remain open to guests. Marking a lesson read records reading only; it does not award assessment credit or a certificate.

Device reading marks require browser storage. Reading is always available.

Sign in or create an account to save separate account progress. Your current page is kept.