Hasura GraphQL Engineと戯れる

## Hasuraとは
[Hasura](https://hasura.io/)はPostgreSQLなどのデータソースから自動的に[GraphQL](https://circleci.com/ja/blog/introduction-to-graphql/)サーバーを作成できるツールです。
対象となるデータソースのアドレスやPasswordを設定して起動すればすぐにGraphQLサーバーとして使えます。
SaaSとして利用することもできますが、Core機能の[Hasura GraphQL Engine](https://github.com/hasura/graphql-engine/)はオープンソースで公開されていますので、Dockerで構築することが可能です。
今回はDockerを使用して自前で構築してみます。

## 環境構築
[こちら](https://raw.githubusercontent.com/hasura/graphql-engine/stable/install-manifests/docker-compose/docker-compose.yaml)からdocker-compose.yamlを入手してyamlがあるディレクトリでコンテナを起動します。

```powershell
docker-compose up -d
```
http://localhost:8080 で Hasura Console にアクセスできます。
同じくコンテナでPostgreSQLも起動してきます。

### データベースの接続
上部メニューの「DATA」タブからDBへの接続文字列を設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/7296a15b-da46-d3de-617d-972a174a4a5e.png)

### テーブルの作成
Hasura ConsoleではDB設定、データ編集も行うことができます。
今回は初期状態のDBなのでテーブルを作成していきますが、既存のDBを接続すると自動的にテーブル情報等を読み取ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/b1db2b6d-2ce6-88ac-9ec3-7d39a4afbede.png)


UUID型のidとText型のnameをもつemployeesテーブルを作成します。

### データの挿入と取得
上部メニューの「API」タブからGraphQL を即座に試せるプレイグラウンドツール GraphiQLを使用してAPIを試すことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/dbafb7d5-7f90-537c-8ed5-a6aa78f2b88b.png)

Hasura GraphQL Engineはテーブルの情報からGraphQLの更新系であるmutationを自動作成してくれるので、`insert_employees`をそのまま利用します。

```graphql
mutation {
  insert_employees(objects: {name: "Yosuke Sakaue"}) {
    affected_rows
  }
}
```

参照系のqueryは以下のように記述します

```graphql
query {
  employees {
    id
    name
  }
}
```
結果

```json
{
  "data": {
    "employees": [
      {
        "id": "24c1de75-9578-497a-9fb2-011dc920572c",
        "name": "Yosuke Sakaue"
      }
    ]
  }
}
```

### テーブルのリレーション
idとnameをもつdepartmentsテーブルを新たに作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/82b98322-caf1-8904-79c4-6c568a371d38.png)

employeesテーブルにUUID型のdepartments_idカラムを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/6300436d-5149-2de4-d80b-2abb03ba47eb.png)

そしてForeign Keysを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/192699d2-abc0-931a-facd-52c04791b4b2.png)

テーブルの「Relationships」タブからリレーションを設定します。
foreign keys を参考にしてリレーションのサジェストをしてくれているのでそのまま「Add」します。
リレーションとは、GraphQL のリソースを結合するためのものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/87fb75b9-d1cc-d0b6-ea57-60125bc137f8.png)

### データの挿入と取得②
「API」タブでデータの挿入をします。


departmentsテーブルに組織情報を挿入

```graphql
mutation {
  insert_departments(objects: {name: "software development"}) {
    affected_rows
    returning {
      id
    }
  }
}
```
結果

```json
{
  "data": {
    "insert_departments": {
      "affected_rows": 1,
      "returning": [
        {
          "id": "20b0042c-bc31-4657-8178-d4e7e097b668"
        }
      ]
    }
  }
}
```

返却された`id`をemployeeの社員情報にupdateします。

```graphql
mutation {
  update_employees(where:
    {id:{_eq: "24c1de75-9578-497a-9fb2-011dc920572c"}},
    _set: {departments_id: "20b0042c-bc31-4657-8178-d4e7e097b668"}){
    affected_rows
  }
}
```

GraphQLの強みである一括取得を試してみます

```graphql
query MyQuery {
  employees {
    id
    name
    department {
      id
      name
    }
  }
}
```

結果
一度のリクエストで社員の情報と紐づく組織の情報も一括で取得することができました。

```
{
  "data": {
    "employees": [
      {
        "id": "24c1de75-9578-497a-9fb2-011dc920572c",
        "name": "Yosuke Sakaue",
        "department": {
          "id": "20b0042c-bc31-4657-8178-d4e7e097b668",
          "name": "software development"
        }
      }
    ]
  }
}
```

## まとめ
今回は新規でテーブルを作成していきましたが、既存のRDBを接続するだけでAPIサーバーを作成できるのは非常に便利で可能性を感じました。
単純なCRUDサービスを構築するだけならこれで十分ですし、Hasuraには他にもActions、Remote Schemas、Event Triggers、認証・認可、ページネーション自動作成など様々な機能があるのでそちらもまた記事にしたいと思います。