GraphQL with Python frameworks GraphQL with Python frameworks - - PowerPoint PPT Presentation

graphql with python frameworks graphql with python
SMART_READER_LITE
LIVE PREVIEW

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


slide-1
SLIDE 1

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

slide-2
SLIDE 2

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 2/56

About About mua mua

Frontend/Backend/Mobile developer Software architect Highly focused on new technologies

slide-3
SLIDE 3

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 3/56

What is GraphQL? What is GraphQL?

A query language for your API

slide-4
SLIDE 4

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 4/56

How it works How it works

slide-5
SLIDE 5

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 5/56

How it works How it works

Database

slide-6
SLIDE 6

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 6/56

How it works How it works

Database REST API

slide-7
SLIDE 7

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 7/56

How it works How it works

Database REST API Legacy API

slide-8
SLIDE 8

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 8/56

Is it production ready? Is it production ready?

slide-9
SLIDE 9

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 9/56

Data structures Data structures

Schema Type Query Mutation

slide-10
SLIDE 10

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 10/56

Schema Schema

Entrypoint to API, defines queries and mutations that can be accessed via GraphQL

type Schema { query: Query mutation: Mutation }

slide-11
SLIDE 11

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 11/56

Type Type

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

type Character { name: String! appearsIn: [Episode]! }

slide-12
SLIDE 12

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 12/56

Query Query

Asking for fields and objects based on provided parameters. Here you can define the shape of response.

{ hero { name } }

slide-13
SLIDE 13

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 13/56

Mutation Mutation

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!" } }

slide-14
SLIDE 14

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 14/56

GraphiQL GraphiQL

A graphical interactive in-browser GraphQL IDE for testing and writing queries.

slide-15
SLIDE 15

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 15/56

Graphene Graphene

GraphQL in Python made easy GraphQL in Python made easy

https://graphene-python.org/

pip install graphene

slide-16
SLIDE 16

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 16/56

Let's build some API Let's build some API

Add user / get user / get all users Add blog post / get post / get all posts

slide-17
SLIDE 17

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 17/56

Django Django

slide-18
SLIDE 18

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 18/56

pip install graphene graphene-django

slide-19
SLIDE 19

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 }

slide-20
SLIDE 20

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)), ]

slide-21
SLIDE 21

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 21/56

User model User model

class User(models.Model): name = models.CharField(max_length=20) surname = models.CharField(max_length=30) age = models.IntegerField()

slide-22
SLIDE 22

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 22/56

User model User model UserType UserType

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

slide-23
SLIDE 23

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 23/56

User Query User Query

class UserQuery(graphene.ObjectType): users = graphene.List(UserType) def resolve_users(self, info): return User.objects.all()

slide-24
SLIDE 24

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 24/56

Schema Schema

schema = graphene.Schema(query=UserQuery) app/schema.py

slide-25
SLIDE 25

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 25/56

slide-26
SLIDE 26

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 26/56

Getting one user Getting one user

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()

slide-27
SLIDE 27

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 27/56

Getting one user Getting one user

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()

slide-28
SLIDE 28

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 28/56

Getting one user Getting one user

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()

slide-29
SLIDE 29

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 29/56

slide-30
SLIDE 30

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 30/56

User mutation User mutation

slide-31
SLIDE 31

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 31/56

Plain GraphQL mutation Plain GraphQL mutation

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)

slide-32
SLIDE 32

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 32/56

Add mutation to the schema Add mutation to the schema

class Mutations(graphene.ObjectType): create_user = UserMutation.Field() schema = graphene.Schema(query=UserQuery, mutation=Mutations)

slide-33
SLIDE 33

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 33/56

Add mutation to the schema Add mutation to the schema

class Mutations(graphene.ObjectType): create_user = UserMutation.Field() schema = graphene.Schema(query=UserQuery, mutation=Mutations)

slide-34
SLIDE 34

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 34/56

slide-35
SLIDE 35

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 35/56

Django Forms-based mutation Django Forms-based mutation

class UserForm(forms.ModelForm): class Meta: model = User fields = ('name', 'surname', 'age') class UserMutation(DjangoModelFormMutation): class Meta: form_class = UserForm

slide-36
SLIDE 36

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 36/56

slide-37
SLIDE 37

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 37/56

Django FAQ Django FAQ

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.

slide-38
SLIDE 38

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 38/56

GraphQL with Django GraphQL with Django Q&A Q&A

slide-39
SLIDE 39

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 39/56

Flask Flask

slide-40
SLIDE 40

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 40/56

Installation Installation

pip install graphene graphene_sqlalchemy Flask-GraphQL app.add_url_rule( '/graphql', view_func=GraphQLView.as_view( 'graphql', schema=schema, graphiql=True ) )

slide-41
SLIDE 41

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 41/56

Post model Post model

class Post(Model): __tablename__ = 'posts' id = Column(Integer, primary_key=True) name = Column(String) intro = Column(Text) content = Column(Text) author = Column(String)

slide-42
SLIDE 42

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 42/56

Type and query Type and query

class PostType(SQLAlchemyObjectType): class Meta: model = Post

slide-43
SLIDE 43

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 43/56

Type and query Type and query

class PostType(SQLAlchemyObjectType): class Meta: model = Post class Query(graphene.ObjectType): posts = graphene.List(PostType) def resolve_posts(self, info): return Post.query.all()

slide-44
SLIDE 44

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 44/56

slide-45
SLIDE 45

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 45/56

Get one post Get one post

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)

slide-46
SLIDE 46

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 46/56

Get one post Get one post

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)

slide-47
SLIDE 47

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 47/56

slide-48
SLIDE 48

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 48/56

A mutation has no helpers ☹ A mutation has no helpers ☹

slide-49
SLIDE 49

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 49/56

Create post mutation Create post mutation

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()

slide-50
SLIDE 50

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 50/56

Add mutation to schema Add mutation to schema

class Mutations(graphene.ObjectType): create_post = CreatePost.Field() schema = graphene.Schema(query=Query, mutation=Mutations)

slide-51
SLIDE 51

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 51/56

slide-52
SLIDE 52

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 52/56

FAQ FAQ

slide-53
SLIDE 53

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 53/56

How to handle errors? How to handle errors?

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.

slide-54
SLIDE 54

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 54/56

Best authorization approach? Best authorization approach?

There are two:

  • 1. Private & public GraphQL endpoints ( BAD!)
  • 2. Login required decorator wrapping classes/methods
slide-55
SLIDE 55

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 55/56

How to limit database calls? How to limit database calls?

Read about batching queries.

slide-56
SLIDE 56

27.09.2018 reveal.js http://0.0.0.0:8080/?print-pdf 56/56

Thanks for watching Thanks for watching

Bartosz Kazuła Bartosz Kazuła

bkazula bartosz@kazula.eu

@