Hasura（GraphQL Engine）をかじってみる

# 環境

- Hasura 1.3 
- Hasura 2.0 のことも少し
  - 但し、2021/4/27 時点で、alpha 10 です。

> 2020年12月から、Hasura を使って複数プロジェクトで開発しています。

# GraphQL 基礎

## 日本語

- CRUD の R（Read）が `query` で、それ以外は `mutation` で処理をします。 
- `query` はパラレルに実行することが可能です。
- 常に `POST` を使います。
- レスポンスは常に `200` が返されます。
- エラーが発生した場合は、`errors` フィールドにエラー内容が含まれます。
- JSON でやりとりするため、画像は base64 encode する必要があります（ファイルサイズがおおよそ1.4倍になります）。
  - signedURL 等を使って、クライアントから、直接ファイルストレージにアップロード/ダウンロードするアーキテクチャを検討してもよいかもしれません。

## English

- "R" of CRUD is `query`. The rest ("CUD") is `mutation`.
- `query` can be run in parallel.
- The http verb is always `POST`.
- The response is always `200`.
- Errors are put into the `errors` filed when there are.
- Requests and responses are sent in JSON format. So images should be encoded in base 64.
 
# Hasura の特徴

- テーブル構造に基づいて、GraphQL の CRUD（query と mutation）を自動生成します。
  - Aggregation（集約）、Pagination を含む。
  - Relay に準拠した API も提供（beta）。
  - Hasura で提供されていない処理を行いたい場合は、Remote Schemas や Actions で拡張可能（後述）。
- Postgres をサポート。
  - MySQL もサポートされていますが、2021/4/27 時点ではプレビュー。
- 認可（JWTを使ったロールベース）が組み込みでサポートされています（要件にあえば非常に強力です）。
  - webhook で行う（別サーバにリクエストをフォワードして認可を行う）ことも可能。
- Docker が提供されているため、容易に環境構築が可能。

# [Remote Schemas](https://hasura.io/docs/latest/graphql/core/remote-schemas/index.html) 及び [Actions](https://hasura.io/docs/latest/graphql/core/actions/index.html)

- Hasura が提供する CRUD で対応しきれない処理を、他のサーバにリクエストを GraphQL で投げる仕組みです（GraphQL のエンドポイントは単一）。
- 同じような仕組みの REST版が Actions です（GraphQL リクエストを受けて、他のサーバに REST で投げます）。
- エンドポイントを単一にする必要がなければ、Remote Schemas や Actions を使う必要はありません。単に、異なるエンドポイント（サーバ）にリクエストを投げればいいだけです。
- 未確認ですが、Remote Schemas、Actions を使った場合は、認証認可は独自対応が必要な想定です。 
  - TODO: https://hasura.io/docs/latest/graphql/core/remote-schemas/auth/index.html を読んでまとめる。
  - 2.0 からは、Remote Schemas で hasura の認可が使えるようです（詳細は要確認）。 

# Hasura を使う時の注意点

- Postgres の組み込み enum がサポートされていません（[see more](https://hasura.io/docs/latest/graphql/core/databases/postgres/schema/enums.html#)）。
  - enum 用のテーブルを作って、そこに値を入れることを推奨しています。
  - 現在のプロジェクトでは、例えば prefecture（都道府県）テーブルなど enum 毎にテーブルを作りたくなかったので、フロントエンドにバックエンドで定義している enum をコピーしています。
     - 事故る（フロントエンドとバックエンドの定義がずれる可能性がある）可能性がある仕組みですが、きちんと運用できていれば問題がないのと、コストが低いためそうしています。
     - Remote Schemas で定義した GraphQL のスキーマファイルを使って共有することも可能です。
     - npm module で定義を共有することも可能ですが、今はそこまでやっていません。 
- ORM が提供する database hook が使えません。
- フレームワーク（例： Rails）が提供するモデル/エンティティ層でのバリデーションが使えません。
- トランザクション処理は出来ません。
  - Remote Schemas を使って独自に mutation を書く等で対応は可能です。
- Remote Schemas を使う場合は、Hasura が提供する query/mutation の名前と被らないようにする必要があります。
  - `insert_user_via_remote_schema` にようにしています。 
- ポリモーフィックなど、アプリケーション層でのDBデザインが使えません。
  - Hasura（GraphQL）の強みを活かせないというだけで、そういうデザインをすることは可能です。
- カラム名
  - `camelCase` にした方が、フロントエンドでの取り回しがスムーズです。
  - 実カラム名を `GraphQL field name` という項目で GraphQL 用に変換することも可能なので、`snake_case` であってもこの機能を使えば問題ありません。
     - GUI（Hasura console）では、`DATA` > `[table name]` > `Modify` > 各カラムの `GraphQL field name` に値を設定。
- テーブル名
  - DB のテーブル名がそのまま使われるので、複数形（e.g. `users`）にしておいたほうが、自然なクエリを実行できます。
- Remote Schemas を使う場合は、本番の GraphQL（Apollo Server）の設定で `introspection: true` を設定する必要があります。
  - 本番では、playground を無効にしている前提です（playground が on であれば、introspection を有効にする必要はないようです（staging 環境など））。  

# Hasura 2.0 の変更点

- 認証の仕組みが拡張されて、リクエスト内容もまるごと webhook に含まれるようになっています（1.3 ではヘッダーのみ）。
- Remote Schemas で hasura の認可が使えるようです（詳細は要確認）