Skip to content

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.

Image

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 typePersoninside the definition scope ofPersonitself,which means at that momentPerson` 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]".