😈

GraphQLサーバのHasuraを使ってみた

2023/01/31に公開

背景

最近PoCをなるべく早く作る方法を考えています。
極端な話、リリース時には作り直したとしても、素早くPoCできた方が良いのではないかと思っています。

PoCでざくざく作る時にどうしてもAPIを用意するのが手間に感じてしまいます。

そんな時にHasuraを教えてもらいました。
https://hasura.io/

ロゴアイコンがかわいい。

※GraphQL自体触るのが初めてなので、他のGraphQL環境と比べてどうかは分からないです。

Hasuraとは

ざっくり言うと、Postgresをデータベースとして、GraphQLサーバを簡単に建てられるものです。
ほんとに数分で環境作れてしまって驚きました。

PoC開発で辛いことの一つにAPI開発があります。
システムの作り方として、ちゃんと境界を分離して作ることはメンテナビリティを高める方法としてとても有用です。ただし、PoCの様に素早く作りたい時には、CRUDのAPIを量産するだけで時間がかかる。そしてちょっと挙動変えたいだけなのに、フロントからAPIから変更部分多いなとか、色々と思うところがありました。

GraphQLを使うと、いちいちAPIを立てずに、フロントからSQLを叩くような感じで使うことができます。

Hasuraには、Hasura Cloudというホスティングサービスと、自分でデプロイするDockerバージョンがあります。今回はHasura Cloudを使ってみました。

チュートリアルをやってみた

https://hasura.io/learn/graphql/hasura/introduction/

チュートリアルがとても良くできているので、興味のある方は一度試してみると良いと思います。
リアルタイムTodoアプリを作るチュートリアルになっています。
所要時間は30分です。
(が、Hasura以外のWebサービスを使うのでそれらに慣れていないともうちょっとかかります)

https://hasura.io/learn/ja/graphql/hasura/introduction/
日本語で読めます。
ただ、たまにアップデートされていないところがあるので、怪しいと思ったら英語の方を確認してください。でもほとんど日本語ドキュメントで対応できました。

ここではざっくりチュートリアルでやることベースで、HASURAがどんなことができるかを解説していきます。

  1. Hasuraデプロイ
  2. データモデリング
  3. リレーションシップ
  4. データ変換
  5. 認可
  6. 認証
  7. カスタムビジネスロジック

1. Hasuraデプロイ

ドキュメントの通りワンクリックでデプロイできます。
Hasuraが対応するのはGraphQL部分のみで、DBは別で立てて接続します。
しかし、そのDBもちゃんと連携が用意されています。

https://neon.tech/
neonというServerless Postgresサービスです。
デザインがかっちょいいですね。

これもドキュメント通りポチポチすることで、GraphQLとPostgresサーバを無料で立ち上げることができます。

※Hasuraの方でもう一つプロジェクトを作ったところ、DBとの接続が切れてしまいました。どうも、NEON側では無料では1つしか作れないみたいで、それをHasura側から作ろうとした時に接続が外れてしまったみたいです。既存の方が接続外れるのは不思議なので、もしかしたら勘違いかもですが念の為。

2. データモデリング

ここでは、Hasuraのウェブコンソール上からテーブルを作成します。

こんな画面で入力できるので、簡単にテーブルが作成できます。

mutation(データ登録)

mutation {
  insert_users(objects:[{id: "1", name:"Praveen"}]) {
    affected_rows
  }
}

検索クエリ

query {
  users {
    id
    name
    created_at
  }
}

サブスクリプション
データを監視して、変更されたらリアルタイムにレスポンスを返すもの

subscription {
  users {
    id
    name
    created_at
  }
}

3. リレーションシップ

GraphQLでいわゆるテーブルJOIN的なことをするものです。

  • オブジェクトリレーションシップ(1対1)
  • 配列リレーションシップ(1対多)

オブジェクトリレーションシップ

query {
  todos {
    id
    title
    user {
      id
      name
    }
  }
}

配列リレーションシップ

query {
  users {
    id
    name
    todos {
      id
      title
    }
  }
}

この様に、ネストして書くことで、関連する情報を取得できます。

これを実現するためには、データベースの外部キー制約とHasuraのリレーションシップ作成が必要になります。

データベースで外部キー制約をつけると、Hasura側でリレーションシップを追加できる様になるので、追加します。リレーションシップ設定をするためには、外部キー制約は必須となります。

4. データ変換

データ変換というと若干違和感あるのですが、英語では Data Transformations となっていました。
ここでは、過去30秒にログインしてオンラインになっているユーザーをアプリが検索する機能を作ります。

