0

I want to explore the creation of a graphql DB using Fastapi and Strawberry. I Start with the basic FastAPI API (taken from their website):

from typing import List, Optional

from fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select


class TeamBase(SQLModel):
    name: str = Field(index=True)
    headquarters: str


class Team(TeamBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    heroes: List["Hero"] = Relationship(back_populates="team")


class TeamCreate(TeamBase):
    pass


class TeamRead(TeamBase):
    id: int

class HeroBase(SQLModel):
    name: str = Field(index=True)
    secret_name: str
    age: Optional[int] = Field(default=None, index=True)

    team_id: Optional[int] = Field(default=None, foreign_key="team.id")


class Hero(HeroBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

    team: Optional[Team] = Relationship(back_populates="heroes")


class HeroRead(HeroBase):
    id: int


class HeroCreate(HeroBase):
    pass

class HeroReadWithTeam(HeroRead):
    team: Optional[TeamRead] = None


class TeamReadWithHeroes(TeamRead):
    heroes: List[HeroRead] = []


DATABASE_URL = 'postgresql+psycopg2://postgres:password@db:5432/blog_db'

engine = create_engine(DATABASE_URL, echo=True)



def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def get_session():
    with Session(engine) as session:
        yield session


app = FastAPI()


@app.on_event("startup")
def on_startup():
    create_db_and_tables()


@app.post("/heroes/", response_model=HeroRead)
def create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):
    db_hero = Hero.from_orm(hero)
    session.add(db_hero)
    session.commit()
    session.refresh(db_hero)
    return db_hero


@app.get("/heroes/", response_model=List[HeroReadWithTeam])
def read_heroes(
    *,
    session: Session = Depends(get_session),
    offset: int = 0,
    limit: int = Query(default=100, lte=100),
):
    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
    print(heroes)
    return heroes



@app.post("/teams/", response_model=TeamRead)
def create_team(*, session: Session = Depends(get_session), team: TeamCreate):
    db_team = Team.from_orm(team)
    session.add(db_team)
    session.commit()
    session.refresh(db_team)
    return db_team


@app.get("/teams/", response_model=List[TeamRead])
def read_teams(
    *,
    session: Session = Depends(get_session),
    offset: int = 0,
    limit: int = Query(default=100, lte=100),
):
    teams = session.exec(select(Team).offset(offset).limit(limit)).all()
    
    return teams

I don't fully understand the get method for heroes. In the log, I see it first queries the heroes table and then gets the team information in another query, but after the return. I suppose it's some magic happening thanks to the response_model.

Building a GraphQL sound like an easy task. The problem is that there I cannot make the transformation that takes place thanks to the response_model and it returns only the hero information, without nesting with the team information

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
gontxomde
  • 132
  • 9
  • I suggest looking up how `foreign_key` argument works in relation to `response_model` – OneCricketeer Aug 19 '23 at 23:46
  • Also, you can make Graphql resolver do a localhost http GET connection. You don't have to query the database directly – OneCricketeer Aug 19 '23 at 23:50
  • Is it a good practice for a graphql to need a get request? This means I need a rest api in order to build a GraphQL API. Regarding your first comment, could you give me any source or elaborate? Thanks! – gontxomde Aug 20 '23 at 00:07
  • 1
    It's not a requirement for graphql, no, but I'm giving you a way to get the data you expect (you've not shown your resolver code/schema anyway). Regarding Fastapi, it'll [convert the data](https://fastapi.tiangolo.com/tutorial/response-model/), yes, which has a [relationship](https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/) that's added whenever the model is queried (such as selecting from the hero table) – OneCricketeer Aug 20 '23 at 14:44

0 Answers0