Analyzer::Python::FastAPI
Inherits Analyzer::Python::PythonEngine < Analyzer < FileHelper < Reference < Object
Constants
A bare dict keeps reading the keys the handler takes from it.
Constant-only matchers hoisted out of the per-line analyze loops so
they aren't recompiled (Crystal rebuilds an interpolated regex
literal on every evaluation). The .to_s expansion of the
interpolated constants is byte-identical to the previous inline form.
The Python identifier a FastAPI handler declares is not always the name the client sends. Two rules rewrite it, and Noir honored neither:
alias=overrides the name outright, for every parameter class (Header,Query,Cookie,Form,File,Body,Path).Header— and onlyHeader— additionally maps_to-, because an HTTP header name can't carry an underscore in most stacks. That isconvert_underscores, and it defaults to True; passingconvert_underscores=Falseis what opts back out.
Reporting the identifier verbatim is not a cosmetic mismatch: it is the
name Noir hands to the next stage. -f curl emitted -H 'x_token: '
for x_token: str = Header(None), a header the app reads as nothing,
and a DAST tool importing the OpenAPI doc probed ?q_name= for a
parameter the app only accepts as q-name.
def init_views(app: FastAPI) (space-stripped): the app built
elsewhere and handed in; its include_router / @app.get calls in
this file register on it too.
Library subclasses of fastapi.APIRouter, constructed like it.
The same rename, one layer down. A request body is described by a
Pydantic model, and Field(alias=...) renames the key there too —
with populate_by_name off (the default) the alias is the only key
the model accepts, so the attribute name is a body field the app
rejects outright.
class UserRouter(APIRouter): — a project router class, constructed
like APIRouter itself.
Class methods
Instance methods
Configures the prefix for each router
Finds the parameters for a base model class, base classes first
(Pydantic orders inherited fields that way): those declared in the
same source, else, given path, where the source imports them from.
Field names follow an inherited alias_generator named for camelCase
unless a Field(alias=...) names the field itself.
Finds parameters in dictionary structures
Infers the type of the parameter based on its default value or type annotation
Best-effort resolver for a non-literal prefix= expression in
include_router(...). Handles two shapes the wild produces:
prefix=API_V1_STR— a top-level constant imported viafrom app.core.config import API_V1_STR. We look up the constant's defining module viaimport_modulesand search it forNAME = "literal".prefix=settings.API_V1_STR— class-attribute access on an imported instance. We look upsettings's module and search it forAPI_V1_STR: str = "literal"(the BaseSettings shape full-stack-fastapi-template uses) orAPI_V1_STR = "literal".
Returns nil when the expression doesn't match either shape or we can't find the underlying file — the caller then falls back to an empty prefix so we never surface raw Python expressions in URLs.
Instance-side view of the same declaration. The per-file rescues live on
this base class, which has no way to name the analyzer that is running
inside them, so a skipped file could not be attributed to a tech.
Deriving it from analyzer_for keeps the name written exactly once.