メインコンテンツまでスキップ

Apollo Linkについての概要を調べる

· 約3分
moroball14

個人で開発中のアプリで Apollo を使っていて、Link という概念について深ぼれていないなと思い、調べてみる。

ドキュメントは以下 ↓

https://www.apollographql.com/docs/react/api/link/introduction/

The Apollo Link library helps you customize the flow of data between Apollo Client and your GraphQL server. You can define your client's network behavior as a chain of link objects that execute in a sequence

とある通り、Apollo Client と GraphQL サーバー間のデータの流れをカスタマイズできるらしい。 シーケンス、つまり順序通り実行する。カスタマイズした処理を。データの流れをつなぐからLinkという表現になったのかな?

Each link should represent either a self-contained modification to a GraphQL operation or a side effect (such as logging).

とあるように、ロギングのような副作用が発生する処理を挟んだり、あとは HTTP ヘッダーに認証情報を追加したりするような、変更や副作用を加える目的で、Link を使う理解であっているかな?

最初にこの Link が必要になったのは HttpLink だったけど、正直この時はそれほど意識していなかった。意識し始めたのはエラーのデバッグ。 デフォルトだと、 ApolloError: Response not successful: Received status code 400 しか出なくて、何が起きているのか把握ができなかった。しかし、

"use client";
import React from "react";
import { ApolloLink, HttpLink, split } from "@apollo/client";
import {
NextSSRApolloClient,
NextSSRInMemoryCache,
SSRMultipartLink,
} from "@apollo/experimental-nextjs-app-support/ssr";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
import { getMainDefinition } from "@apollo/client/utilities";
import { onError } from "@apollo/client/link/error";

function makeClient() {
const httpLink = new HttpLink({
uri: "http://localhost:3000/graphql", // localhostでGraphQLサーバーを立てている前提
});

const wsLink = new GraphQLWsLink(
createClient({
url: "ws://localhost:3000/graphql",
})
);

// Log any GraphQL errors or network error that occurred
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.forEach(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
if (networkError) console.log(`[Network error]: ${networkError}`);
});

const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
errorLink.concat(wsLink),
errorLink.concat(httpLink)
);

return new NextSSRApolloClient({
cache: new NextSSRInMemoryCache(),
link:
typeof window === "undefined"
? ApolloLink.from([
new SSRMultipartLink({
stripDefer: true,
}),
errorLink,
httpLink,
])
: splitLink,
});
}

とすると、エラー文の詳細が確認でき、コードの修正ができるようになった。

その他にもカスタムリンクと呼ばれる機能もあり、自分で自由にネットワーク操作を拡張できる。 たとえば

import { ApolloLink } from "@apollo/client";

const timeStartLink = new ApolloLink((operation, forward) => {
operation.setContext({ start: new Date() });
return forward(operation);
});

このようにしたら、GraphQL の操作のコンテキストに新しい start というプロパティが追加できる。 forward を呼び忘れそうー。ESLint で防げそうな感じはする。

概要は少しわかった気がするので、またわからない点が出てきたら、このブログに追記する。