서버 사이드 헬퍼
서버 사이드 헬퍼는 서버에서 쿼리를 사전에 가져오기(prefetch)할 때 사용할 수 있는 헬퍼 함수 집합을 제공합니다. 이는 SSG에 유용할 뿐만 아니라, ssr: true를 사용하지 않기로 선택한 경우에도 SSR에 유용합니다.
서버 사이드 헬퍼를 통한 사전 가져오기는 서버에서 쿼리 캐시를 채우는 것을 허용하므로, 이러한 쿼리는 클라이언트에서 초기에 가져오지 않아도 됩니다.
서버 사이드 헬퍼를 사용하는 두 가지 방법
1. 내부 라우터
이 방법은 tRPC 라우터에 직접 접근할 수 있는 경우, 예를 들어 모놀리식 Next.js 애플리케이션을 개발할 때 사용됩니다.
헬퍼를 사용하면 tRPC가 HTTP 요청 없이 서버에서 프로시저를 직접 호출합니다. 이는 서버 사이드 호출과 유사합니다.
따라서 일반적인 요청 처리와 달리 요청 및 응답 객체를 사용할 수 없습니다. 보통 컨텍스트 생성 과정에서 채워지는 req와 res를 제외하고 서버 사이드 헬퍼를 초기화해야 합니다. 이 경우에는 "내부" 및 "외부" 컨텍스트 패턴을 권장합니다.
tsimport {createServerSideHelpers } from '@trpc/react-query/server';import {createContext } from './server/context';import {appRouter } from './server/routers/_app';importsuperjson from 'superjson';consthelpers =createServerSideHelpers ({router :appRouter ,ctx : awaitcreateContext (),transformer :superjson ,});
tsimport {createServerSideHelpers } from '@trpc/react-query/server';import {createContext } from './server/context';import {appRouter } from './server/routers/_app';importsuperjson from 'superjson';consthelpers =createServerSideHelpers ({router :appRouter ,ctx : awaitcreateContext (),transformer :superjson ,});
2. 외부 라우터
이 방법은 tRPC 라우터에 직접 접근할 수 없는 경우, 예를 들어 Next.js 애플리케이션과 별도로 호스팅되는 독립형 API를 개발할 때 사용됩니다.
tsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import {createServerSideHelpers } from '@trpc/react-query/server';import type {AppRouter } from './server/router';importsuperjson from 'superjson';constproxyClient =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000/api/trpc',}),],});consthelpers =createServerSideHelpers ({client :proxyClient ,});
tsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import {createServerSideHelpers } from '@trpc/react-query/server';import type {AppRouter } from './server/router';importsuperjson from 'superjson';constproxyClient =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000/api/trpc',}),],});consthelpers =createServerSideHelpers ({client :proxyClient ,});
헬퍼 사용법
서버 사이드 헬퍼 메서드는 라우터 구조를 그대로 반영하는 객체를 반환합니다. 다만 useQuery와 useMutation 대신 prefetch, fetch, prefetchInfinite, fetchInfinite 함수를 제공합니다.
fetch는 일반 함수처럼 쿼리 결과를 반환합니다. 반면 prefetch는 결과를 반환하지 않고 예외도 발생시키지 않으며, 쿼리를 캐시에 추가합니다. 이후 prefetch로 채운 캐시를 탈수화(dehydrate)해 클라이언트로 전송할 수 있습니다. fetch의 반환값이나 예외가 필요하다면 prefetch 대신 fetch를 사용하세요.
ts// In getServerSideProps / getStaticProps:constprops = {// very important - use `trpcState` as the keytrpcState :helpers .dehydrate (),};
ts// In getServerSideProps / getStaticProps:constprops = {// very important - use `trpcState` as the keytrpcState :helpers .dehydrate (),};
일반적인 규칙은 클라이언트에서 필요할 것으로 알고 있는 쿼리에 대해 prefetch를 사용하고, 서버에서 결과를 사용하려는 쿼리에 대해 fetch를 사용하는 것입니다.
이 함수들은 모두 react-query 함수를 감싸는 래퍼입니다. 자세한 내용은 react-query 문서를 확인하세요.
전체 예제는 E2E SSG 테스트 예제를 확인하세요.
Next.js 예제
pages/posts/[id].tsxtsximport {createServerSideHelpers } from '@trpc/react-query/server';import {appRouter } from './server/routers/_app';import {trpc } from './utils/trpc';import {GetServerSidePropsContext ,InferGetServerSidePropsType } from 'next';importsuperjson from 'superjson';export async functiongetServerSideProps (context :GetServerSidePropsContext <{id : string }>,) {consthelpers =createServerSideHelpers ({router :appRouter ,ctx : {},transformer :superjson ,});constid =context .params ?.id as string;/** Prefetching the `post.byId` query.* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.*/awaithelpers .post .byId .prefetch ({id });// Make sure to return { props: { trpcState: helpers.dehydrate() } }return {props : {trpcState :helpers .dehydrate (),id ,},};}export default functionPostViewPage (props :InferGetServerSidePropsType <typeofgetServerSideProps >,) {const {id } =props ;constpostQuery =trpc .post .byId .useQuery ({id });if (postQuery .status !== 'success') {// won't happen since the query has been prefetchedreturn <>Loading...</>;}const {data } =postQuery ;return (<><h1 >{data .title }</h1 ><em >Created {data .createdAt .toLocaleDateString ()}</em ><p >{data .text }</p ><h2 >Raw data:</h2 ><pre >{JSON .stringify (data , null, 4)}</pre ></>);}
pages/posts/[id].tsxtsximport {createServerSideHelpers } from '@trpc/react-query/server';import {appRouter } from './server/routers/_app';import {trpc } from './utils/trpc';import {GetServerSidePropsContext ,InferGetServerSidePropsType } from 'next';importsuperjson from 'superjson';export async functiongetServerSideProps (context :GetServerSidePropsContext <{id : string }>,) {consthelpers =createServerSideHelpers ({router :appRouter ,ctx : {},transformer :superjson ,});constid =context .params ?.id as string;/** Prefetching the `post.byId` query.* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.*/awaithelpers .post .byId .prefetch ({id });// Make sure to return { props: { trpcState: helpers.dehydrate() } }return {props : {trpcState :helpers .dehydrate (),id ,},};}export default functionPostViewPage (props :InferGetServerSidePropsType <typeofgetServerSideProps >,) {const {id } =props ;constpostQuery =trpc .post .byId .useQuery ({id });if (postQuery .status !== 'success') {// won't happen since the query has been prefetchedreturn <>Loading...</>;}const {data } =postQuery ;return (<><h1 >{data .title }</h1 ><em >Created {data .createdAt .toLocaleDateString ()}</em ><p >{data .text }</p ><h2 >Raw data:</h2 ><pre >{JSON .stringify (data , null, 4)}</pre ></>);}