27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 1/56
GraphQL with Python frameworks GraphQL with Python frameworks
Create next-generation API with ease Bartosz Kazuła
GraphQL with Python frameworks GraphQL with Python frameworks - - PowerPoint PPT Presentation
27.09.2018 reveal.js GraphQL with Python frameworks GraphQL with Python frameworks Create next-generation API with ease Bartosz Kazua http://0.0.0.0:8080/?print-pdf 1/56 27.09.2018 reveal.js About About mua mua Frontend/Backend/Mobile
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 1/56
Create next-generation API with ease Bartosz Kazuła
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 2/56
Frontend/Backend/Mobile developer Software architect Highly focused on new technologies
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 3/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 4/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 5/56
Database
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 6/56
Database REST API
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 7/56
Database REST API Legacy API
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 8/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 9/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 10/56
Entrypoint to API, defines queries and mutations that can be accessed via GraphQL
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 11/56
The most basic components of a GraphQL schema, which just represent a kind of object you can fetch from your service, and what fields it has
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 12/56
Asking for fields and objects based on provided parameters. Here you can define the shape of response.
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 13/56
The way to modify data. If the mutation field returns an object type, you can ask for nested fields.
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }
{ "ep": "JEDI", "review": { "stars": 5, "commentary": "This is a great movie!" } }
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 14/56
A graphical interactive in-browser GraphQL IDE for testing and writing queries.
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 15/56
https://graphene-python.org/
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 16/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 17/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 18/56
pip install graphene graphene-django
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 19/56
pip install graphene graphene-django INSTALLED_APPS = ( # ... 'graphene_django', ) GRAPHENE = { 'SCHEMA': 'app.schema.schema' # Path to main schema }
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 20/56
pip install graphene graphene-django INSTALLED_APPS = ( # ... 'graphene_django', ) GRAPHENE = { 'SCHEMA': 'app.schema.schema' # Path to main schema }
from django.urls import path from graphene_django.views import GraphQLView urlpatterns = [ # ... path('graphql/', GraphQLView.as_view(graphiql=True)), ]
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 21/56
class User(models.Model): name = models.CharField(max_length=20) surname = models.CharField(max_length=30) age = models.IntegerField()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 22/56
class User(models.Model): name = models.CharField(max_length=20) surname = models.CharField(max_length=30) age = models.IntegerField() from graphene_django import DjangoObjectType class UserType(DjangoObjectType): class Meta: model = User
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 23/56
class UserQuery(graphene.ObjectType): users = graphene.List(UserType) def resolve_users(self, info): return User.objects.all()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 24/56
schema = graphene.Schema(query=UserQuery) app/schema.py
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 25/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 26/56
class UserQuery(graphene.ObjectType): users = graphene.List(UserType) user = graphene.Field(UserType, name=graphene.String()) def resolve_users(self, info): return User.objects.all() def resolve_user(self, info, name): return User.objects.filter(name=name).first()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 27/56
class UserQuery(graphene.ObjectType): users = graphene.List(UserType) user = graphene.Field(UserType, name=graphene.String()) def resolve_users(self, info): return User.objects.all() def resolve_user(self, info, name): return User.objects.filter(name=name).first()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 28/56
class UserQuery(graphene.ObjectType): users = graphene.List(UserType) user = graphene.Field(UserType, name=graphene.String()) def resolve_users(self, info): return User.objects.all() def resolve_user(self, info, name): return User.objects.filter(name=name).first()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 29/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 30/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 31/56
class UserMutation(graphene.Mutation): user = graphene.Field(UserType) class Arguments: name = graphene.String() surname = graphene.String() age = graphene.Int() def mutate(self, info, **kwargs): user = User.objects.create(**kwargs) return UserMutation(user=user)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 32/56
class Mutations(graphene.ObjectType): create_user = UserMutation.Field() schema = graphene.Schema(query=UserQuery, mutation=Mutations)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 33/56
class Mutations(graphene.ObjectType): create_user = UserMutation.Field() schema = graphene.Schema(query=UserQuery, mutation=Mutations)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 34/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 35/56
class UserForm(forms.ModelForm): class Meta: model = User fields = ('name', 'surname', 'age') class UserMutation(DjangoModelFormMutation): class Meta: form_class = UserForm
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 36/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 37/56
I use REST Framework - how to live? Take a look at graphene_django.rest_framework package. How to validate data? When using forms - use built-in validation. When going plain - add your own validator. How to receive user data? Use info.context variable passed to every function.
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 38/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 39/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 40/56
pip install graphene graphene_sqlalchemy Flask-GraphQL app.add_url_rule( '/graphql', view_func=GraphQLView.as_view( 'graphql', schema=schema, graphiql=True ) )
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 41/56
class Post(Model): __tablename__ = 'posts' id = Column(Integer, primary_key=True) name = Column(String) intro = Column(Text) content = Column(Text) author = Column(String)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 42/56
class PostType(SQLAlchemyObjectType): class Meta: model = Post
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 43/56
class PostType(SQLAlchemyObjectType): class Meta: model = Post class Query(graphene.ObjectType): posts = graphene.List(PostType) def resolve_posts(self, info): return Post.query.all()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 44/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 45/56
class Query(graphene.ObjectType): posts = graphene.List(PostType) post = graphene.Field(PostType, id=graphene.Int()) def resolve_posts(self, info): return Post.query.all() def resolve_post(self, info, id): return Post.query.get(id)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 46/56
class Query(graphene.ObjectType): posts = graphene.List(PostType) post = graphene.Field(PostType, id=graphene.Int()) def resolve_posts(self, info): return Post.query.all() def resolve_post(self, info, id): return Post.query.get(id)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 47/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 48/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 49/56
class CreatePost(graphene.Mutation): post = graphene.Field(PostType) class Arguments: name = graphene.String() intro = graphene.String() content = graphene.String() author = graphene.String() def mutate(self, info, **kwargs): post = Post(**kwargs) db_session.add(post) db_session.commit()
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 50/56
class Mutations(graphene.ObjectType): create_post = CreatePost.Field() schema = graphene.Schema(query=Query, mutation=Mutations)
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 51/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 52/56
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 53/56
Check out the "errors" list next to data. If it has some errors then handle them. You can customize your GraphQLView to handle errors differently.
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 54/56
There are two:
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 55/56
Read about batching queries.
27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 56/56
bkazula bartosz@kazula.eu