初めてのGraphQL with Rails ②（Apollo Client編）

## この記事の内容

前回、`GraphQL`の初心者がRailsでGraphQLを使えるようになるまでに調べたことをまとめて書きました。

https://qiita.com/tanutanu/items/58106174392516da5f1d

GraphQLでデータを取得する作業のうち、

- 型の定義
- スキーマの書き方

までは記載できたのですが、肝心の**「どうやってデータを取得してくるか」**が長文になりすぎて書けなかったので、ここに記載します。

参考にしたのはこちらの記事と

https://qiita.com/soutaschool/items/2f65d9bec3753d48bbc0

こちらのチュートリアルなど

https://www.apollographql.com/docs/react/get-started/

実際の実装方法は上記の記事の方が詳しいので、ここでは自分が担当したところでの実装で工夫していた点について主に記載していきます。

## Apollo Clientを扱う
### GraphQLの準備
既存の記事や公式チュートリアルの記載内容が大変優れているので、詳細はそちらに譲ります。ここではシンプルに手順だけ。

```ruby:Gemfile
gem 'graphiql-rails'
```
こちらのgemをインストールして

```sh
$ bundle install
$ rails g graphql:install
```
のコマンドを実行したときに、`routes.rb`に以下の内容が記載されていると思います。

```config/routes.rb
Rails.application.routes.draw do
  post "/graphql", to: "graphql#execute"
  # 後略
end
```

これによって、`/graphql`のURLに`POST`でアクセスすることで`GraphQL`のメソッドが実行されます。

その後の方の定義などは[前回の記事](https://qiita.com/tanutanu/items/58106174392516da5f1d)をご覧ください。

### Apollo Clientの準備

`apollo-client`をインストールし、

```sh
yarn add @apollo/client
```

`appolo-client`を初期化します。

```jsx:App.jsx
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider
} from "@apollo/client";

// 解説します（★１）
const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql',
  cache: new InMemoryCache()
});

// 解説します（★2）
export const App = () => {
    return (
        <ApolloProvider client={client} >
            <Sample />
        </ApolloProvider>
    );
}
```

## apollo-clientの初期化

まずは`ApolloClient()`メソッドを用いて`apollo-client`を初期化します。
以下の2つが必須オプションです。

```js:App.jsx
const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql',
  cache: new InMemoryCache()
});
```
- **uri**...`apollo-client`が`GraphQL`の情報を受け取るところ。`uri`か`link`のどちらかが必須で、両方あった場合はlinkが優先される。
- **cache**...`apollo-client`がクエリの実行結果をローカルに保存するために使用するもの。` @apollo/client`に同梱されている`InMemoryCache`がおすすめ。

詳細なオプションはこちら。

https://www.apollographql.com/docs/react/api/core/ApolloClient/

このサンプルでは`App.jsx`にて初期化をしていますが、初期化の内容を他のファイルに記載して`App.jsx`に読み込むこともできました。

## ApolloProviderをアプリ上方に設置

そして、`ApolloProvider`をアプリの可能な限り上方に設置します。これに先ほど初期化した`ApolloClient`のインスタンスを渡すことで下層のコンポーネントで`apollo-client`が使えるようになります。

```jsx:App.jsx
export const App = () => {
    return (
        <ApolloProvider client={client} >
            <Sample />
        </ ApolloProvider>
    );
}
```

## クエリの実行

クエリを実行するには`useQuery()`メソッドを利用します。先程`App.jsx`内で呼び出した、`Sample.jsx`内で、このように記載します。

```jsx:Sample.jsx
import React from 'react';
import { useQuery, gql } from "@apollo/client";

const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
      email
    }
  }
`;

export const Sample = () => {
    const {loading, error, data} = useQuery(GET_USERS); // 解説します
    
    if (loading) return 'ロード中....';
    if (error) return `Error ${error.message}`;

    return (
        <>
            {data.users.map(user => (
                <div key={user.id}>
                    <h1>{user.name}</h1>
                    <h2>{user.email}</h2>
                </div>
            )}
        </>
    )
};
```

`useQuery`メソッドはデフォルトで **loading**, **error**,**data**の3つのプロパティを持つ`result`オブジェクトを返します。
それを分割代入でそれぞれ`{loading, error, data}`に代入しています。

- **loading**...これが`true`である間、クエリはまだ実行中であり、結果はまだ返されていません。
- **error**...クエリで1つ以上のエラーが発生した場合、このオブジェクトには、`graphQLErrors`の配列または単一の`networkError`が含まれます。
- **result**...`GraphQLクエリ`の実行結果を含むオブジェクトです。

useQueryの詳細な仕様はこちら

https://www.apollographql.com/docs/react/api/react/hooks/#usequery

## 完成！

これで、ユーザーの情報を画面に描画することができたはずです。（既存のアプリは実像がかなり異なるので、抜け漏れがあるかもしれませんが、見つけ次第修正します）

その他、

- nestしたオブジェクトの`GET`
- ID等を利用した単一オブジェクトの`GET`
- mutationを利用した`POST`や`UPDATE`メソッドの実行

はまだできていませんが、徐々に試したいと思います。（試し次第追記します）