Hasura + Auth0

2021年10月10日

Hasuraが本当に便利そう(Hasura + Auth0 + React)

Hasuraが本当に便利そうなので、チュートリアルに挑戦。

今回は、Hasuraを試したら開発工数が大きく削減できそうな予感がしたので、その紹介です。
ソースはチュートリアルのTodoアプリ(React)ですが、まともに動かすまでにハマりまくったので、その注意点を含めて書きたいと思います。

Hasura公式サイト
https://hasura.io/

GraphQL公式サイト
https://graphql.org/

まず、この記事の対象読者ですが、かなり狭い範囲かと思います。

  • GraphQLを概要だけでも知っている。
  • GraphQLとREST API双方のメリット・デメリットに関して、少しは知っている。
  • GraphQLを試したいと思っているが、実装が面倒そうだと感じている。(*特にココ)
  • Hasuraについて、名前ぐらいは聞いたことがある。

ここではGraphQLとは何か?という説明は省きます。
それを書くだけで、記事が10個ぐらい書けそうなので・・・

今回の記事は、Hasuraで開発効率がこれだけ上がるなら、GraphQLを使って何か作ってみたいと思った・・・という内容の記事です。

これまでの流れ

  1. GraphQLについて知る(REST APIとの違いや、メリット・デメリット)
  2. Apollo(GraphQL Client / Server)やPrisma 2(ORM)とか少し触ってみる。
  3. すごく面倒くさい(特にバックエンド側)で、あっという間に興味を失う。
  4. しばらく経ってこの記事を読む。
  5. またGraphQLへの関心が高まり再挑戦するも、バックエンド側の手間が半端ないと挫折しかかる。
  6. Hasuraを知って、試してみる。
  7. Hasuraの開発効率・設計思想に感銘を受ける(←今ココ)

まず、GraphQL懐疑派だった私が、
改めて挑戦しようと思った記事が下記になります。

GraphQLの全体像とWebApp開発のこれから
https://qiita.com/saboyutaka/items/171f7382cdf75b67d076

すごくスッキリとまとめてあるという印象です。
GraphQLを調べていたら出てくる情報ではありますが、
とくに「フロントエンドとサーバーサイドの関心の分離」の項目は腑に落ちたという感じでした。

それでまたGraphQLを触り直すのですが、フロントエンドとバックエンド(サーバーサイド>DBへのつなぎ込みまで含める)をトータルで考えると、REST APIと比較して工数が減るわけではない・・・というのが現時点での印象です。

この時点で試した技術スタックは下記になります。
ちなみにどんな選択肢があるのか、一望できるのが下記のサイトです。

Code using GraphQL
https://graphql.org/code/

バックエンド・サーバーサイド側も、Node.js(JavaScript / TypeScript)を選定。

  • GraphQLクライアントは、Apollo Client
  • GraphQLサーバーは、Apollo Server
  • ORMは、Prisma 2

現時点では最も情報量の多い組み合わせではないでしょうか?

この組み合わせでいいから動くソースをくれ!と言う人は、素直にそれぞれの公式サイトのチュートリアルのソースを落としてきましょう。それが最短コースです。

公式サイトのチュートリアルのソース

GraphQL with a Database Has Never Been Easier with Apollo & Prisma
https://www.prisma.io/apollo#apollo-tabs

Using Apollo with TypeScript
https://www.apollographql.com/docs/react/development-testing/static-typing/

やはり、リゾルバの実装とか結構大変だという感想は変わらなかった・・・というときに、ふと見かけたのが下記の記事。

Hasuraがめちゃくちゃ便利だよという話
https://qiita.com/maaz118/items/9e198ea91ad8fc624491

試した結果、本当にめちゃくちゃ便利です。
言いたいことは全部この記事に書いてあります。

これは実際に試してみないと実感できないのですが、最初は感動ものでした。

もちろんどんなサービスもメリット・デメリットはあります。
Hasuraもそれは同じです。
GraphQL自体がそうであるように、使い所を間違えないようにする必要があります。

能書きはいいから動くソースをくれ!と言う方には、
公式のチュートリアルのソースを・・・と言いたいところですが、
残念ながらそうはいきません。
私の環境(M1 MacBook Pro)では、何かしらでまともに動かないのが多かったです。
動いたソースとその注意点を記載します。

  • macOS Big High Sur 11.6 チップ Apple M1
  • node  v14.17.6
  • npm 7.24.2

チュートリアルをうまく動かす設定

ソースは下記のものを使用する

https://github.com/hasura/learn-graphql/tree/master/tutorials/frontend/react-apollo/app-final

上記のリポジトリには、React(TypeScript用)やNext.js用など各種あるのですが、
エラーでコンパイルできなかったり、起動はするけど一部動作がおかしいなどの現象がありました。
(Vue.js版は起動するけどOnline Usersが表示されるはずの箇所がエラーとか)

ソースからの変更箇所は、下記の該当箇所を自分のプロジェクト用に書き換えてください。

  • src/components/App.js
  • src/components/Auth/auth0-variables.js

実施するチュートリアルについて

コース紹介
https://hasura.io/learn/ja/graphql/hasura/introduction/

からスタートして。。。

ユーザとルールの同期
https://hasura.io/learn/ja/graphql/hasura/authentication/4-user-sync-rule/

ここまで書いてある通りに進めてください。

