React+GraphQLをHeroku+Hasura でセットアップする


今回は以前から気になっていた GraphQL を Heroku + Hasura で構築し、React から Apollo Client で呼び出すまでの流れを備忘録として記事にしたいと思います。
実際に試してみると、Firebase と同じくらいに簡単にサーバーを構築することができました。

Hasura でプロジェクトを作成する

Hasura で新しく GraphQL のサーバーを作成します。

PostgresSQL サーバーを選択しますが、Heroku を使用する場合はアカウントリンクをすることで Heroku 側のプロジェクトを自動的に初期化してくれます。

プロジェクトの作成が完了すると管理画面が表示され、GraphQL のエンドポイントやおなじみの GraphQL の画面を確認することができます。

サンプルのデータを追加する

この状態ではデータベースに何もデータがない状態なので、ダミーデータを入れてみます。
データは何でも良いですが、このリポジトリload_employees.dump から一部データを取ってきました。

Create Table からテーブルの型を決めます。今回は次のようにしました。

テーブルの型を決めたら Insert Row からデータをいくつか入れます。

最終的には次のようになりました。

データの入力が完了すると、トップページから GraphQL のクエリを試すことができます。
クエリ構文を覚えていなくても Explorer から選ぶだけで自動でクエリが生成されるのでかなり簡単ではないでしょうか。

React アプリケーションの作成

上記で用意した GraphQL サーバーを React+Apollo Client で呼び出してみます。
GitHub も公開しているので良かったらクローンして試してみてください。

Client を作成し Provider に与える

React hooks から GraphQL を呼び出せるように、作成した client を Provider で 指定します。

index.tsx
import { ApolloProvider } from "@apollo/client";
import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
  uri: process.env.REACT_APP_SERVER_URL,
  cache: new InMemoryCache(),
});
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root")
);

コンポーネント側から useQuery を使用してクエリを実行します。

App.tsx
import { useQuery, gql } from "@apollo/client";

const GET_EPLOYEES = gql`
  query GetEmployees {
    employees {
      birth_date
      emp_no
      first_name
      hire_date
      last_name
    }
  }
`;

function App() {
  const { data } = useQuery(GET_EPLOYEES);
  return (
    <Container>
      <Pre>{JSON.stringify(data, null, 2)}</Pre>
    </Container>
  );
}

これを表示してみると、次のようになります。
先程 Hasura で登録した内容を表示できていることが分かります。

取得するデータを型安全にする

ここからは TypeScript を使用する人向けです。
先程取得した dataany 型となっています。これを apollo-tooling を使用することでクエリ文から型を生成できるようになります。

まず Apollo Tooling をインストールします。

yarn global add apollo

そして React プロジェクトのルートに apollo.config.js を作成します。
GraphQL の URL もこの中に指定します。

module.exports = {
  client: {
    name: "client",
    includes: ["src/**/*.ts", "src/**/*.tsx"],
    tagName: "gql",
    addTypename: true,
    service: {
      // remote endpoint
      name: "sever",
      url: "https://xxxxxxxxxxxxxxxxx/graphql",
    },
  },
};

そして client:codegen コマンドで型定義ファイルを生成します。

apollo client:codegen --target typescript types

完了すると、 src/types/xxxx.ts に生成されたファイルが保存されます。

export interface GetEmployees_employees {
  __typename: "employees";
  birth_date: any;
  emp_no: number;
  first_name: string;
  hire_date: any;
  last_name: string;
}

export interface GetEmployees {
  /**
   * fetch data from the table: "employees"
   */
  employees: GetEmployees_employees[];
}

useQuery のジェネリクスにこの生成された型を指定すると、data に型が付きます。 🎉

const { data } = useQuery<GetEmployees>(GET_EPLOYEES);

おわりに

DB サーバーの用意から React での使用まで、想像より遥かに簡単に行うことができました。
さらには TypeScript の型付けも自動で行うことができ、かなり DX が向上すると思います。
また、Hasura では データベース内のアクセス権限などの管理はできるようですが、認証などは搭載していないようです。このあたりは Firebase と組み合わせて使用するのが一番簡単かもしれないですね。

追記

JOIN などを行う方法を記事にしました。(https://qiita.com/TakaoNarikawa/items/c599a84c8f587fdcc867)

参考