概要
Apollo Clientでファイルアップロードを実現する際、ApolloのFile uploadsのドキュメントにある通り、apollo-upload-clientのように別途ライブラリを使用する方法が挙げられています。ドキュメントではReactでの使用が載せられていますが、今回はこのapollo-upload-clientをNuxtで使用してみたのでそのメモ書きです。
前提
- 使用したNuxtのバージョンは
3.13.0
です。 - 使用したNuxt Apolloのバージョンは
5.0.0-alpha.14
です。 - 使用したapollo-upload-clientのバージョンは
18.0.1
です。 - NuxtをTypeScriptで今回使用しましたが、apollo-upload-clientがこの記事を書いた時点(2024年9月)で型に対応してないので、types/apollo-upload-clientを別途入れます。バージョンは
18.0.0
を使用しました。 -
graphql-codegen/cli
の5.0.2
を使用して、schemaからコードを生成します。
対応方針
基本的な実装方針はGraphQL File Uploads Client Side with NuxtJSにある通りです。pluginsで別途Apollo Clientの設定を実装することができるので、ここでapollo-upload-clientを使用するようにします。
設定部分の実装サンプル
まずはcodegenの設定でschemaでUploadを使用できるよう、File型を設定するようにします。以下の通り設定しました。
codegen.ts
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: "graphqlSchema/*.graphql",
documents: ["query/*.ts"],
ignoreNoDocuments: true, // for better experience with the watcher
generates: {
"./gql/": {
preset: "client",
presetConfig: {
fragmentMasking: false,
},
config: {
useTypeImports: true,
scalars: {
Upload: "File", // UploadにFile型を割り当てる
},
},
},
},
};
export default config;
次にpluginsの実装です。基本的には上記で紹介した記事の通りですが、TypeScriptの対応などで一部実装を変えてる箇所もあります。
plugins/apolloConfig.ts
import { from, ApolloLink } from "@apollo/client/core";
import { onError } from "@apollo/client/link/error";
import { setContext } from "@apollo/client/link/context";
import { provideApolloClient } from "@vue/apollo-composable";
import createUploadLink from "apollo-upload-client/createUploadLink.mjs";
export default defineNuxtPlugin((app) => {
const envVars = useRuntimeConfig();
// 型のエラーを出さないために一旦anyにする
const { $apollo } = useNuxtApp();
const apollo: any = $apollo;
const errorLink = onError((err) => {
app.callHook("vue:error", err, null, "apollo error"); // must be called bc `@nuxtjs/apollo` will not do it anymore
});
const authLink = setContext(async (_, { headers }) => {
const { getToken } = useApollo(); //get you token from Nuxt/Apollo helper
const token = await getToken();
return {
headers: {
...headers,
"Apollo-Require-Preflight": "true",
Authorization: `Bearer ${token}`,
},
};
});
// create an customLink as example for an custom manual link
const customLink = new ApolloLink((operation, forward) => {
return forward(operation).map((data) => {
return data;
});
});
// Default httpLink (main communication for apollo) use createUploadLink function from apollo-upload-client
const httpLink = createUploadLink({
uri: envVars.public.apiEndpoint, // 環境変数でGraphQLの接続先を設定する
useGETForQueries: false, // GETは使用しないのでfalseにする
});
apollo.defaultClient.setLink(
from([errorLink, authLink, customLink, httpLink])
);
provideApolloClient(apollo.defaultClient);
});