GraphQL은 FE 입장에서 RESTful과 같은 역할의 프로토콜이므로 GraphQL 자체가 요청을 보내는 역할을 하지 않는다. 따라서 request를 위한 별도의 무언가가 필요하다.
물론 fetch를 사용도 가능하다. fetch를 사용하면 method는 주로 POST를 사용한다.
fetch('https://rickandmortyapi.com/graphql', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
query: `{
characters {
results {
name
}
}
}`
})
})
하지만 이렇게 하면 string 문자열을 매번 적어줘야 하고 JSON.stringify를 매번 해줘야 하는 번거로움이 있기 때문에 Apollo, urql과 같은 라이브러리를 사용하는 것이다.
현재 프로젝트는 Nextjs App router를 사용하고 있기 때문에 이 기준에 부합하는 라이브러리를 살펴보겠다.
공식 사이트
아마 가장 대중적인 라이브러리라고 생각한다. 라이브러리 중에서 가장 많은 기능을 지원하고 그렇기에 무겁다.
처음엔 이걸 사용할까 고민했지만, nextjs 13부터 적용된 rsc에 대응하기 위한 패키지가 아직 정식 버전이 아닌 듯 했다. 이름부터 experimental이 들어가있다.
https://www.npmjs.com/package/@apollo/experimental-nextjs-app-support

위 사이트 설명에서도 정식 버전이 아님을 말하고 있다.
사용방법은 이전 포스팅을 참고하면 된다.
사용법은 Apollo와 거의 흡사했다.
// @/lib/urql/UrqlWrapper.tsx
'use client';
import {
cacheExchange,
createClient,
fetchExchange,
ssrExchange,
UrqlProvider,
} from '@urql/next';
import { useMemo } from 'react';
export default function UrqlWrapper({
children,
}: {
children: React.ReactNode;
}) {
const [client, ssr] = useMemo(() => {
const ssr = ssrExchange({
isClient: typeof window !== 'undefined',
});
const client = createClient({
url: process.env.NEXT_PUBLIC_BASE_URL || '',
exchanges: [cacheExchange, ssr, fetchExchange],
suspense: true,
});
return [client, ssr];
}, []);
return (
<UrqlProvider client={client} ssr={ssr}>
{children}
</UrqlProvider>
);
}
// layout.tsx
import UrqlWrapper from '@/lib/urql/UrqlWrapper';
export default function UrqlLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<UrqlWrapper>
{children}
</UrqlWrapper>
);
}
apollo와 마찬가지로 rsc 지원을 위한 별도 설정이 필요하다.
import { registerUrql } from '@urql/next/rsc';
import { cacheExchange, createClient, fetchExchange } from 'urql';
const makeClient = () => {
return createClient({
url: process.env.BASE_URL || 'http://localhost:3001/graphql',
exchanges: [cacheExchange, fetchExchange],
});
};
export const { getClient } = registerUrql(makeClient);
// @/lib/urql/queries
import { gql } from 'urql';
// 쿼리 선언 방법 Apollo와 동일하다.
export const GET_POST_LIST = gql`
{
posts {
id
title
}
}
`;
차이점이 있다면 apollo와 다르게 server component에서 상태 관리까지 해주진 못한다 ㅠ
import { GET_POST_LIST } from '@/lib/urql/queries';
import { getClient } from '@/lib/urql/UrqlClient';
import { Post } from '@/types/post';
import Link from 'next/link';
export default async function Page() {
const { data } = await getClient().query<{ posts: Post[] }>(
GET_POST_LIST,
{}
);
return (
<div>
<ul>
{data &&
data.posts.map((el) => (
<li key={el.id}>
<Link href={`/test/${el.id}`}>{el.title}</Link>
</li>
))}
</ul>
</div>
);
}
캐싱 방식의 차이가 있다. Apollo는 id를 사용한 정규화 캐싱을 사용하고 Urql은 Document 캐싱을 사용한다. => 아직 내용 파악이 안됐다 ㅠ 찾아봐야함
공식 문서 참고
urql은 데이터를 캐싱할 때 기준이 query와 그 변수이다.
상태 관리, 페이지네이션, 에러 핸들링 등 다양한 기능이 필요하다 => Apollo
graphql 관련된 기능만 필요하다 => Urql
개인적으론, 러닝 커브가 있지만 고점이 높다는 Relay를 사용해보고 싶은데 next app router 버전부터는 공식 지원이 안돼서 아쉽다 ㅠ
https://blog.logrocket.com/why-i-finally-switched-to-urql-from-apollo-client/
apollo client의 문제점
apollo vs relay vs urql