APIサーバが不要！Hasuraを導入してみた結果と本番運用について

# はじめに
今回商用プロダクトに、[Hasura](https://hasura.io/ "Hasura") という **GraphQL APIサーバを自動生成** してくれるツールを活用しました。
初期フェーズのプロダクト開発で、開発コスト削減にすごく貢献してくれたツールなので大変気に入ってます。

とはいえ、使い方などで多少ハマったり、難しさもあったので実際に使ってみてどうだったのかを中心に書いていけたらと思います。

全体のインフラについてはこちらにまとめています。

https://qiita.com/yoshinori_hisakawa/items/23dad9d4c65d13c1b785

# そもそもHasuraを使うことが適しているのか？
問答無用で使わず、まずは本当にHasuraを使う必要があるのか？は、検討する余地があると思います。
実際に私が使うに至る理由がプロダクト要件と、組織全体の開発スピードでした。

### プロダクト要件の話
:::note info
**プロダクト要求を満たすために、高度な条件Filterをデータベースに求められるか？**
:::
が今回は、大きな節目でした。本当に重要な要素でした・・・

初期はFirebaseを利用しデータベースを構築していたんですが、
後に、プロダクト要求としてFilter機能を豊富につけたく、データ量も膨大になることがわかりました。

Firebaseだと実際に使っていく中で、Filterはあるものの歯痒いところに手が届かなかったり、
データ量が多いと、アプリケーション上でFilterしてしまうという代案なども破綻するなと思い、途中からRDBに乗り換えることにしました。

### 組織全体の開発スピード
組織でプロダクトを作る上で一番時間を割く必要があるのが、コミュニケーションコストかなと思います。
APIのインタフェースを一旦決めても、フロント・バックエンドの都合で途中から変更を加えたくなったりはあるあるかと思います。
また、少数精鋭でやるとどうしてもリソースが足りなく、雑に作ってバグを起こすくらいなら作りたくないくらいのテンションでした。

そういったのもあり、Firebaseって最高だなと・・・

RDBでもFirebaseのように、APIサーバを作ることなく、データベースの情報をCRUDすることができるツールが2つありました。
それが、[Hasura](https://hasura.io/ "Hasura")と[Supabase](https://supabase.com/ "Supabase") でした。


# Hasuraが出来ること

Hasuraを使うに至る理由をここまでで書いたので、次にHasuraってこんなこと出来ますよ！を書いていきます。

HasuraのDocumentのスクリーンショットですが、ざっと見るだけでも全体的に何ができるかイメージがつくかと思います。
![スクリーンショット 2022-07-15 10.00.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/3f2f85e7-a791-e698-384c-aefbdb99bfc9.png)

今回は上記の中でも、今回メインで活用したのは以下の5点かなーと思います！

## 1. Event Triggers

RDBの特定のテーブルのフィールドがCRUDされたことをトリガーに、lambdaなどのAPIエンドポイントを実行することができる機能です。
HeaderにAuthorizationを利用することも出来るので安全に利用できました。

強いていうならば、リクエストがPOSTで送られることに少しハマりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/98f3987b-11a1-0ce9-0ad7-55901640e937.png)

## 2. Authorization

Hasura側での、認証機能です。

今回、ユーザーのログインは、Firebase Autheticationを利用していたので、
ログイン済みのユーザーかの判定をする必要がありました。また、そのユーザーはどのワークスペースに所属しているのか？もです。

ログイン判定に関しては、JWTトークンを利用し、Hasura側で検証させています。
所属してるワースペースに関しては、firebaseのcustomClaimに、追記するようにしました。
ここは、ドキュメントにあることと同じです。

![スクリーンショット 2022-07-15 10.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/d22b8503-d333-4610-7b37-c07ca475ff6c.png)

## 3. Access Contorol

ロールベースアクセスコントロール機能です。
管理者ユーザーや、編集者ユーザーなど、ユーザーごとに、CRUD自体の制限や、フィールドの閲覧範囲までかなり自由に設定できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/5aff8419-f34d-bdc9-3562-71dbdbe19439.png)


## 4. Migrations basic
Hasura独自のマイグレーション管理です。
本番環境と、開発環境など環境を分けておこなってる場合などにすごく便利でした。

以下のCLIコマンドを利用し、CLI経由でHasura Consoleを開き、
Hasura Consoleからテーブル生成などをすると、マイグレーション用のファイルが自動で生成されます。
これをGit管理するだけで良かったのですごく便利でした。
```
hasura console --envfile env/.dev.env
```

