Next.js 15 버전에서 apollo client를 적용하는 과정에 대해 설명하는 글이다.
처음 Next.js 15로 만든 프로젝트에 apollo client를 적용할 때, 이 라이브러리가 존재하지 않았다. 기존 Apollo GraphQL 라이브러리에 나와있던 experimental 버전을 사용하다가 아래 에러를 겪고 결국 해결하지 못해 잠시 접어두고 있었다. 프로젝트를 계속 진행하다가 @apollo/client-integration-nextjs 라이브러리가 새로 릴리즈된 것을 알게 되었고, 이를 적용함으로써 이전의 문제를 해결할 수 있었다.
아래는 이 패키지가 나온 배경과 특징에 관해 설명한 글이다. 간단히 요약하자면 이 패키지는 ‘Next.js에서 Apollo Client를 RSC와 SSR 각각의 상황에 맞게 잘 통합해 주는 도구’로써 사용될 수 있다는 것이다.
블로그 - @apollo/client-integration-nextjs Officially Released | Apollo GraphQL Blog
공식문서 - @apollo/client-integration-nextjs
이제 공식문서를 따라 초기 세팅을 진행해보자.
npm install @apollo/client@latest @apollo/client-integration-nextjs
query()
는 Promise 객체를 반환하기 때문에 사용하는 쪽에서는 비동기 처리를 위해 async/await
키워드를 사용해야 한다. 이 Promise 객체는 loading
, error
, data
프로퍼티를 갖는 객체로 resolve된다. import { HttpLink } from "@apollo/client";
import {
registerApolloClient,
ApolloClient,
InMemoryCache,
} from "@apollo/client-integration-nextjs";
export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
// graphql api 엔드포인트에 대한 절대 경로
uri: "http://example.com/api/graphql",
fetchOptions: {
},
}),
});
});
클라이언트 컴포넌트 관련 ApolloClient 객체 초기화
클라이언트 컴포넌트에서 graphql 요청을 처리하기 위한 설정이다. 사용하는 쪽에서는 useSuspenseQuery
를 사용하여 React의 Suspense
와 조합할 수 있다.
"use client";
import { HttpLink } from "@apollo/client";
import {
ApolloNextAppProvider,
ApolloClient,
InMemoryCache,
} from "@apollo/client-integration-nextjs";
// have a function to create a client for you
function makeClient() {
const httpLink = new HttpLink({
// graphql api 엔드포인트에 대한 절대 경로
uri: "https://example.com/api/graphql",
fetchOptions: {
},
});
// use the `ApolloClient` from "@apollo/client-integration-nextjs"
return new ApolloClient({
// use the `InMemoryCache` from "@apollo/client-integration-nextjs"
cache: new InMemoryCache(),
link: httpLink,
});
}
// 루트 레이아웃에서 사용될 래퍼
export function ApolloWrapper({ children }: React.PropsWithChildren) {
return (
<ApolloNextAppProvider makeClient={makeClient}>
{children}
</ApolloNextAppProvider>
);
}
// 루트 레이아웃에 적용한다.
import type { Metadata } from 'next';
import './globals.css';
import Link from 'next/link';
import MSWProvider from '@/applications/msw-provider';
import { ApolloWrapper } from '@/applications/apollo-wrapper';
export const metadata: Metadata = {
};
export default function RootLayout({
children,
modal,
}: Readonly<{
children: React.ReactNode;
modal: React.ReactNode;
}>) {
const isMockingEnabled = process.env.NEXT_PUBLIC_API_MOCKING === 'enabled';
return (
<html lang="en">
<ApolloWrapper>
<body>
</body>
</ApolloWrapper>
</html>
);
}
ApolloClient의 link와 cache는 필수 옵션이다.
실습 환경은 MSW로 응답을 모킹하고 있으며, 엔드포인트는 MSW의 목 서버로 지정되어 있음을 미리 알린다.
Suspense
와 useSuspenseQuery
훅을 사용하여 요청을 수행해본다.
MSW의 핸들러 상에 graphql 요청에 대한 응답 핸들러가 아래와 같이 정의된 상태이다.
이전에 서버 컴포넌트를 위해 선언했던 apollo-client의 query
를 사용하여 실제 쿼리를 수행해본다. query
에는 gql
템플릿 리터럴 태그로 감싼 쿼리문을 할당한다.
서버 사이드에서 일어나는 Next의 서버 액션 특성상 Apollo Client가 제공하는 클라이언트 동작을 수행하는 mutation 코드를 작성할 수 없다. 하지만, GraphQL은 기본적으로 HTTP 기반으로 동작하기 때문에, 별도의 라이브러리 없이 fetch 메서드를 통해서도 HTTP 요청을 보낼 수 있다.
참고자료
npm 공식문서
Nextjs Graphql mutation query using App router
Daleseo 블로그 - [GraphQL] Apollo Client 사용법
Is it possible to make GraphQL mutations into server side calls with NextJs App Router (v14)?