Problem
The quickstart's Forms section (line 476-512) teaches await request.form() as the primary form pattern with the annotation:
As Air is based off starlette, when we receive data from a form it needs to occur within an async view.
This is misleading. Air's AirForm works with def endpoints via FastAPI's dependency injection:
from typing import Annotated
from fastapi import Depends
@app.post("/submit")
def handle_form(form: Annotated[ContactForm, Depends(ContactForm.from_request)]):
if form.is_valid:
return air.H1(f"Name: {form.data.name}")
return form.render()
FastAPI resolves async dependencies on the event loop before dispatching sync endpoints to the threadpool. Verified working.
What should change
- The Forms section should lead with the simplest pattern that works
- The annotation "it needs to occur within an async view" should be removed or corrected
- Raw
await request.form() is a Starlette escape hatch, not the primary recommendation
Additional context
The quickstart also uses air.Form(...) as a parameter default (line 104), which is a separate bug (see #1082). air.Form is the HTML <form> tag, not FastAPI's Form().
Found during work on #1077.
Problem
The quickstart's Forms section (line 476-512) teaches
await request.form()as the primary form pattern with the annotation:This is misleading. Air's
AirFormworks withdefendpoints via FastAPI's dependency injection:FastAPI resolves async dependencies on the event loop before dispatching sync endpoints to the threadpool. Verified working.
What should change
await request.form()is a Starlette escape hatch, not the primary recommendationAdditional context
The quickstart also uses
air.Form(...)as a parameter default (line 104), which is a separate bug (see #1082).air.Formis the HTML<form>tag, not FastAPI'sForm().Found during work on #1077.