Prisma with FastAPI and GraphQL

Hyo
dooboolab
Published in
3 min readJun 19, 2022

Following the previous post, we want to continue working on creating graphql resolvers in the current post.

Since FastAPI recommends using Strawberry for using graphql as written in the document, we decided to look into this.

1. Install strawberry-graphql and add directories

pip install 'strawberry-graphql[debug-server]'
We created `models` and `resolvers` folders under `src`.

2. Adding graphql types

You can define the graphql types with Strawberry with decorators. As an example in User.py, the code looks like the one below.

@strawberry.type
class User:
id: strawberry.ID
email: str
name: Optional[str] = None
nickname: Optional[str] = None
thumbURL: Optional[str] = None
photoURL: Optional[str] = None
birthday: Optional[date] = None
gender: Optional[Gender] = None
phone: Optional[str] = None
@strawberry.enum
class Gender(Enum):
Male = "male"
Female = "female"
  • ID type can be defined as strawberry.ID
  • Required type can be defined as str, int
  • An optional type can be defined with Optional imported from typing like Optional[str]
  • Enum type can be defined with @strawberry.enum as written above
  • Date type can be defined from datetime import date

More can be found in Strawberry schema directives.

3. Adding queries

Create queries with Strawberry type.

@strawberry.type
class Query:
@strawberry.field(permission_classes=[IsAuthenticated])
def users(self) -> List[User]:
return prisma.user.find_many()
@strawberry.field(permission_classes=[IsAuthenticated])
def user(self, id: strawberry.ID) -> User:
return prisma.user.find_unique(where={"id": id})
class IsAuthenticated(BasePermission):
message = "User is not authenticated"
def has_permission(self, source: typing.Any, info: Info, **kwargs) -> bool:
request: typing.Union[Request, WebSocket] = info.context["request"]
authorization = request.headers.get("Authorization")
if "Authorization" in request.headers:
auth = decodeJWT(authorization)
return auth
return False

4. Adding mutation queries

Creating mutation queries is similar to adding queries.

@strawberry.type
class Mutation:
@strawberry.mutation
async def signIn(self, email: str, password: str) -> AuthPayload:
user = await prisma.user.find_first(
where={
"email": email,
}
)
validated = validatePassword(password, user.password)if validated:
token = signJWT(user.id)
return AuthPayload(token=token, user=user)
return None

You can define return class like above which is AuthPayload. It looks like the one below.

@strawberry.type
class User:
id: strawberry.ID
email: str
name: Optional[str] = None
nickname: Optional[str] = None
thumbURL: Optional[str] = None
photoURL: Optional[str] = None
birthday: Optional[date] = None
gender: Optional[Gender] = None
phone: Optional[str] = None
@strawberry.type
class AuthPayload:
token: str
user: User

5. Adding input types

@strawberry.input
class UserCreateInput:
email: str
password: str
name: Optional[str] = None
nickname: Optional[str] = None
birthday: Optional[datetime.date] = None
gender: Optional[Gender] = None
phone: Optional[str] = None

6. Define the Strawberry schema altogether in __init__.py

from src.resolvers.users import Query, Mutation
import strawberry
schema = strawberry.Schema(query=Query, mutation=Mutation)

7. Run server

uvicorn main:app --reload

Note: If you want to set Authorization header you might need another graphql tool like Insomnia.

--

--