Open twavv opened 1 year ago
I think the FAQ blurb about circular imports is missing a (IMO pretty important) case where you have a strawberry.field()
that specifies a resolver function.
I'll share some examples from my own project:
# cargo.py
def get_cargo_flights(
cargo_uuid: UUID,
) -> List[Annotated["FlightResult",
strawberry.lazy("flight_pipeline.api.flights")]]
]:
"""Get all flights associated with the given cargo"""
query_result = Flights().get_cargo_flights(cargo_id=cargo_uuid)
result = []
for flight in query_result:
result.append(FlightResult.from_db_model(flight)) # <--- still need a concrete FlightResult here
return result
...
@strawberry.type
class CargoResult:
uuid: UUID
bag_tag: str
flights: List[Annotated["FlightResult",
strawberry.lazy("flight_pipeline.api.flights")]
] = strawberry.field(
resolver=lambda root: get_cargo_flights(cargo_uuid=root.uuid)
)
...
and likewise for flights:
# flights.py
from flight_pipeline.api.cargo import CargoResult
def get_flight_cargo(
flight_uuid: UUID
) -> List[Annotated["CargoResult",
strawberry.lazy("flight_pipeline.api.cargo")]]:
"""Get all cargo associated with the given flight"""
query_result = Cargo().get_flight_cargo(flight_id=flight_uuid)
result = []
for cargo in query_result:
result.append(CargoResult.from_db_model(cargo))
return result
class FlightResult:
uuid: UUID
flight_number: str
cargo: List[Annotated["CargoResult",
strawberry.lazy("flight_pipeline.api.cargo")]
] = strawberry.field(
resolver=lambda root: get_flight_cargo(flight_uuid=root.uuid)
)
...
I was eventually able to find a (seemingly hacky) solution: move the from flight_pipeline.api.flights import FlightResult
to the very bottom of cargo.py (and leave the from flight_pipeline.api.cargo import CargoResult
at the top of flights.py); this seems to evaluate the import late enough that the circular import error is avoided. But it seems like this is not a reliable solution...
Circular dependencies seem to be a common issue with Strawberry.
I'm wondering if Strawberry would consider adding support for something like type-graphql's
FieldResolver
s. That allows one to define fields for other types outside of the immediate class definition of that type.For example, consider a schema with
Person
andPet
objects. APerson
might have apets: [Pet!]!
field and each pet might have aowners: [Person!]!
field. This requiresPerson
andPet
to "know" about each other.With type-graphql, one can define
and
In Strawberry land, this might look something like
and
Thoughts? Am I missing something?
Upvote & Fund