Hasuraでこんなときどうするの?
👉 はじめに
Hasura を新規プロジェクトで採用するかを検討するにあたって、
調べたことや"こんな時どうするの?"を備忘録として書いています。
Announcing Hasura GraphQL Engine 2.0! にてv2.0がリリースされましたが、この記事ではv1.3.3を基に記載しています。
👉 What's Hasura
に詳しく紹介していただいているので割愛します 🙏
👉 カスタムロジックをはさみたい
Custom Business Logic | Hasura GraphQL Tutorial
HasuraはDBに対するCRUDをGraphQLを介して提供しますが、時にはビジネスロジックをはさみたくなることがあります。それに対してHasuraは以下の2つの機能を提供し実現します。
-
Actions
(Recommended) Remote Schemas
Actions | Remote Schemas |
---|---|
REST APIをHasuraと統合する場合 | (Hasuraではない)GraphQL EndpointをHasuraと統合する場合 |
Actions
- REST API EndpointをHasuraのGraphQL Schemaとマッピングする機能(Hasura Consoleで設定します)
- REST API EndpointはCloud FunctionsやAWS Lambdaのようなサーバーレス(FaaS)を利用できます
- REST API Endpointにvalidationロジックをはさみつつ、HasuraへのGraphQL Queryを投げたり、外部APIをたたいて結果をmutationでHasura DBに保存したりなど
Remote Schemas
- 既存の自前GraphQLサーバーなどHasura以外のGraphQL Endpoint(以下,Own GraphQL Endpoint)とHasuraのGraphQL Schemaを統合する機能(Schema stitching)
- Own GraphQL EndpointとHasura GraphQLのQuery Nameがかぶらないよう実装する必要があります
- Own GraphQL Endpointにvalidationロジックをはさみつつ、HasuraへのGraphQL Queryを投げたり、外部APIをたたいて結果をmutationでHasura DBに保存したりなど
🤔 雑感
- 新規開発の場合はHasuraの公式ドキュメントの通り、Actionsを利用していくのが良さそうです。
- 一方で、【エンジニアブログ】ダイニーのエンジニアリング3カ条|dinii(ダイニー)公式|noteで紹介されているように、Mutationの多くをRemote Schemasを利用して自前実装していくのは規模が大きくなるアプリケーションでは良い棲み分けだなと思います。
- カスタムロジックが必要となるユースケースが多ければ多いほど、(QueryをHasuraに任せられるというメリットはありますが)DBのCRUDを得意とするHasuraを導入するモチベーションは小さくなっていく(旨味が少ない)ので、このあたりはアプリケーションの要件を見極めた上で判断する必要がありそうです。
👉 ファイルアップロードしたい
ファイルアップロードについてはHasuraというよりGraphQLでの扱いの話になりますが、一考の余地はありそうです。
HERE'S HOW YOU UPLOAD FILES IN GRAPHQL...BOTH EASY AND HARD
にもありますが、GraphQLでファイルアップロードを実現する場合、以下のパターンを検討することが多いと思います。
- Base64 Encode - ファイルをBase64エンコードし文字列として扱う
- Direct Upload - Amazon S3やGoogle Cloud StorageのようなObject Storageにクライアント側からダイレクトアップロードし、結果をGraphQL mutationでDBに保存する
- GraphQL Multipart Request - graphql-multipart-request-specに従ってGraphQL multipart requestでアップロードする
1.Base64 Encode
Hasura利用を前提とすると、
- DBにBase64文字列を格納しない限りはサーバー側でのデコードとObject Storageへのアップロード処理が必要なので、ActionsかRemote Shemasでカスタムロジックを挟む必要がありそうです。
- また、Base64エンコードすることでデータ長が33%増加するので、帯域幅を使うことはデメリットと言えそうです。
2.Direct Upload
Building file upload/downloads for your Hasura app | Hasura GraphQL でも紹介されているように、Amazon S3やCloud StorageにClientから直接アップロードし、そのアップロード結果をGraphQL mutationでDBに保存する方法です。
また、結果のアップロード方法についても以下の方法が考えられます。
- Client(=Browser)側で実装する(上記ブログ方式)
- AWS LambdaやCloud Functions を利用して、Object Storageへのアップロードをトリガーにしてfunctionを起動させる
前者の場合はClient視点では少しChattyな気もしつつ、後者にくらべて失敗時のリカバリーはまだハンドリングしやすいかなと思います。
Hasuraを利用する場合は結果(のテキストデータ)のみを扱うため、ActionsやRemote Schemasを利用しなくてもDBへ保存できる点では良いと思います。
3.GraphQL Multipart Request
結論からいうと、Hasuraでのgraphql-multipart-request-specは2021-07-06現在、サポートしていません。
これは、Remote Schemasを利用して、仮にOwn GraphQL EndpointがMultipart Requestをサポートしていたとしても、前段にたつHasuraがサポートしていないためエラーになります。
Support multipart file uploads through remote schema · Issue #2419 · hasura/graphql-engine
support for graphql multipart request spec · Issue #1326 · hasura/graphql-engine
このあたりは、Issueとしてもあがっているため将来サポートされることを期待しています。
🤔 雑感
- 3がサポートされるのがベストだとは思いつつ、今回のプロジェクトでは扱うファイルサイズも大きく、2を採用する方針で考えています
- テキストファイルのような小さなファイルだと1での実装もありえるかなと思いました。
👉 認証 / 認可したい
Authentication & Authorization | Hasura GraphQL Docs
Hasura自身にはユーザー認証機能が提供されていませんが、Auth0やFirebase AuthenticationのようなIDaaSを利用し、ユーザー認証・アクセスコントロールをする仕組みを提供しています。
認証 / Authentication
Authentication | Hasura GraphQL Docs
Hasuraでユーザー認証をしたい場合,2つのモードが提供されています。
いずれのモードも session variables
と呼んでいる変数(X-Hasura-Role
や X-Hasura-User-Id
) に値をセットし、Hasura Engineに渡すことで、ユーザーの識別や後述のアクセスコントロールをします
Using webhook | Using JWT |
---|---|
Sample Code with Firebase | Sample Code with Firebase |
Using webhook
- HasuraへのすべてのHTTP Request (GraphQL Query)時に、HasuraがwebhookへHTTP Requestし、webhook側にて、ID Tokenの検証および、Hasura上での"session variables" (
X-Hasura-*
) をResponseを返すことによって認証 & 認可を行う -
HASURA_GRAPHQL_AUTH_HOOK
(URL of authorization webhook) を指定することで利用可能(1つのみ指定可能) - 🙆🏻♂ リクエストの都度、ユーザー状態を検知できる
- 🙅♂️ すべてのRequest時でwebhookへのroundtripが発生する
Using JWT
- JWT生成時に custom claims (
x-hasura-*
)をJWTに含めることで、Hasura上でJWTを検証し、認証 & 認可を行う - 🙆🏻♂ webhookの場合に比べてroundtripは発生しない
- 🙅♂️ JWT生成後の動的な状態変更(Roleの変更etc..)を反映するのが困難
認可・アクセスコントロール / Authorization・Access control
Authorization / Access control | Hasura GraphQL Docs
HasuraではRoleベースのアクセスコントロールを提供しています。
具体的には、 session variablesのX-Hasura-Role
や X-Hasura-User-Id
に応じて、
DBの列(columns)単位・行(rows)単位でのアクセスコントロールが可能です。
🤔 雑感
- HasuraやGraphQLから話は少しそれますが、IDaaSの(ID Tokenをセッショントークンとして利用するという)お作法はOAuth2.0やOpenID Connect文脈とのそれとは異なるので少し注意が必要そうです。
🖌 参考
- Using Firebase to add authentication and authorization to a Hasura app
- graphql-engine/community/sample-apps/firebase-jwt at master · hasura/graphql-engine
- Hasura GraphQLとAuth0で認証をする - Qiita
- React + Firebase + Hasuraで体験する快適なGraphQL生活
👉 最後に
以上、Hasuraを新規プロジェクトに採用するかの検討時に考えたことや検討したことをまとめました。
Hasuraを利用して本格的に実装しているわけでもなく、Productionでの運用をしているわけでもないので、よりよい手段や訂正等あればコメントにてご指摘してもらえると嬉しいです。
検討にあたってLocalでHasuraを触っていると、GUI(Hasura Console)での操作が設定ファイルとして吐き出せたり、DBのschema管理ができたりと、とても良い体験でした。
Discussion