GraphQLを使ってシンプルな電子掲示板を作ってみる(5)

2020.6.6 12:00

前回と連携するクライアント側を作っていく。

サンプルコードのダウンロード

ベースとなる部分をVue.jsで作成してあるため、それにGraphQLを組み込んでみる。

https://github.com/tkzwhr/simple-bbs/archive/tutorial.zip

GraphQLクライアントライブラリの導入

実は、ライブラリを使わなくとも、GraphQLのエンドポイントに決まったフォーマットで POSTすればそれだけで使えるのだが、拡張性や可読性を考えるとライブラリ任せにできる部分は 任せてしまったほうが効率がいい。

今のところ、高機能なライブラリではApollo一強状態なので、Apolloを導入する。

公式のインストールガイド

  • Apollo client full configuration
  • Install the plugin into Vue
  • Apollo provider

を順番にやっていけば良い。

但し、

const httpLink = createHttpLink({
  // You should use an absolute URL here
  uri: 'http://localhost:3020/graphql',
})

の部分だけは、自分でHerokuに用意したエンドポイントのURLに 書き換える必要があるので、忘れずに行う。

投稿フォームから投稿してみる

GraphQLの定義

GraphQLを定義するには graphql-tag を使う。 本文はタグ付けされたテンプレートリテラルの形で定義する。

src/views/Posts.vue
    ...
    import {PostFormData, PostModel} from '@/types'
    import {RawLocation} from 'vue-router'
    import Paginator from '@/components/Paginator.vue'
+   import gql from 'graphql-tag'

+   const ADD_POST = (name?: string) => gql`
+     mutation addPost($title: String!, $message: String!, ${name ? '$name: String!, ' : ''}$email: String, $deleteKey: String!) {
+       insert_posts_one(object: {title: $title, message: $message, email: $email, ${name ? 'name: $name, ' : ''}delete_key: $deleteKey}) {
+         id
+         message
+         name
+         title
+         email
+         created_at
+         comments {
+           id
+           message
+           name
+           email
+           created_at
+         }
+       }
+     }
+   `

    ...

defaultが設定されているnonnullなcolumnに対してnullを送るとサーバエラーになってしまうため、 nameについてはmutationに含めるかどうかを選べるように無名関数の形で定義している。

リクエスト処理

実際にGraphQLサーバにリクエストするには、 thisコンテキストに$apolloが定義されているので、その中にあるmutateを使う。

オプションとして下記を指定する。

key value
mutation タグ付けされたテンプレートリテラル(前項で定義したもの)
variables 変数の値が定義されたオブジェクト

Promiseが返却されるので、リクエスト完了後の処理をthenに書くことができる。

Hasuraの場合、insert_<tablename>_oneの処理のレスポンスは

{
  "data": {
    "insert_<tablename>_one": {
      ...response
    }
  }
}

となっている。

src/views/Posts.vue
      ...
      createPost(value: PostFormData) {
-       // TODO: graphql mutation
-       console.log(value)
-       alert("Create a post")
+       this.$apollo.mutate({
+         mutation: ADD_POST(value.name),
+         variables: value
+       })
+       .then(({data: { insert_posts_one: post } }) => {
+         // 先頭に今回更新したデータを追加
+         this.posts.unshift(post)
+         // フォームデータをクリア
+         const postForm = this.$refs.postForm as PostForm
+         postForm.reset()
+       })
      }
      ...

フォームの値を消す

リクエストが成功したらフォームからデータを消しておく。

src/components/PostForm.vue
      ...
      private errors: Errors = { title: false, message: false, deleteKey: false };

+     reset() {
+       this.title = ''
+       this.message = ''
+       this.name = ''
+       this.email = ''
+       this.deleteKey = ''
+     }
      validate() {
     ...

デモ

フォームに入力して投稿すると画面に反映される。

5-1

次回

次回は一覧取得を行う。

graphql

Copyright 2020 tkzwhr's tech notes. All Rights Reserved. Built with Gatsby.