Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DjangoではじめるGraphQLとフロントエンド開発の協業

 DjangoではじめるGraphQLとフロントエンド開発の協業

DjangoCongress JP 2019発表資料

Masaya Nasu

May 18, 2019
Tweet

More Decks by Masaya Nasu

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

  3. なんでGraphQL?

    View full-size slide

  4. 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/

    View full-size slide

  5. 2018年11月 GraphQL Foundation設立

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. そこでGraphene-Django

    View full-size slide

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

    View full-size slide

  11. GraphQLの基礎

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  14. 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を定義するスキーマ
    型の定義
    クエリの定義

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  19. graphene-djangoの簡単な紹介

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  23. サンプル
    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

    View full-size slide

  24. 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が使える

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. クイズアプリの実装

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  33. リゾルバの作成
    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を使用して書ける

    View full-size slide

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

    View full-size slide

  35. 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の名前になる

    View full-size slide

  36. 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フィールドに定義した変数が
    引数として渡される

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  40. 次はフロント

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  44. 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のクエリ(?)をかく
    クエリ内のパラメータを定義

    View full-size slide

  45. フロントも完成

    View full-size slide

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

    View full-size slide

  47. GraphQL&graphene-django雑感

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  51. とはいえ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  54. おしまい

    View full-size slide