概要
突然ですが、皆さんはGraphQLをSPAなどで利用する際にセッション情報をリクエストURLのクエリ文字やGraphQLのinput部分に含んだりしていませんか?
実は、GraphQL使いたての頃の自分はリアルにセッション情報の一部をリクエストURLのクエリ文字に含んでバックエンドにログインしているか教えていました。
※ 今回は、NextAuthを利用しているので、セッション情報はバックエンドではなくフロントエンドが保持しています。
NextAuthにはsessionを管理してくるuseSessionというフックが存在します。これを利用することで、Redisの設定やCookie周りで非常に苦しめられた「バックエンドでセッションを管理する」から解放されるのです。
→ こちらNextAuthの公式サイトです。興味があればご覧になってみてください!
本題に戻りますが今回は、実際にApollo Clientの初期設定を行いながら解説していこうと思います。
Apollo Clientをインストールする
$ npm install @apollo/client graphql
ここでは、1.@apollo/clientと2.graphql*という二つのパッケージのインストールを行っています。
一つ目のパッケージ(@apollo/client)はapollo clientを使う上で必要な基本的なものが大体まとまっているというものです。
例えば、Apollo Clientにおける代表的なキャッシュ機構であるInMemoryCacheやエラー処理、ローカルステート管理などが含まれているらしいです。
二つの目のパッケージ(graphql)は、GraphQLのクエリを解析するために必要なものです。
Apollo Clientのインスタンスを初期化する
細かいヘッダーにセッション情報を追加する部分などもここに含まれていますが、切り分けるのが面倒だったので一挙に解説してしまいます。
// 1. 必要なシンボルのimport
import {
ApolloClient,
InMemoryCache,
createHttpLink,
ApolloProvider,
} from "@apollo/client";
// 2. http linkの生成
const httpLink = createHttpLink({
uri: `${server url}/graphql`,
});
// 3. headerをリクエストを送る前のコンテキストに追加する
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token');
return {
headers: {
...headers,
authorization: token && token !== 'undefined' ? token : "",
}
}
})
// 4. apollo clientのインスタンスの初期化
const apolloClient = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
コードの中にコメントでざっくり「何してるか」を記述してみましたが、もう一度詳しく解説していこうと思います。
※1.の部分は単なるインポートですので割愛させていただきます。
2. http linkの生成
ここでは、バックエンドにリクエストを送る際のリクエストURLを作成しています。
今回のサンプルコードでは、「LocalStrageに保存してあるJWTトークンを取得し、それをheaderの中に追加する」という手順で行なっているためリクエストURLの生成部分とheaderの作成部分を分けていますが、どうやら下記のように、headerも一緒に渡すという方法もあるようです。
コードの引用元: Apollo Clientを使ってGitHubクライアントを作成してみた
const httpLink = createHttpLink({
uri: "https://api.github.com/graphql",
headers: {
authorization: `Bearer ${process.env.REACT_APP_GITHUB_TOKEN}`
}
});
3. header部分の作成
ここではsetContextという関数を使ってコンテキストの設定を行なっています。
どうやらこのsetContextという関数は、オブジェクトまたは、プロミスを返す関数を受け取り、リクエストの新しいコンテキスト(ここではheader
)を設定するためのオブジェクトを返すそうです。
さらにsetContextの引数の関数は、基本的に二つの引数を受け取るそうで、一つ目が「これから実行しようとするGraphQLのリクエスト」で、二つ目が「リクエスト前のコンテキスト」です。
必ず二つの引数を受け取る必要があるっぽいので、第一引数を_(アンダースコア)でおいておき、第二引数からはheaderのみを受け取ることにします。(基本的に第一引数とheader以外は必要ないので)
あとは、上記でも少し触れましたが、今回はlocalStorageにJWTトークンを保存しているのでそれを取り出してheaderに追加しています。
4. apollo clientのインスタンスの初期化
最後の部分は、2.と3.で作ったリクエストURLとheaderをconcatさせたものを引数に渡してインスタンスを初期化させている。
これでapollo clientが作成できれば、ApolloProviderを使って下記のように、クライアント情報を他のコンポーネントで共有することができます。
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
最後に
何か間違っていたり、ツッコミどころがあればなんでもコメントください!🙇♀️