Almacenamiento en caché de respuestas
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Los siguientes ejemplos utilizan el almacenamiento en caché de edge de Vercel para servir datos a tus usuarios lo más rápido posible.
Siempre ten cuidado con el almacenamiento en caché, especialmente si manejas información personal.
Como la agrupación de solicitudes está habilitada por defecto, se recomienda configurar las cabeceras de caché en la función responseMeta y asegurarte de que no haya llamadas concurrentes que puedan incluir datos personales, u omitir completamente las cabeceras de caché si existe una cabecera de autenticación o cookie.
También puedes usar un splitLink para separar tus solicitudes públicas de aquellas que deben ser privadas y no almacenadas en caché.
Almacenamiento en caché de aplicaciones
Si activas SSR en tu aplicación, podrías descubrir que se carga lentamente en, por ejemplo, Vercel. Pero en realidad puedes renderizar estáticamente toda tu aplicación sin usar SSG; lee este hilo de Twitter para más información.
Código de ejemplo
utils/trpc.tsxtsximport { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../server/routers/_app';export const trpc = createTRPCNext<AppRouter>({config(config) {if (typeof window !== 'undefined') {return {links: [httpBatchLink({url: '/api/trpc',}),],};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {links: {http: httpBatchLink({url,}),},};},ssr: true,responseMeta(opts) {const { clientErrors } = opts;if (clientErrors.length) {// propagate http first error from API callsreturn {status: clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: new Headers([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,],]),};},});
utils/trpc.tsxtsximport { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import type { AppRouter } from '../server/routers/_app';export const trpc = createTRPCNext<AppRouter>({config(config) {if (typeof window !== 'undefined') {return {links: [httpBatchLink({url: '/api/trpc',}),],};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {links: {http: httpBatchLink({url,}),},};},ssr: true,responseMeta(opts) {const { clientErrors } = opts;if (clientErrors.length) {// propagate http first error from API callsreturn {status: clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: new Headers([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,],]),};},});
Almacenamiento en caché de respuestas de API
Dado que todas las consultas son HTTP GETs normales, podemos usar cabeceras HTTP estándar para almacenar respuestas en caché, hacer que las respuestas sean rápidas, dar un descanso a tu base de datos y escalar fácilmente tu API para millones de usuarios.
Usar responseMeta para almacenar respuestas en caché
Suponiendo que despliegas tu API en un lugar que pueda manejar cabeceras de caché stale-while-revalidate como Vercel.
server.tstsximport { initTRPC } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';export const createContext = async ({req,res,}: trpcNext.CreateNextContextOptions) => {return {req,res,prisma,};};type Context = Awaited<ReturnType<typeof createContext>>;export const t = initTRPC.context<Context>().create();const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = t.router({public: t.router({slowQueryCached: t.procedure.query(async (opts) => {await waitFor(5000); // wait for 5sreturn {lastUpdated: new Date().toJSON(),};}),}),});// Exporting type _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 type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext,responseMeta(opts) {const { ctx, paths, errors, type } = opts;// assuming you have all your public routes with the keyword `public` in themconst allPublic = paths && paths.every((path) => path.includes('public'));// checking that no procedures erroredconst allOk = errors.length === 0;// checking we're doing a query requestconst isQuery = type === 'query';if (ctx?.res && allPublic && allOk && isQuery) {// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: new Headers([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,],]),};}return {};},});
server.tstsximport { initTRPC } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';export const createContext = async ({req,res,}: trpcNext.CreateNextContextOptions) => {return {req,res,prisma,};};type Context = Awaited<ReturnType<typeof createContext>>;export const t = initTRPC.context<Context>().create();const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = t.router({public: t.router({slowQueryCached: t.procedure.query(async (opts) => {await waitFor(5000); // wait for 5sreturn {lastUpdated: new Date().toJSON(),};}),}),});// Exporting type _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 type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext,responseMeta(opts) {const { ctx, paths, errors, type } = opts;// assuming you have all your public routes with the keyword `public` in themconst allPublic = paths && paths.every((path) => path.includes('public'));// checking that no procedures erroredconst allOk = errors.length === 0;// checking we're doing a query requestconst isQuery = type === 'query';if (ctx?.res && allPublic && allOk && isQuery) {// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: new Headers([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,],]),};}return {};},});