チュートリアルとの相違点や注意点

  • Hasura CloudではなくHerokuにデプロイする。
    (チュートリアルによってはHasura Cloudへのデプロイ方法が書いてありますが、私はHerokuにデプロイしました)
  • Herokuのコンソールにログインして、デプロイしたアプリケーションのOverviewから、Configure Add-onsをクリックして、Auth0を追加する。
  • Herokuのコンソール Settings>Config Varsから、Auth0プロジェクトの内容に変更する。
    (チュートリアルには、HASURA_GRAPHQL_ADMIN_SECRET, HASURA_GRAPHQL_JWT_SECRETの2つの追加しか言及されてないが念の為)
  • チュートリアル途中の
    todos テーブルの権限のセットアップ
    https://hasura.io/learn/ja/graphql/hasura/authorization/1-todos-table-permissions/
    最後にカラムのプリセットの下で from session variable から X-HASURA-USER-ID へのマッピングから user_id を選択します。
    とさらっと書いてありますが、insertの
    Column presets :
    user_id – from session variable – X-Hasura-User-Id
    のことです。(見落としがち)
  • チュートリアル途中の
    ユーザとルールの同期
    https://hasura.io/learn/ja/graphql/hasura/authentication/4-user-sync-rule/
    記事内にあるinsert-userの
    const admin_secret = “xxxx”;
    const url = “https://learn-hasura-backend.herokuapp.com/v1/graphql”;
    は、自分のHasuraコンソールからの情報に書き換えること。

これらの点を間違いなく設定できたら、
私の環境では無事に実行できました。

最後に念の為、Hasuraのコンソールからダウンロードしたmetadataを添付します。
ここに設定が全部書いてますが、PostgreSQLのURLは各自のものに書き換えてください。

{
  "resource_version": 16,
  "metadata": {
    "version": 3,
    "sources": [
      {
        "name": "default",
        "kind": "postgres",
        "tables": [
          {
            "table": {
              "schema": "public",
              "name": "online_users"
            },
            "object_relationships": [
              {
                "name": "user",
                "using": {
                  "manual_configuration": {
                    "remote_table": {
                      "schema": "public",
                      "name": "users"
                    },
                    "insertion_order": null,
                    "column_mapping": {
                      "id": "id"
                    }
                  }
                }
              }
            ],
            "select_permissions": [
              {
                "role": "user",
                "permission": {
                  "columns": [
                    "id",
                    "last_seen"
                  ],
                  "filter": {}
                }
              }
            ]
          },
          {
            "table": {
              "schema": "public",
              "name": "todos"
            },
            "object_relationships": [
              {
                "name": "user",
                "using": {
                  "foreign_key_constraint_on": "user_id"
                }
              }
            ],
            "insert_permissions": [
              {
                "role": "user",
                "permission": {
                  "check": {
                    "user_id": {
                      "_eq": "X-Hasura-User-Id"
                    }
                  },
                  "set": {
                    "user_id": "x-hasura-User-Id"
                  },
                  "columns": [
                    "is_public",
                    "title"
                  ],
                  "backend_only": false
                }
              }
            ],
            "select_permissions": [
              {
                "role": "user",
                "permission": {
                  "columns": [
                    "is_completed",
                    "is_public",
                    "id",
                    "title",
                    "user_id",
                    "created_at"
                  ],
                  "filter": {
                    "_or": [
                      {
                        "is_public": {
                          "_eq": true
                        }
                      },
                      {
                        "user_id": {
                          "_eq": "X-Hasura-User-Id"
                        }
                      }
                    ]
                  }
                }
              }
            ],
            "update_permissions": [
              {
                "role": "user",
                "permission": {
                  "columns": [
                    "is_completed"
                  ],
                  "filter": {
                    "user_id": {
                      "_eq": "X-Hasura-User-Id"
                    }
                  },
                  "check": null
                }
              }
            ],
            "delete_permissions": [
              {
                "role": "user",
                "permission": {
                  "filter": {
                    "user_id": {
                      "_eq": "X-Hasura-User-Id"
                    }
                  }
                }
              }
            ]
          },
          {
            "table": {
              "schema": "public",
              "name": "users"
            },
            "select_permissions": [
              {
                "role": "user",
                "permission": {
                  "columns": [
                    "id",
                    "name"
                  ],
                  "filter": {}
                }
              }
            ],
            "update_permissions": [
              {
                "role": "user",
                "permission": {
                  "columns": [
                    "last_seen"
                  ],
                  "filter": {
                    "id": {
                      "_eq": "X-Hasura-User-Id"
                    }
                  },
                  "check": null
                }
              }
            ]
          }
        ],
        "configuration": {
          "connection_info": {
            "use_prepared_statements": true,
            "database_url": "postgres://ここは自分のPostgreSQLのURLを記載",
            "isolation_level": "read-committed",
            "pool_settings": {
              "connection_lifetime": 600,
              "retries": 1,
              "idle_timeout": 180,
              "max_connections": 15
            }
          }
        }
      }
    ]
  }
}

今回はここまでになります。
Hasuraで何か作る予定ですがブログで公開するかどうかは未定です。

LINEで送る
Pocket

label

Written by
isaka

バックエンドエンジニア

CONTACT

お問い合わせ、ご依頼などは下記電話番号かメールアドレスまでご連絡ください。
※内容により回答までお時間をいただく場合がございます、予めご了承ください。

tel. 06-6534-9333

10:00-19:00(※土日祝を除く)