コード譜投稿アプリを作る #4（apollo clientを使ってnextからrailsにリクエストする）

[←前回の記事](https://qiita.com/t_sekky/items/70fca252f9fbe4b42d79)

# 今回やること
前回railsとGraphQLを使ってバックエンドの実装を進めたので今回はそれをフロントで表示するのが目標です。
apollo使います
何かっていうとフロントでgraphqlを使うためのライブラリです。

## apollo clientインストール
フロント側で以下を実行
```
yarn add @apollo/client graphql
```

## apolloセットアップ
`/src/pages/_App.tsx`に以下を追記

``` tsx:/src/pages/_App.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
import { ChakraProvider } from '@chakra-ui/react'
+ import {
+  ApolloClient,
+  InMemoryCache,
+  ApolloProvider,
+  createHttpLink
+ } from "@apollo/client";
+
+ const link = createHttpLink({
+   uri: "http://localhost:3000/graphql",
+   credentials: "include",
+ });
+ 
+ const client = new ApolloClient({
+   cache: new InMemoryCache(),
+   link: link,
+ });

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page)

  return (
+   <ApolloProvider client={client} >
      <ChakraProvider>
        {getLayout(<Component {...pageProps} />)}
      </ChakraProvider>
+   </ApolloProvider>
  )
}
```

これで全てのページでapollo clientが使用できるようになりました！

## 実装
とりあえずトップページに前回作った`Scores`を一覧で表示しようと思います
ISRとか一旦抜きに普通に表示します

```
import { Box } from '@chakra-ui/react'
import type { ReactElement } from 'react'
import { Layout } from '../components/common/Layout'
import type { NextPageWithLayout } from './_app'
import { useQuery, gql } from "@apollo/client";

const GET_SCORES = gql`
  query GetScores {
    scores {
      id
      title
    }
  }
`;

type Score = {
  id: Number
  title: String
}

const Page: NextPageWithLayout = () => {
  const { data, loading, error } = useQuery(GET_SCORES)
  if (loading) return <Box>ロード中...</Box>;
  if (error) return <Box>{error.message}</Box>;
  return (
    <Box>
      <ul>
        {data.scores.map((score: Score) => (
          <li>{score.title}</li>
        ))}
      </ul>
    </Box>
  )
}

Page.getLayout = function getLayout(page: ReactElement) {
  return (
    <Layout>
      {page}
    </Layout>
  )
}

export default Page
```

こんな感じで一旦作成。
無事（？）CORSエラーが出ました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664809/9735123f-6c00-b00f-2b6e-85ed2fb97b08.png)

## CORSエラーの解消
Rails側に戻り、Gemfileでコメントアウトになっている以下の行のコメントを外します
```:Gemfile
gem "rack-cors"
```

`/config/initializers/cors.rb`を以下のように編集。

``` rb:/config/initializers/cors.rb
# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3001'
    resource "*",
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      credentials: true
  end
end
```

コメントアウト外して`credentials: true`を追加しています。（`methods:`の行の最後のコンマ忘れずに！）
私の環境はフロント側のサーバーを`:3001`ポートで建てているので、ここはよしなに変更してください。

これでサーバー再起動すればCORSエラーが解消されているはずです！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664809/9e39d53e-ddee-3362-8458-4cca4a93480b.png)
表示されました！
今回はここまで！

## 参考にさせていただいたサイト、記事
- [初めてのGraphQL with Rails ②（Apollo Client編）](https://qiita.com/sazumy/items/5fcb905b05d67126394f)
- [【フロントエンド】Apollo Clientを導入する](https://zenn.dev/lilac/books/37bdf5d90b5f9b/viewer/90ef78)