ただ注意点として、Hasura Cloudをそのままインターネット経由で利用すると、マイグレーションファイルなどが落とされないので、CLI経由でコンソールを開くように徹底する必要があります。
他のメンバーのアカウントをHasura Cloudに登録しなければCLI経由で開くしかないので、Cloud側のアカウント発行は限定した方が良いと思います。

また、マイグレーション管理する場合は、環境差異があるものに関しては、Hasuraのカスタム環境変数を利用することをお勧めします。
↓なイメージ
![スクリーンショット 2022-07-15 11.15.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/3b9f0bf1-7d07-8d42-1a38-22ad7d952247.png)

こうすることで、開発環境と、本番環境で呼び出すAPIのドメインが違くても、環境変数に切り出すことが出来るので、
マイグレーション管理が非常にしやすくなります。

## 5. Deploy Using XXX
Hasuraのイメージファイルが配布されているので、Dockerを利用しECS Fargateなどに構築することができます。
HasuraはDBに直接接続する形を取りますし、DBはprivate subnetに配置することが多く、同一VPC内にHasuraを配置したかったため、ECS上にHasuraを構築して運用しました。

Hasura cloudでVPCを利用するには、エンタープライズプランなど、費用などもがっつり変わってきそうでした。


# 実際に構築し、運用する上での覚書 （簡易ハンズオン！）

開発環境と本番環境の2つの環境が存在する場合での初期準備と運用方法について

## 初期設定

- Hasura Cloudの設定
```
Hasura cloudのコンソールにログインし、利用したDBのエンドポイントを入力するくらいで終わります。
```

- CLIのインストール
```
https://hasura.io/docs/latest/graphql/core/hasura-cli/install-hasura-cli/
```

- Hasuraのエンドポイントを指定して、初期化
```
hasura init --endpoint https://xxx.hasura.app
```

- 本番環境と開発環境の設定（env/.xxx.envファイルを作成）
```
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻ ls -la  env/                                           
-rw-r--r--  1 hisakawa  staff  747  5 11 14:32 .dev.env
-rw-r--r--  1 hisakawa  staff  733  5 19 13:51 .prod.env
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻
```

- 環境ごとに、環境変数を指定する
```
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻ cat env/.dev.env
HASURA_GRAPHQL_JWT_SECRET=xxx
HASURA_GRAPHQL_ENDPOINT=https://xxx.hasura.app
HASURA_GRAPHQL_ADMIN_SECRET=xxxxx
API_ADMIN_BASE_URL=https://xxx
HASURA_GRAPHQL_CORS_DOMAIN=*
DATABASE_URL=postgresql://xxx:xxx@xxx:5432/xxx
AUTHORIZATION=Bearer xxxx
FIREBASE_FUNCTION_BASE_URL=https://xxxxx
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻
```

- config.yamlからendpoinを削除
```
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻ cat config.yaml
version: 3
metadata_directory: metadata
actions:
  kind: synchronous
  handler_webhook_baseurl: http://localhost:3000
❰hisakawa❙~/Documents/work/migrate(git:master)❱✔≻
```

- これで、CLI経由でコンソールが開けるかと思います
```
hasura console --envfile env/.dev.env
```

- 本番環境用のenvファイルも作成する

## 開発環境の変更を本番環境に反映させる
- ClI経由で開発環境のHasuraコンソールを開き、変更を加える
```
hasura console --envfile env/.dev.env
```

- 変更の確認（migrations、metadata）
```
// マイグレーションステータスの確認
hasura migrate status --envfile env/.dev.env

// migrationsが複数ある場合は、squshしてみやすくもできます。
hasura migrate squash --name "{コメント書いてね！}" --from {squashしたい開始versionを指定} --envfile env/.dev.env

// metadataはステータスなどはなく、変更差分がファイルに出力されています。

```

- 変更の反映（migrations、metadata）
```
// マイグレーションの反映
hasura metadata apply --envfile env/.prod.env

// メタデータの反映
hasura metadata apply --envfile env/.prod.env

// メタデータのリロード
hasura metadata reload --envfile env/.prod.env
```

# 最後に
フロントの開発者が、GraphQLに抵抗がなければすごく良いツールだなと思いました。
ただ、ビジネスロジックがフロントに染み出してしまうのと、回避するためにHasura Actionsを使い倒すのも開発スピードという観点では微妙だな・・・という印象でした。

Read系のみHasuraが生成した自動生成APIを利用し、書き込みのみ、Hasuraを使うか別でAPIサーバを立ててしまうのもありかなと思います。
今回のプロダクト要求と、開発スピードという観点では、Hasuraを利用して非常に良かったと思います。