apollo-server(v3系)は非推奨となったので、@apollo/server(v4系)に移行しましょう
ApolloServer3 のサポート終了は 2023/10/22
以下公式サイトにApollo Server 3の終了と、Apollo Server 4 移行の説明が載っています。
https://www.apollographql.com/docs/apollo-server/migration
現在使用しているパッケージがapollo-serverだった場合は非推奨バージョンです。できるだけ早く準備を整えて@apollo/serverに乗り換えましょう。
何が変わったのか
バラバラに散っていた機能が一つのパッケージに集約されました。その関係で切られる機能はバッサリ切られ、自分で書かなければならないコードが増えました。
情報が少ない
ネット上の記事はほぼApollo Server 3の頃のものばかりなので、公式以外の情報はあまり期待できません。こういう時に必要なのは、情報が少ないときほどワクワクする心を持つことです。新雪に最初に足跡を突っ込んでやるヒャッホーという気持ちこそが必要なのです。
サンプルを作ってみる
Next.js の APIRoute からアクセス出来る GraphQL のエンドポイントを作ってみます。ただし、普通にやるだけなら公式を見れば良いだろうという話になるので、なぜか人々が作るのを嫌がるファイルのアップロード機能を入れてみます。
Next.js のサンプル
https://github.com/SoraKumo001/next-apollo-server
API Route に GraphQL のエンドポイントを用意
Apollo Server4では、GraphQL の処理に executeHTTPGraphQLRequest を使用します。httpGraphQLRequest に適切な情報を載せて呼び出します。
必要な部分はパッケージから利用出来るようになっています。変換に関する具体的な処理は以下のコードを参照してください。
https://github.com/ReactLibraries/next-apollo-server/blob/master/src/index.ts
src/pages/api/graphql
1import { promises as fs } from 'fs';2import { ApolloServer } from '@apollo/server';3import { executeHTTPGraphQLRequest, FormidableFile } from '@react-libraries/next-apollo-server';4import type { IResolvers } from '@graphql-tools/utils';5import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';67/**8 * Type settings for GraphQL9 */10const typeDefs = `11 # Return date12 scalar Date13 type Query {14 date: Date!15 }16 # Return file information17 type File {18 name: String!19 type: String!20 value: String!21 }22 scalar Upload23 type Mutation {24 upload(file: Upload!): File!25 }26`;2728/**29 * Set Context type30 */31type Context = { req: NextApiRequest; res: NextApiResponse };3233/**34 * Resolver for GraphQL35 */36const resolvers: IResolvers<Context> = {37 Query: {38 date: async (_context, _args) => new Date(),39 },40 Mutation: {41 upload: async (_context, { file }: { file: FormidableFile }) => {42 return {43 name: file.originalFilename,44 type: file.mimetype,45 value: await fs.readFile(file.filepath, { encoding: 'utf8' }),46 };47 },48 },49};5051/**52 * apolloServer53 */54const apolloServer = new ApolloServer<Context>({55 typeDefs,56 resolvers,57});58apolloServer.start();5960/**61 * APIRoute handler for Next.js62 */63const handler: NextApiHandler = async (req, res) => {64 //Convert NextApiRequest to body format for GraphQL (multipart/form-data support).65 return executeHTTPGraphQLRequest({66 req,67 res,68 apolloServer,69 context: async () => ({ req, res }),70 options: {71 //Maximum upload file size set at 10 MB72 maxFileSize: 10 * 1024 * 1024,73 },74 });75};7677export default handler;7879export const config = {80 api: {81 bodyParser: false,82 },83};
フロント側の処理
src/pages/_app.tsx
createUploadLink でUploadタイプのパラメータを multipart 形式に変換させる必要があります。また、ヘッダーにapollo-require-preflightが必要です。
1import type { AppType } from "next/app";2import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";3import { createUploadLink } from "apollo-upload-client";4const endpoint = "/api/graphql";5const uri =6 typeof window === "undefined"7 ? `${8 process.env.VERCEL_URL9 ? `https://${process.env.VERCEL_URL}`10 : "http://localhost:3000"11 }${endpoint}`12 : endpoint;1314const App: AppType = ({ Component, pageProps }) => {15 const client = new ApolloClient({16 cache: new InMemoryCache(),17 // Upload用18 link: createUploadLink({19 uri,20 headers: { "apollo-require-preflight": "true" },21 }),22 });2324 return (25 <ApolloProvider client={client}>26 <Component {...pageProps} />27 </ApolloProvider>28 );29};3031export default App;
src/pages/index.tsx
アップロードの処理は variables に blob オブジェクトのデータを載せるだけなので簡単です。
こちらのサンプルでは、ドラッグドロップされたデータをバックエンドに送って、内容を戻してもらい表示する実装になっています。
また、日付表示はおまけで、ファイルのアップロードとは関係ありません。
1import { gql, useMutation, useQuery } from '@apollo/client';23// Date retrieval4const QUERY = gql`5 query date {6 date7 }8`;910// Uploading files11const UPLOAD = gql`12 mutation Upload($file: Upload!) {13 upload(file: $file) {14 name15 type16 value17 }18 }19`;2021const Page = () => {22 const { data, refetch } = useQuery(QUERY);23 const [upload, { data: file }] = useMutation(UPLOAD);24 return (25 <>26 <a target="_blank" href="https://github.com/SoraKumo001/next-apollo-server" rel="noreferrer">27 Source code28 </a>29 <hr />30 {/* SSRedacted data can be updated by refetch. */}31 <button onClick={() => refetch()}>Update date</button>32 {33 /* Dates are output as SSR. */34 data?.date && new Date(data.date).toLocaleString('en-US', { timeZone: 'UTC' })35 }36 {/* File upload sample from here down. */}37 <div38 style={{39 height: '100px',40 width: '100px',41 background: 'lightgray',42 marginTop: '8px',43 padding: '8px',44 }}45 onDragOver={(e) => {46 e.preventDefault();47 }}48 onDrop={(e) => {49 const file = e.dataTransfer.files[0];50 if (file) {51 upload({ variables: { file } });52 }53 e.preventDefault();54 }}55 >56 Upload Area57 </div>58 {/* Display of information on returned file data to check upload operation. */}59 {file && <pre>{JSON.stringify(file, undefined, ' ')}</pre>}60 </>61 );62};6364export default Page;
まとめ
Apollo Server 3は非推奨パッケージなので、早々にApollo Server 4への移行をお勧めします。