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]'
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 fromtyping
likeOptional[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})
- You can see that we are using Prisma Python Client here as described in the previous post.
- The query can be protected with
permission_classes
as just like graphql shield. See below.
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 authreturn 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 strawberryschema = 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.