🐾
Apollo Client や URQL でリクエストヘッダーやレスポンスヘッダーを操作する
この記事は以下のページに移動しました。
GraphQLのクライエントパッケージとしては Apollo Client や URQL が有名です。
リクエストヘッダーに値をセットしたり、レスポンスヘッダーから値を取得するコードを書いたので記事にしておきます。
今回は例としてCSRFトークンをセットしたり、取り出したりします。
書いてるコードはTypescriptなのでJavascriptで書く人はうまく読み替えてください。
登場するRouterコンポーネントはReactRouterを使ったものですが、別になんでもいいです。
また、説明中に出てくるsessionStorageはブラウザにデータを保存するものです。サーバーサイドで扱うセッションやCookieではないです。
Apollo Client の例
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
HttpLink,
ApolloLink,
} from "@apollo/client";
import Router from "./Router";
const App: React.FC = () => {
const httpLink = new HttpLink({ uri: "/graphql" });
const middlewareLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
"X-CSRF-Token":
sessionStorage.getItem("csrfToken") ||
document.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')
?.content ||
null,
},
}));
return forward(operation);
});
const afterwareLink = new ApolloLink((operation, forward) => {
return forward(operation).map((response) => {
const context = operation.getContext();
const headers = context.response.headers;
if (headers && headers.get("csrf-token")) {
sessionStorage.setItem("csrfToken", headers.get("csrf-token"));
}
return response;
});
});
const client = new ApolloClient({
link: ApolloLink.from([middlewareLink, afterwareLink, httpLink]),
cache: new InMemoryCache(),
});
return (
<ApolloProvider client={client}>
<Router />
</ApolloProvider>
);
};
export default App;
middlewareLinkの方がリクエストヘッダーにCSRFトークンをセットしています。
sessionStorageにトークンが入っていればそれを使い、なければHTMLのhead内metaタグ内に入ってるトークンを使うようにしてます。
afterwareLinkの方がレスポンスヘッダーからCSRFトークンを取り出しています。
レスポンスヘッダーにトークンが存在すればsessionStorageに保存してます。
URQL
import { createClient, Provider } from "urql";
import Router from "./Router";
const App: React.FC = () => {
const client = createClient({
url: "/graphql",
fetchOptions: () => {
const csrfToken =
sessionStorage.getItem("csrfToken") ||
document.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')
?.content ||
"";
return {
headers: {
"X-CSRF-Token": csrfToken,
},
};
},
fetch: (...args) =>
fetch(...args).then((response) => {
const csrfToken = response.headers.get("csrf-token");
if (csrfToken) {
sessionStorage.setItem("csrfToken", csrfToken);
}
return response;
}),
});
return (
<Provider value={client}>
<Router />
</Provider>
);
};
export default App;
fetchOptionsオプションを使ってリクエストヘッダーに値をセットできます。
公式ドキュメントにあるようにheaders: { ... }
のハッシュを返す処理を書けばよいので、ハッシュの中にCSRFトークンを入れてます。
fetchオプションを使ってレスポンスヘッダーから値を取得できます。
Apollo clientの時と同様に、レスポンスヘッダー内にトークンがあればsessionStorageに保存しています。
参考
Discussion