응답 캐싱
모든 tRPC 쿼리는 표준 HTTP GET 요청이므로, 표준 HTTP 캐시 헤더를 사용하여 응답을 캐시할 수 있습니다. 이를 통해 응답 속도를 높이고, 데이터베이스 부하를 줄이며, API의 확장성을 향상시킬 수 있습니다.
정보
캐싱은 특히 개인 정보를 처리하는 경우 항상 주의 깊게 다뤄야 합니다.
기본적으로 배치 처리가 활성화되어 있으므로, responseMeta 함수에서 캐시 헤더를 설정하고 개인 데이터가 포함될 수 있는 동시 호출이 없도록 확인하는 것이 좋습니다. 또는 인증 헤더나 쿠키가 있는 경우 캐시 헤더를 완전히 생략할 수도 있습니다.
splitLink를 사용하여 공개 요청과 비공개 및 캐싱되지 않아야 하는 요청을 분리할 수도 있습니다.
responseMeta를 사용하여 응답 캐싱
대부분의 tRPC 어댑터는 호출되는 프로시저에 따라 HTTP 헤더(캐시 헤더 포함)를 설정할 수 있는 responseMeta 콜백을 지원합니다.
표준 HTTP 캐시 헤더를 지원하는 모든 호스팅 제공업체(예: Vercel, Cloudflare, AWS CloudFront)에서 작동합니다.
server.tstsimport {initTRPC } from '@trpc/server';import {createHTTPServer } from '@trpc/server/adapters/standalone';import type {CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';export constcreateContext = async (opts :CreateHTTPContextOptions ) => {return {req :opts .req ,res :opts .res ,};};typeContext =Awaited <ReturnType <typeofcreateContext >>;export constt =initTRPC .context <Context >().create ();constwaitFor = async (ms : number) =>newPromise ((resolve ) =>setTimeout (resolve ,ms ));export constappRouter =t .router ({public :t .router ({slowQueryCached :t .procedure .query (async (opts ) => {awaitwaitFor (5000); // wait for 5sreturn {lastUpdated : newDate ().toJSON (),};}),}),});// Exporting `type AppRouter` only exposes types that can be used for inference// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-exportexport typeAppRouter = typeofappRouter ;// export API handlerconstserver =createHTTPServer ({router :appRouter ,createContext ,responseMeta (opts ) {const {paths ,errors ,type } =opts ;// assuming you have all your public routes with the keyword `public` in themconstallPublic =paths &&paths .every ((path ) =>path .includes ('public'));// checking that no procedures erroredconstallOk =errors .length === 0;// checking we're doing a query requestconstisQuery =type === 'query';if (allPublic &&allOk &&isQuery ) {// cache request for 1 day + revalidate once every secondconstONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers : newHeaders ([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS }`,],]),};}return {};},});server .listen (3000);
server.tstsimport {initTRPC } from '@trpc/server';import {createHTTPServer } from '@trpc/server/adapters/standalone';import type {CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';export constcreateContext = async (opts :CreateHTTPContextOptions ) => {return {req :opts .req ,res :opts .res ,};};typeContext =Awaited <ReturnType <typeofcreateContext >>;export constt =initTRPC .context <Context >().create ();constwaitFor = async (ms : number) =>newPromise ((resolve ) =>setTimeout (resolve ,ms ));export constappRouter =t .router ({public :t .router ({slowQueryCached :t .procedure .query (async (opts ) => {awaitwaitFor (5000); // wait for 5sreturn {lastUpdated : newDate ().toJSON (),};}),}),});// Exporting `type AppRouter` only exposes types that can be used for inference// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-exportexport typeAppRouter = typeofappRouter ;// export API handlerconstserver =createHTTPServer ({router :appRouter ,createContext ,responseMeta (opts ) {const {paths ,errors ,type } =opts ;// assuming you have all your public routes with the keyword `public` in themconstallPublic =paths &&paths .every ((path ) =>path .includes ('public'));// checking that no procedures erroredconstallOk =errors .length === 0;// checking we're doing a query requestconstisQuery =type === 'query';if (allPublic &&allOk &&isQuery ) {// cache request for 1 day + revalidate once every secondconstONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers : newHeaders ([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS }`,],]),};}return {};},});server .listen (3000);
팁
Next.js를 사용하는 경우, createTRPCNext와 Next.js 어댑터를 사용한 Next.js 전용 캐싱 예시를 확인하려면 Next.js SSR 캐싱 가이드를 참조하세요.