Slide 1

Slide 1 text

DjangoではじめるGraphQLと フロントエンド開発の協業 DjangoCongress JP 2019 2019.05.18 GitHub @nasum Twitter @tomato360

Slide 2

Slide 2 text

自己紹介 那須理也 Twitter:@tomato360 https://twitter.com/tomato360 GitHub:@nasum https://github.com/nasum 所属:LAPRAS株式会社

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

なんでGraphQL?

Slide 6

Slide 6 text

Githubが2017年にAPI v4に採用 > Why GitHub is using GraphQL > GitHub chose GraphQL for our API v4 because it offers significantly more flexibility for our integrators. The ability to define precisely the data you want—and only the data you want—is a powerful advantage over the REST API v3 endpoints. GraphQL lets you replace multiple REST requests with a single call to fetch the data you specify. > GitHubは、API v4にGraphQLを選択しました。インテグレータにとって、柔軟性が大 幅に向上するためです。必要なデータ(および必要なデータのみ)を正確に定義できるこ とは、REST API v3エンドポイントを超える強力な利点です。 GraphQLでは、指定した データを取得するために、複数のREST要求を単一の呼び出しに置き換えることができ ます。 https://developer.github.com/v4/

Slide 7

Slide 7 text

2018年11月 GraphQL Foundation設立

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

機は熟した(個人の感想です)

Slide 10

Slide 10 text

学びたいが自分の領域に近いところで 学びたい

Slide 11

Slide 11 text

最近仕事で使っているのはDjango

Slide 12

Slide 12 text

そこでGraphene-Django

Slide 13

Slide 13 text

今日話すこと ● GraphQLの基礎 ● graphene-djangoの紹介 ● graphene-djangoを使ったWebアプリケーションの開発 ○ バックエンドにgraphene-django ○ フロントエンドにvue-apollo ○ うまく連携させる ● GraphQL雑感(個人の意見です)

Slide 14

Slide 14 text

GraphQLの基礎

Slide 15

Slide 15 text

GraphQLとは ● WebAPIのための規格 ○ クエリ言語とスキーマからなる ● 2015年にFacebookが仕様を公開 ● 現在はGraphQL Foundationでメンテナンスされている

Slide 16

Slide 16 text

REST APIと比べて優れていること ● エンドポイントが1つになる ● 1リクエストで必要なデータを全て取得できる ○ RESTだと複数APIを叩いて1ページを構築しがち ● スキーマファーストな開発が出来る ○ フロントとバックエンドの開発を非同期に行える ● スキーマに型が定義出来る ○ みんな型欲しいよね?私は欲しいです

Slide 17

Slide 17 text

type Ship { id: ID! name: String! shipType: ShipType! } type Organization { id: ID! name:String! ships: [Ship] } type Query { ships(name: String, shipType: ShipType): [Ship!]! organizations(name: String): [Organization!]! } APIを定義するスキーマ 型の定義 クエリの定義

Slide 18

Slide 18 text

データを取得するためのQuery クエリの実行 { "data": { "ships": [ { "name": "aoba", "shipType": "HEAVY_CRUISER" } ] } } query ships { ships { name shipType } }

Slide 19

Slide 19 text

データを更新するためのMutation Mutationの実行 mutation newShip { createShip(input:{name:"aoba", shipType: HEAVY_CRUISER}) { id name shipType } } { "data": { "createShip": { "id": "乱数", "name": "aoba", "shipType": "HEAVY_CRUISER" } } }

Slide 20

Slide 20 text

GraphQLには他にもいろいろな機能がある ● 共通フィールドを定義できるinterface ● 返値にいずれかの型を指定できるunion ● クエリとべつに渡すことがができるVariables ● メタデータを与えられるDirective

Slide 21

Slide 21 text

まずはGitHubのAPIで試してみる(デモ) https://developer.github.com/v4/explorer/

Slide 22

Slide 22 text

graphene-djangoの簡単な紹介

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

スポンサーがいないのが 若干気になるが・・・

Slide 25

Slide 25 text

ドキュメントが豊富で安心感がある

Slide 26

Slide 26 text

graphene-djangoの特徴 ● Pythonのコードでスキーマを構築する ● graphiqlが簡単に使える ● relayを使う場合便利(未検証)

Slide 27

Slide 27 text

サンプル from django.db import models from graphene_django import DjangoObjectType import graphene class UserModel(models.Model): name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class User(DjangoObjectType): class Meta: model = UserModel class Query(graphene.ObjectType): users = graphene.List(User) def resolve_users(self, info): return UserModel.objects.all() schema = graphene.Schema(query=Query) https://github.com/graphql-python/graphene-django/#examples

Slide 28

Slide 28 text

graphiqlが簡単に使える urlpatterns = [ path('admin/', admin.site.urls), path('', TemplateView.as_view(template_name='index.html')), path('graphql/', GraphQLView.as_view(graphiql=True)), ] + static(settings.STATIC_URL) Trueにするとgraphiqlが使える

Slide 29

Slide 29 text

relayと組み合わせると便利 ./manage.py graphql_schema --out schema.json ● babel-relay-pluginで読み込めるスキーマが出力できる ● react-relayとかで組み合わせると良さそう

Slide 30

Slide 30 text

Graphene-Djangoを使った Webアプリケーション開発

Slide 31

Slide 31 text

クイズアプリの実装

Slide 32

