Schema(...) build time, not at
decoration time. This means you can use string annotations and Python
ForwardRefs to define types that refer to each other — enabling circular and
mutually-recursive type graphs without import cycles.
String annotations (lazy by default with from __future__ import annotations)
Adding from __future__ import annotations at the top of a module makes all
annotations strings automatically. FastQL reads these strings and resolves them
against the module’s globals at schema build time.
Explicit string annotations
Withoutfrom __future__ import annotations, wrap any forward-referenced type in
a string:
Optional, Union (X | None), and
list[...] inside string annotations, matching the same rules as real type hints.
How resolution works
FastQL’s annotation engine (infastql.decorators.annotations) performs the
following steps at Schema(...) build time:
- String /
ForwardRef: creates aTypeReference(name, module)placeholder. - Schema builder indexes all decorated types by their Python class name.
- Resolution pass walks the reachable type graph, replacing each
TypeReferencewith its concrete GraphQL type.
Schema(...) raises a descriptive
LookupError naming the unresolved type.
Circular types
Circular references — whereA references B and B references A — are fully
supported. The schema builder tracks types it has already started building and
returns a placeholder that is filled in once both sides complete.
Circular input types are valid in FastQL’s type system but are rejected by the
GraphQL specification for inputs — attempting to build a schema with a circular
Input graph will raise a validation error at Schema(...) build time.