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

2020.5.30 12:00

前回作成したスキーマに対してクエリを実行していく。

クエリを流して確認してみる

既にCRUDを行うための処理がHasuraから提供されているので、今回はそれを利用する。

管理者権限でクエリが実行されないように、 Request Headers にある x-hasura-admin-secret のチェックを外しておく。

4-1

投稿する

まず、投稿できるか確認してみる。 投稿に限らず、なにかデータに変更を加えるときは mutation を使う。

GraphiQL
mutation createPost($title: String!, $message: String!, $name: String!, $email: String!, $deleteKey: String!) {
  insert_posts_one(object: {delete_key: $deleteKey, email: $email, message: $message, name: $name, title: $title}) {
    id
    created_at
    message
    name
    title
    email
  }
}
QUERY VARIABLES
{
  "title": "My First Post",
  "message": "Hello world",
  "name": "John",
  "email": "john@example.com",
  "deleteKey": "deletepass"
}

下図のように、三角ボタンをクリックすると右側にレスポンスが表示される。

4-2

続いて、返信も行ってみる。

GraphiQL
mutation replyPost($postId: Int!, $message: String!, $name: String!, $email: String!, $deleteKey: String!) {
  insert_comments_one(object: {post_id: $postId, message: $message, name: $name, email: $email, delete_key: $deleteKey}) {
    id
    post_id
    message
    name
    email
    created_at
  }
}
QUERY VARIABLES
{
  "postId": 1,
  "message": "It sounds great!",
  "name": "Bob",
  "email": "bob@example.com",
  "deleteKey": "deletepazz"
}

4-3

参照する

参照は query で行う。

GraphiQL
query list {
  posts {
    id
    created_at
    message
    name
    title
    email
    comments {
      id
      created_at
      message
      name
      email
    }
  }
}

4-4

正しく権限設定されていれば、 delete_key を取得しようとしてもエラーになる。

4-5

削除する

削除は mutation で行う。

GraphiQL
mutation deletePost($postId: Int!) {
  delete_posts_by_pk(id: $postId) {
    id
  }
}
QUERY VARIABLES
{
  "postId": 1
}

削除はmutationクエリだけでなく、ヘッダーに削除キーを追加する必要がある。 試しに間違った実行しても削除キーが一致しないため null が返ってくる。

4-6

削除キーを正しくすると、下記のようなエラーが返ってくる。

4-7

これは記事に紐づく返信があるため外部キー制約違反が起こり、記事を削除できないためである。
要件が曖昧だったため、削除ポリシーを見直す必要があるだろう。

削除要件の見直し

削除ポリシーについては、

  • 返信は記事ありきであると考え、記事が削除されるのであれば返信も同時に削除する

    1. 記事データを削除するときに返信も削除する
    2. 記事とそれに紐づく返信全てに削除フラグを付ける
  • 返信も一つの独立したコンテンツと考え、記事が削除されても返信は削除しない

    1. 記事にのみ削除フラグを付ける

が考えられるが、今回は1の案で対応してみる。

DBにトリガーを設定する

返信を削除するためには、記事のdeleteが行われる前に 同じ記事IDの返信が全て削除されていれば良い。

PL/pgSQLが使えるため、トリガー用の関数を作成してトリガーに設定する。
下記のSQLをコンソールのRaw SQLに直接貼り付けて実行する。

CREATE FUNCTION delete_related_comments() RETURNS trigger AS $$
    BEGIN
        DELETE FROM comments WHERE post_id = OLD.id;
        RETURN OLD;
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER delete_related_comments BEFORE DELETE ON posts
    FOR EACH ROW EXECUTE PROCEDURE delete_related_comments();

4-8

この状態で再度、削除クエリを実行すると削除が行われる。

4-9

デプロイする

一通り作成できたらデプロイしてWebにAPIを公開してみる。 今回はHerokuにデプロイするので、事前に Heroku のアカウントを取得しておく。

公式からテンプレートが展開されているのでそれを使って環境を作る。

https://heroku.com/deploy?template=https://github.com/hasura/graphql-engine-heroku

LocalhostでHasuraを実行するで編集した docker-compose.yml の内容は、 [Settings] > [Config Vars] へ入力する。

4-10

LocalhostのDBスキーマを移行する

Hasuraへ入力した内容を再度入力するのは大変なので、
Localhostの内容をHerokuに反映させるために、postgresをエクスポートする。

(本来はpostgresに対してきちんとmigration処理を行う必要があるが、今回は少し手抜きをする)

まず、dockerのpostgresのプロセスに対してpg_dumpする。

$ docker ps
(略)
$ docker exec -t <postgresのCONTAINER ID> /usr/bin/pg_dump -U postgres -s -t public.posts -t public.comments > out.sql

次に、out.sql を開いて、 冒頭に記載されている

SET ~~~

のすべての行と、

ALTER TABLE public.comments OWNER TO postgres;
ALTER TABLE public.posts OWNER TO postgres;

を削除する。

これをコピーし、HasuraのコンソールのRaw SQLに直接貼り付けて実行する。

Hasuraの設定を移行する

LocalhostのHasuraメタデータも同様にエクスポートしてHerokuへインポートする。
なお、メタデータはpostgresにテーブルがある前提で記載されているので、必ず先にpostgresへテーブルを作る必要がある。

こちらは簡単で、LocalhostのHasuraにて、歯車アイコンから Hasura Metadata Actions の段落にある [Export metadata]のボタンを押してjsonを保存し、HerokuのHasuraにて、 歯車アイコンから Hasura Metadata Actions の段落にある [Import metadata]のボタンを押して先程のjsonを読み込ませるだけである。

次回

次回はフロントエンドでGraphQLのエンドポイントを呼び出してみる。

graphql

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