FastAPI

Lesson 06

Async handler boundaries

Keep async route handlers non-blocking and await asynchronous collaborators directly.

Good Code

api/reports.py
from fastapi import APIRouter

router = APIRouter()


@router.get("/reports/{report_id}")
async def get_report(report_id: int):
    report = await report_service.fetch_report(report_id)
    audit = await audit_service.record_view(report_id)
    return {"report": report, "audit_id": audit.id}

Bad Code

api/reports.py
import requests
from fastapi import APIRouter

router = APIRouter()


@router.get("/reports/{report_id}")
async def get_report(report_id: int):
    response = requests.get(f"https://api.example.com/reports/{report_id}")
    audit_service.record_view(report_id)
    return response.json()

Review Notes

What to review

Good Code

The good version awaits async collaborators so I/O yields control back to the event loop.

Bad Code

The bad version calls a blocking HTTP client inside an async route and forgets to await the audit work.

Takeaways

  • An `async def` route should not hide blocking I/O inside the event loop.