この様なビューを作ります。これはデータベースの機能です。

CREATE OR REPLACE VIEW "public"."online_users" AS
 SELECT users.id,
    users.last_seen
   FROM users
  WHERE (users.last_seen >= (now() - '00:00:30'::interval));

このビューに対してサブスクリプションgraphqlを実行します。

subscription {
  online_users {
    id
    last_seen
  }
}

すると、30秒以内にlast_seen(ログインした時に現在時刻で更新想定)が更新されたデータのみ表示され、30秒を超えると表示されなくなります。

5. 認可

権限です。
誰がどのデータにアクセスできるのか、変更できるのかをロールベースでアクセス制御できます。

今回のtodoアプリでは、ユーザーが自分のtodoを管理できる様にし、さらに、is_publicなものは誰でも見れる様にします。

ここでもまた、画面上からRoleを作り、そのRoleに対して、パーミッションを設定していきます。
とにかく、全てのことがwebコンソール上で操作できます。

これをテーブルごとに設定します。

6. 認証

認証にはAuth0を使います。

正直、この認証部分はかなり設定するものが多いです。
認証やJWT周りの設定が初めてだと、そもそも何を設定しているのかよく分からないので、頭から丁寧に設定していかないと何が悪くて動かないのか分からなくなるので注意してください。

自分が立てたAuth0のドメインを入力しなければいけないのに、ドキュメントのそのまま入力して動かないとかやらかしました。

https://hasura.io/learn/ja/graphql/hasura/authentication/4-user-sync-rule/

ここで、Rulesでユーザーを同期するというのがあるのですが、これがなかなか感動です。
Auth0にユーザーを追加すると、自動でHasura側のデータベースにあるuserテーブルにもユーザーを追加してくれる機能です。

こんなルールを設定することで、実現しています。

function (user, context, callback) {
  const userId = user.user_id;
  const nickname = user.nickname;

  const admin_secret = "xxxx";
  const url = "https://ready-panda-91.hasura.app/v1/graphql";
  const query = `mutation($userId: String!, $nickname: String) {
    insert_users(objects: [{
      id: $userId, name: $nickname, last_seen: "now()"
    }], on_conflict: {constraint: users_pkey, update_columns: [last_seen, name]}
    ) {
      affected_rows
    }
  }`;

  const variables = { "userId": userId, "nickname": nickname };

  request.post({
      url: url,
      headers: {'content-type' : 'application/json', 'x-hasura-admin-secret': admin_secret},
      body: JSON.stringify({
        query: query,
        variables: variables
      })
  }, function(error, response, body){
       console.log(body);
       callback(null, user, context);
  });
}

7. カスタムビジネスロジック

カスタムビジネスロジックはGraphQL APIにビジネスロジックを追加する方法です。

  • アクション
  • リモートスキーマ
  • イベントトリガー

の3種類があります。

アクション

GraphQLをクエリかミューテーションで定義して、その裏でREST APIを動かすことができます。
裏で動かすREST APIは何で書いても良いですが、このチュートリアルではGlitchを使ってNode.jsで書いています。
https://glitch.com/
Glitchはfatlyがやっているサービスで、ウェブ上でコードをサクッと書いてAPIを立ち上げることができるサービスです。

リモートスキーマ

GraphQLのカスタムリゾルバーを書いて、それをリモートスキーマとして登録する方法です。
ビジネスロジックにGraphQLを使う場合は、リモートスキーマ。REST APIを使う場合はアクションという使い分けになります。

このチュートリアルでは、ApolloServerでGraphQLサーバーを書いて、Glitchにデプロイ。それをHasuraのリモートスキーマで設定して呼び出す形になります。

イベントトリガー

最後のイベントトリガーはとてもシンプルです。
チュートリアルではユーザー追加時にメール送信するためにSendGridを使っていて、この辺の設定がややこしいですが、イベントトリガー自体はイベント発生時にWeb hookを叩くだけなので簡単です。

テーブルに行が追加、更新、削除されたことをトリガーとして呼び出すことができます。

まとめ

一通りチュートリアルを試しただけですが、本当にちょっとしたものやPoCであればこれで十分使えそうです。今回は全てWebコンソールからの呼び出しだったので、呼び出し側のクライアントがどんな感じで書けるかも試してみたいと思います。

また、neon、Glitchなどの新しい開発環境に触れられたのも良かったです。

公式のチュートリアルが分かりやすかったので、気になった方はぜひ試してみてください!

レスキューナウテックブログ

Discussion