Classes with complex attributes
FastGraphQL also supports classes with attributes
having as type any other supported type.
Let us have a look at the following code
main.py |
---|
| from fastapi import FastAPI
from fastgraphql import FastGraphQL
from fastgraphql.fastapi import make_ariadne_fastapi_router
from pydantic import BaseModel
from typing import List
app = FastAPI()
fast_graphql = FastGraphQL()
@fast_graphql.type()
class Address(BaseModel):
planet: str
@fast_graphql.type()
class Person(BaseModel):
first_name: str
last_name: str
age: int
height: float
addresses: List[Address]
siblings: List["Person"]
@fast_graphql.query()
def get_person() -> Person:
return Person(
first_name="Luke",
last_name="Skywalker",
height=1.7,
age=23,
siblings=[
Person(
first_name="Leia",
last_name="Organa",
age=23,
height=1.6,
addresses=[],
siblings=[],
)
],
addresses=[Address(planet="Tatooine")],
)
app.include_router(make_ariadne_fastapi_router(fast_graphql=fast_graphql))
|
and, as always, run
$ uvicorn main:app --reload
and under http://127.0.0.1:8000/graphql
you can see the result.
Dissecting
Step 1: Define models
main.py |
---|
| from fastapi import FastAPI
from fastgraphql import FastGraphQL
from fastgraphql.fastapi import make_ariadne_fastapi_router
from pydantic import BaseModel
from typing import List
app = FastAPI()
fast_graphql = FastGraphQL()
@fast_graphql.type()
class Address(BaseModel):
planet: str
@fast_graphql.type()
class Person(BaseModel):
first_name: str
last_name: str
age: int
height: float
addresses: List[Address]
siblings: List["Person"]
@fast_graphql.query()
def get_person() -> Person:
return Person(
first_name="Luke",
last_name="Skywalker",
height=1.7,
age=23,
siblings=[
Person(
first_name="Leia",
last_name="Organa",
age=23,
height=1.6,
addresses=[],
siblings=[],
)
],
addresses=[Address(planet="Tatooine")],
)
app.include_router(make_ariadne_fastapi_router(fast_graphql=fast_graphql))
|
In the highlighted lines we are defining Pydantinc models as explained in the
previous chapter, Classes
Step 2: Reference other models
main.py |
---|
| from fastapi import FastAPI
from fastgraphql import FastGraphQL
from fastgraphql.fastapi import make_ariadne_fastapi_router
from pydantic import BaseModel
from typing import List
app = FastAPI()
fast_graphql = FastGraphQL()
@fast_graphql.type()
class Address(BaseModel):
planet: str
@fast_graphql.type()
class Person(BaseModel):
first_name: str
last_name: str
age: int
height: float
addresses: List[Address]
siblings: List["Person"]
@fast_graphql.query()
def get_person() -> Person:
return Person(
first_name="Luke",
last_name="Skywalker",
height=1.7,
age=23,
siblings=[
Person(
first_name="Leia",
last_name="Organa",
age=23,
height=1.6,
addresses=[],
siblings=[],
)
],
addresses=[Address(planet="Tatooine")],
)
app.include_router(make_ariadne_fastapi_router(fast_graphql=fast_graphql))
|
Now we declare class attributes whose types are other Pydantinc models.
Nothing else is needed.
Forward References
Let us take a closer look at line 24``, here we are using a
<a href="https://peps.python.org/pep-0484/#forward-references" target="_black">*Forward Reference*</a>.
The special thing about _Forward References_ is that it allows annotating something
yet not fully defined or yet not defined at all. In our case, we are referencing
the type
Personinside the definition scope of
Personitself,
which means at that moment
Person` is not yet fully defined.
FastGraphQL only supports Forward References in the form List["Person"]
and not
"List[Person]"
even though both are correct. This holds to all generic
annotations, e.g. Optional["Person"]
vs "Optional[Person]"
.