Slide 32 text

クイズアプリの実装 https://quiz-l.herokuapp.com/ https://github.com/nasum/quiz

Slide 33

Slide 33 text

使用技術等 ● django ● graphene-django ● vue-apollo(!)

Slide 34

Slide 34 text

まずはバックエンドの開発

Slide 35

Slide 35 text

モデル作成 from django.db import models class Terms(models.Model): title = models.CharField(max_length=256) def __str__(self): return self.title

Slide 36

Slide 36 text

GraphQLのスキーマを作成する # 型の作成 class TermType(DjangoObjectType): class Meta: model = Terms id = graphene.ID() title = graphene.String() questions = graphene.List(QuestionsType)

Slide 37

Slide 37 text

リゾルバの作成 class Query(graphene.ObjectType): term = graphene.Field(TermType, id=graphene.ID()) terms = graphene.List(TermType) def resolve_term(self, info, id): return Terms.objects.get(pk=id) def resolve_terms(self, info): return Terms.objects.all() 各フィールドに対応する 関数を定義する djangoのormを使用して書ける

Slide 38

Slide 38 text

登録する schema = graphene.Schema(query=Query)

Slide 39

Slide 39 text

Mutationの作成 class CreateTerm(graphene.Mutation): term = graphene.Field(TermType) question = graphene.Field(QuestionsType) answer = graphene.Field(AnswersType) class Arguments: title = graphene.String(required=True) questions = graphene.List(QuestionsInputType) クラス名がMutationの名前になる

Slide 40

Slide 40 text

Mutationの作成 def mutate(self, info, title, questions): term = Terms.objects.create(title=title) for question in questions: question_obj = Questions.objects.create( terms=term, description=question.description ) # 略 return CreateTerm(term=term) Argumentフィールドに定義した変数が 引数として渡される

Slide 41

Slide 41 text

Mutationの作成 class MyMutations(graphene.ObjectType): create_term = CreateTerm.Field() schema = graphene.Schema( query=Query, mutation=MyMutations )

Slide 42

Slide 42 text

ここまでくるとGraphiQLで確認できる https://quiz-l.herokuapp.com/graphql/

Slide 43

Slide 43 text

これでバックエンドはできた

Slide 44

Slide 44 text

次はフロント

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

vue-apollo ● Vue.jsでapollo-clientを使いやすくするPlugin ● VueCLIで簡単に入れることが出来る ○ vue add apollo ● Vue.jsでGraphQLをやるときおそらく一番使いやすい

Slide 47

Slide 47 text

apollo-clientが便利 ● データの取得等をほとんど任せられる ○ axiosなどのhttp requestのためのライブラリは内包している ● キャッシュの仕組みやリロード周りも設定を書ける ● WebSocketにも対応している ● データソースはGraphQLサーバー相手でなくても良い ○ localstorageとかもクエリすることが出来る

Slide 48

Slide 48 text

vue-apolloを使ったクエリの実行方法 export default Vue({ name: 'Index', apollo: { terms: gql`query{ terms { id, title } }` } }) graphql-tagが提供しているテ ンプレートリテラルのタグ クエリをパースしている。 this.termsでアクセス出来る ようになる

Slide 49

Slide 49 text

methods: { async register() { const result = await this.$apollo.mutate({ // Query mutation: gql`mutation ($title: String!, $questions: [QuestionsInputType]){ createTerm(title: $title, questions: $questions) { term { title } } }`, // Parameters variables: { title: this.title, questions: this.questions }, }) } } Mutationの実行方法 mutationのクエリ(?)をかく クエリ内のパラメータを定義

Slide 50

Slide 50 text

フロントも完成

Slide 51

Slide 51 text

https://quiz-l.herokuapp.com/

Slide 52

Slide 52 text

GraphQL&graphene-django雑感

Slide 53

Slide 53 text

ツールがそろっていて開発はしやすい ● GraphiQLが簡単に使える ● ドキュメントが豊富 ● relayと組み合わせるとさらによさそう(検証できてない ● apollo-clientを使えばクエリもミューテーションも簡単 ● 逆に言えばライブラリありきではある ○ でもWeb開発ってだいたいそんな感じだと思う

Slide 54

Slide 54 text

Pythonのコードでスキーマを書くのに少し違和感 ● スキーマは本来コードと関係ないはず ○ あくまで仕様だから ● スキーマを書いたらそこからコードを出力して欲しい ○ golangのライブラリがその辺いい感じに解決している(余談 https://github.com/99designs/gqlgen

Slide 55

Slide 55 text

DDDとかやりにくそう ● djangoのモデルにがっつり結びついている ○ インフラ層の事情がそのままアプリケーション層に影響する ○ リゾルバで工夫すればうまくいくかも? ● 素のgrapheneを使うといいかもしれない ● 用法用量はよく考えましょう(虹色の解釈

Slide 56

Slide 56 text

とはいえ

Slide 57

Slide 57 text

使ってみて結構便利さを感じたのも事実 ● APIのエンドポイントと仕様を考えないでいい ○ エンドポイントは1つ ○ 仕様はコードにあるし型もつく ● graphiqlがとにかく便利 ● vue-apolloなどapollo関連の技術を使うととても楽

Slide 58

Slide 58 text

多分残り続ける技術なので 個人サービスで素振りをすれば 良いんじゃないかな?

Slide 59

Slide 59 text

おしまい