Hasura調査
Hasuraはフルマネージド / セルフホスティング(OSS)が選べる。
日本語記事で機能比較をしているものが見つからないので調査してみる。
Hasuraとは
- Haskellで作られている。Haskell + 阿修羅 = Hasuraらしい。(阿修羅は魔神や鬼の側面があるのでアイコンには角が生えてる)
- データベースからGraphQLによるシンプルなCRUDを自動生成するサービス
- CRUDに加えていくつかの機能が存在
- 認証 - HasuraのGraphQL APIへのリスエストを認証済みかどうか判定できる
- アクセス制約 - リソース毎の参照・更新条件
- キャッシュ - クエリ(参照)オペレーションコードをハッシュ化してキャッシュ (persisted queryの仕組みに近い)
- 外部APIとの連携 - バリデーションや更新ロジックを持たせたい場合はリクエストを別APIに流すことができる
- remote schema - 別に建てたGraphQL API(以下、自前GraphQL)からintrospectionでスキーマを取得してHasuraに連携、クライアントからのリクエストはHasuraを経由して自前GraphQLに委譲
- actions - 別に建てたREST API(以下、自前REST)にHasuraへのリクエストを委譲できる
- GlitchなどのFaaSと連携すればHasuraからコードが書ける
- イベント(webhook)、スケジュール、クーロンなどの機能もある
- クエリ(参照)はHasura / ミューテーション(更新)は自前APIというアーキテクチャが選択でき、コードを減らせる・立ち上がりが早くなるためスタートアップとの親和性が高い (CQS)
- 外部APIとの連携方法についてはHasura公式ブログのNestJS and Hasuraで説明されている (NestJSは癖(DI & moduleによる依存解決の規約)があるため他WAFを利用する場合は読みにくいかも)
製品の種類
Hasuraは製品として下記3つを提供している。
-
Hasura CE (community edition)
- セルフホスティング型のOSS
-
Hasura Cloud
- フルマネージド型のPaas
-
Hasura EE (enterprise edition)
- セルフホスティング(オンプレミス含む)型にCloudの機能を付与したプラン?
- シングルテナントのフルマネージド型 or サポート付きのセルフホスティングを選択できると解釈したけど詳しく見ていない
- セキュリティ、パフォーマンス、サポート付
- セルフホスティング(オンプレミス含む)型にCloudの機能を付与したプラン?
価格
feature highlightsを比較すれば差分の概要は掴めそう
Cloud
セルフホスティング
CloudとCE版セルフホスティング(以下CE)の比較
Cloudは課金コンテンツのため「CloudにはあるけどCEにはない」機能を見ていく
- Cloudの未課金
- CloudはFreeでもPosgreSQL以外を選択できる
- リソースのロールベースによるアクセス制限は全ての製品で可能
- Cloudの課金 - Professional - $1.5/h (active) - 最大 1.5x24x31=$1,116(*140=¥156,000) + 通信料 / 月
- クエリキャッシュ
- リードレプリカによるスケールアウト
- データの監視・統合 - e.g. Hasura上でデータ変更を検知して自前APIなどにwebhookしたり、複数のデータソース間で同期できたり
- 前述のロールベースに加えて、ホワイトリストによるリソースのアクセス制限
- データベースの上限開放 (Freeは2)
- 通信量制限開放 - $0.13/GB
- APIリクエスト量制限が6MBに緩和 (Freeは3MB、エンプラで上限解放)
- Cloudの課金 - Enterprise - custom price
- APIリクエスト量の上限解放 - 6MBは割と早く到達しそう
- VPCに組み込める
- キャッシュとリードレプリカによるスケールアウトが上限解放
- SSOなどの認証を組み合わせることができる
- サポート付き - (professionalはないのか..) 企業で利用する場合はEnterpriseになりそう
priceから読み取れるのは以上
Hasura Cloudを試す
せっかくなので試したログも残す
Hasura公式 GraphQL Backendコースの日本語版
目次
- Hasura Cloudにサインアップ
- サインアップ後、プロジェクトが作成されているので「Launch Console」を選択
- 3つのタイプから管理画面のタイプを選択する
- データベースを作成
- usersテーブル作成
- GraphiQLからusersリソースのミューテーション、クエリを叩く
- todosテーブル作成
- GraphiQLからtodosリソースのミューテーション、クエリを叩く
- 過去30秒以内にログインしたユーザを検索する (
online_users
View作成) -
online_users
とusers
のリレーションシップを作成 - todosテーブルに権限を追加
- usersテーブルに権限を追加
- online_users Viewに権限を追加
- GraphiQLでヘッダーを設定してクエリを叩いてみる
1. Hasura Cloudにサインアップ
2. サインアップ後、プロジェクトが作成されているので「Launch Console」を選択
3. 3つのタイプから管理画面のタイプを選択する
ロジックを持つことができる GraphQL Backend
を選択
4. データベースを作成
BaaSのNeonと連携できるため、Neonを選択 (サインアップはHasuraアカウントでSSOできる)
5. usersテーブル作成
操作はHasura管理画面(コンソール)から行える
6. GraphiQLからusersリソースのミューテーション、クエリを叩く
テーブルを作成した時点でGraphQLのCRUD操作が行えるため、ミューテーションとクエリを叩いてみる
-
ミューテーション
-
クエリ
7. todosテーブル作成
なお、外部キー制約を設定するとリレーションシップを作成してくれる。
todos.user_id を users.id の外部キーとして登録して、cascade(親リソースの削除・更新を小リソースにも反映)にしておく。
リレーションシップタブに移動すると前述の外部キー制約がリレーションシップとして提案されているので、nameを user
に変更して登録する。
外部キー制約の登録と別インターフェースになっているのは、このようにフィールドとしてアクセスする時の名前などをカスタマイズできるようにする目的だと想定できる。
8. GraphiQLからtodosリソースのミューテーション、クエリを叩く
-
ミューテーション
-
クエリ
-
リレーションシップクエリ
online_users
View作成)
9. 過去30秒以内にログインしたユーザを検索する (ロジックをもたせる方法として、Viewを利用する。
Data > SQLから下記の online_users
Viewを追加する。
VIewを追加すると、このviewに対してもCRUD操作が可能になる。
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));
usersテーブルのレコードを編集して last_soon
を now()
に更新する。
下記のように online_users
をクエリ参照すると更新したユーザのみが返ってくる。
(更新から30秒以内に確認する)
online_users
と users
のリレーションシップを作成
10. 先程追加した online_users
ビューに users
のリレーションシップを追加することで online_users
には存在しない users
リソースのフィールドを参照できる。
先程の手順でレコードの users.last_soon
を編集して下記のクエリを叩くと online_users.user
が参照できていることが分かる
query {
online_users {
id
last_seen
user {
id
name
}
}
}
11. todosテーブルに権限を追加
長いので公式ドキュメントに譲る
12. usersテーブルに権限を追加
長いので公式ドキュメントに譲る
13. online_users Viewに権限を追加
長いので公式ドキュメントに譲る
14. GraphiQLでヘッダーを設定してクエリを叩いてみる
todosを取得するクエリを叩いて制限が掛かっているか確認する。
ヘッダー
x-hasura-role - user
x-hasura-user-id - 1
クエリ
query {
todos {
id
title
is_public
is_completed
user_id
}
}
ヘッダーに指定したユーザのtodoのみが取得されていることが分かる。
x-hasura-user-id
ヘッダーの値を変えればレスポンスも変わる
後日、NestJSのGraphQLエンドポイントからremote schemaを利用してHasura連携する方法を試したら追記する予定
下記をやりたい
- Hasuraでリソース追加
- NestJSでリソース追加
- Hasuraから2のremote schemaを取得
- Hasuraでschema.graphqlを出力 (1,2の複合リソース)
- クライアントでGraphQL Code Generatorを利用して4を読み込む、レスポンス型とhooks生成
公式チュートリアル
カスタムビジネスロジック
Hasura x persisted queryについて
Hasuraとしてはpersisted queryの対応はしない方針らしい
- キャッシュ機構でpersisted queryのmanifestに相当するバックエンドロジックは持っている
- 現状だとApollo Clientに依存することになる (apollo clientはクエリのsha256ハッシュを作ってリクエスト時にパラメータ送信するpersisted query用のapiを持っている)
- manifestを生成するライブラリ(npm)もメンテされているものは現状なさそう (the guild謹製のプラグインは詳しく探していない)
- Hasura x persisted queryを行いたい場合は、自前でmanifestを作ってredisなどで保持・保持したハッシュとリクエストハッシュを検証するロジックの実装が必要
- Hasuraのキャッシュ機構とバッティングしそうなため運用も気を付ける必要がありそう
- (hasuraインスタンスも含めたblue/greenデプロイ機構を作るなど?)
Hasura上でカスタムロジックを実現する方法
- remote schema - 外部APIにロジックを委譲する手段 (hasura上ではない)
- actions - faasと連携すればコンソール上で編集可能 (半分hasura上といえる)
- sql view - sqlに依存するがsqlで実現できることは可能 (利用はリレーションシップ位に留めたい気持ち)
- computed field - posgresqlの関数を利用 (これはコードで表現したい気持ち)
①認証 + ②ロールベースアクセス制御(権限) + ③CRUDで表現できるものはHasuraを利用して、これで表現できないものは外部APIに委譲するのが妥当そうに思える。(詳しくない現状においては)
コードが存在しないことはレビューやメンテナンスのコストを減らしてくれるので初速は確実に早くなりそう、一方で共通モジュールやgeneratorを利用することで①〜③はある程度自動化できてしまえそうな気もしている。
nest.js x prismaのgenerator plugin
上記以外にHasuraのメリット・デメリットを思いついたら追記していく。
pros
- リレーションシップでネストされたリソースを取得する際に、HasuraはN+1を解決してくれるらしいので自前でdataloaderの設定をする必要もなくなる。(フレームワークとdataloaderライブラリにもよるが、自分が利用していたgrapheneでは都度リレーションシップごとに設定が必要だったので、それなりに手間な印象)
cons
- a
Hasuraを使う予定がなくなったため一旦クローズする