Mise en cache des réponses
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Les exemples ci-dessous utilisent la mise en cache Edge de Vercel pour fournir des données à vos utilisateurs aussi rapidement que possible.
⚠️ Un mot d'avertissement ⚠️
Soyez toujours prudent avec la mise en cache - surtout si vous traitez des informations personnelles.
Comme le traitement par lot est activé par défaut, il est recommandé de définir vos en-têtes de cache dans la fonction responseMeta et de vous assurer qu'il n'y a pas d'appels concurrents pouvant inclure des données personnelles - ou d'omettre complètement les en-têtes de cache s'il existe des en-têtes d'authentification ou des cookies.
Vous pouvez également utiliser un splitLink pour séparer vos requêtes publiques de celles qui doivent être privées et non mises en cache.
Mise en cache d'application
Si vous activez le SSR dans votre application, vous pourriez constater que votre application se charge lentement sur Vercel par exemple, mais vous pouvez en fait effectuer un rendu statique de toute votre application sans utiliser SSG ; lisez ce fil Twitter pour plus d'informations.
Exemple de code
pages/_app.tsxtsxexport default withTRPC({config(config) {if (typeof window !== 'undefined') {return {url: '/api/trpc',};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,};},ssr: true,responseMeta(config) {if (config.clientErrors.length) {// propagate http first error from API callsreturn {status: config.clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};},})(MyApp);
pages/_app.tsxtsxexport default withTRPC({config(config) {if (typeof window !== 'undefined') {return {url: '/api/trpc',};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,};},ssr: true,responseMeta(config) {if (config.clientErrors.length) {// propagate http first error from API callsreturn {status: config.clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};},})(MyApp);
Mise en cache des réponses d'API
Comme toutes les requêtes sont de simples GET HTTP, nous pouvons utiliser des en-têtes HTTP normaux pour mettre en cache les réponses, accélérer les réponses, soulager votre base de données et faciliter la montée en charge de votre API pour des milliards d'utilisateurs.
Utiliser responseMeta pour la mise en cache
En supposant que vous déployez votre API sur une plateforme gérant les en-têtes stale-while-revalidate comme Vercel.
server.tstsximport * as trpc from '@trpc/server';import { inferAsyncReturnType } 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 = inferAsyncReturnType<typeof createContext>;export function createRouter() {return trpc.router<Context>();}const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = createRouter().query('public.slow-query-cached', {async resolve({ ctx }) {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({ ctx, paths, type, errors }) {// 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: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};}return {};},});
server.tstsximport * as trpc from '@trpc/server';import { inferAsyncReturnType } 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 = inferAsyncReturnType<typeof createContext>;export function createRouter() {return trpc.router<Context>();}const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = createRouter().query('public.slow-query-cached', {async resolve({ ctx }) {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({ ctx, paths, type, errors }) {// 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: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};}return {};},});