Aller au contenu principal
Version : 11.x

Adaptateur Fetch / Runtimes Edge

Traduction Bêta Non Officielle

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 →

Vous pouvez créer un serveur tRPC dans n'importe quel runtime edge conforme aux spécifications WinterCG, en particulier l'API Web Plateforme Commune Minimale.

Ces environnements d'exécution incluent notamment, sans s'y limiter :

  • Cloudflare Workers

  • Deno Deploy

  • Vercel Edge Runtime (& Next.js Edge Runtime)

Cela facilite également l'intégration dans les frameworks utilisant les API de la plateforme web pour représenter les requêtes et réponses, tels que :

  • Astro (mode SSR)

  • Remix

  • SolidStart

Exemples d'applications​

DescriptionLinks
Cloudflare Workers example

Source

Deno Deploy example

Source

Next.js Edge Runtime example

Source

Vercel Edge Runtime example

Source

Utiliser le serveur tRPC avec un runtime edge​

tRPC fournit un adaptateur fetch utilisant les API natives Request et Response comme entrées/sorties. Le code spécifique à tRPC reste identique quel que soit le runtime, seule la gestion de la réponse diffère.

tRPC intègre nativement un adaptateur pour l'API Fetch. Celui-ci transforme votre routeur tRPC en gestionnaire de Request produisant des objets Response.

API Web requises​

Le serveur tRPC utilise les API Fetch suivantes :

  • Request, Response

  • fetch

  • Headers

  • URL

Si votre runtime supporte ces API, vous pouvez utiliser le serveur tRPC.

astuce

Saviez-vous que cela signifie que vous pouvez utiliser un serveur tRPC directement dans votre navigateur ?

Configuration commune​

Installer les dépendances​

astuce

Cette étape est optionnelle si vous utilisez Deno Deploy.

npm install @trpc/server @trpc/client zod

Zod n'est pas obligatoire mais est utilisé dans l'exemple de routeur ci-dessous.

Agents IA

Si vous utilisez un agent de codage IA, installez les compétences tRPC pour une meilleure génération de code :

bash
npx @tanstack/intent@latest install
bash
npx @tanstack/intent@latest install

Créer le routeur​

Vous devez d'abord créer un routeur pour gérer vos requêtes, mutations et abonnements.

Un exemple de routeur est fourni ci-dessous - enregistrez-le dans un fichier router.ts.

router.ts
router.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import type { Context } from './context';
 
type User = {
id: string;
name: string;
bio?: string;
};
 
const users: Record<string, User> = {};
 
export const t = initTRPC.context<Context>().create();
 
export const appRouter = t.router({
getUserById: t.procedure.input(z.string()).query((opts) => {
return users[opts.input]; // input type is string
}),
createUser: t.procedure
// validate input with Zod
.input(
z.object({
name: z.string().min(3),
bio: z.string().max(142).optional(),
}),
)
.mutation((opts) => {
const id = Date.now().toString();
const user: User = { id, ...opts.input };
users[user.id] = user;
return user;
}),
});
 
// export type definition of API
export type AppRouter = typeof appRouter;
router.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import type { Context } from './context';
 
type User = {
id: string;
name: string;
bio?: string;
};
 
const users: Record<string, User> = {};
 
export const t = initTRPC.context<Context>().create();
 
export const appRouter = t.router({
getUserById: t.procedure.input(z.string()).query((opts) => {
return users[opts.input]; // input type is string
}),
createUser: t.procedure
// validate input with Zod
.input(
z.object({
name: z.string().min(3),
bio: z.string().max(142).optional(),
}),
)
.mutation((opts) => {
const id = Date.now().toString();
const user: User = { id, ...opts.input };
users[user.id] = user;
return user;
}),
});
 
// export type definition of API
export type AppRouter = typeof appRouter;

Si votre routeur devient trop volumineux, découpez-le en sous-routeurs autonomes dans des fichiers séparés, puis fusionnez-les dans un routeur racine appRouter.

Créer le contexte​

Vous devez ensuite définir un contexte généré pour chaque requête.

Exemple de contexte à enregistrer dans context.ts :

context.ts
context.ts
ts
import type { FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';
 
export function createContext({
req,
resHeaders,
}: FetchCreateContextFnOptions) {
const user = { name: req.headers.get('username') ?? 'anonymous' };
return { req, resHeaders, user };
}
 
export type Context = Awaited<ReturnType<typeof createContext>>;
context.ts
ts
import type { FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';
 
export function createContext({
req,
resHeaders,
}: FetchCreateContextFnOptions) {
const user = { name: req.headers.get('username') ?? 'anonymous' };
return { req, resHeaders, user };
}
 
export type Context = Awaited<ReturnType<typeof createContext>>;

Configuration spécifique au runtime​

Astro​

src/pages/trpc/[trpc].ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import type { APIRoute } from 'astro';
import { createContext } from '../../server/context';
import { appRouter } from '../../server/router';
 
export const ALL: APIRoute = (opts) => {
return fetchRequestHandler({
endpoint: '/trpc',
req: opts.request,
router: appRouter,
createContext,
});
};
src/pages/trpc/[trpc].ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import type { APIRoute } from 'astro';
import { createContext } from '../../server/context';
import { appRouter } from '../../server/router';
 
export const ALL: APIRoute = (opts) => {
return fetchRequestHandler({
endpoint: '/trpc',
req: opts.request,
router: appRouter,
createContext,
});
};

Cloudflare Worker​

note

L'outil Wrangler CLI est requis pour exécuter Cloudflare Workers.

Créer un Cloudflare Worker​

server.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from './context';
import { appRouter } from './router';
 
export default {
async fetch(request: Request): Promise<Response> {
return fetchRequestHandler({
endpoint: '/trpc',
req: request,
router: appRouter,
createContext,
});
},
};
server.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from './context';
import { appRouter } from './router';
 
export default {
async fetch(request: Request): Promise<Response> {
return fetchRequestHandler({
endpoint: '/trpc',
req: request,
router: appRouter,
createContext,
});
},
};

Exécutez wrangler dev server.ts : vos endpoints seront accessibles via HTTP !

EndpointHTTP URI
getUserGET http://localhost:8787/trpc/getUserById?input=INPUT

where INPUT is a URI-encoded JSON string.
createUserPOST http://localhost:8787/trpc/createUser

with req.body of type User

Deno Oak​

note

Ce guide suppose que Deno est installé et configuré. Consultez leur guide de démarrage pour plus d'informations.

Mettre à jour les imports dans router.ts​

router.ts
ts
import { initTRPC } from 'npm:@trpc/server';
import { z } from 'npm:zod';
import { Context } from './context.ts';
router.ts
ts
import { initTRPC } from 'npm:@trpc/server';
import { z } from 'npm:zod';
import { Context } from './context.ts';

Mettre à jour les imports dans context.ts​

context.ts
ts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.ts
ts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';

Utiliser fetchRequestHandler avec Oak dans app.ts​

app.ts
ts
import { Application, Router } from 'https://deno.land/x/oak/mod.ts';
import { fetchRequestHandler } from 'npm:@trpc/server/adapters/fetch';
import { createContext } from './context.ts';
import { appRouter } from './router.ts';
const app = new Application();
const router = new Router();
router.all('/trpc/(.*)', async (ctx) => {
const res = await fetchRequestHandler({
endpoint: '/trpc',
req: new Request(ctx.request.url, {
headers: ctx.request.headers,
body:
ctx.request.method !== 'GET' && ctx.request.method !== 'HEAD'
? ctx.request.body({ type: 'stream' }).value
: void 0,
method: ctx.request.method,
}),
router: appRouter,
createContext,
});
ctx.response.status = res.status;
ctx.response.headers = res.headers;
ctx.response.body = res.body;
});
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 3000 });
app.ts
ts
import { Application, Router } from 'https://deno.land/x/oak/mod.ts';
import { fetchRequestHandler } from 'npm:@trpc/server/adapters/fetch';
import { createContext } from './context.ts';
import { appRouter } from './router.ts';
const app = new Application();
const router = new Router();
router.all('/trpc/(.*)', async (ctx) => {
const res = await fetchRequestHandler({
endpoint: '/trpc',
req: new Request(ctx.request.url, {
headers: ctx.request.headers,
body:
ctx.request.method !== 'GET' && ctx.request.method !== 'HEAD'
? ctx.request.body({ type: 'stream' }).value
: void 0,
method: ctx.request.method,
}),
router: appRouter,
createContext,
});
ctx.response.status = res.status;
ctx.response.headers = res.headers;
ctx.response.body = res.body;
});
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 3000 });

Deno Deploy​

note

Ce guide suppose que Deno est installé et configuré. Consultez leur guide de démarrage pour plus d'informations.

astuce

Voir notre exemple d'application Deno Deploy fonctionnel.

Mettre à jour les imports dans router.ts​

router.ts
ts
import { initTRPC } from 'npm:@trpc/server';
import { z } from 'npm:zod';
import { Context } from './context.ts';
router.ts
ts
import { initTRPC } from 'npm:@trpc/server';
import { z } from 'npm:zod';
import { Context } from './context.ts';

Mettre à jour les imports dans context.ts​

context.ts
ts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.ts
ts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';

Créer une fonction Deno Deploy​

server.ts
ts
import { fetchRequestHandler } from 'npm:@trpc/server/adapters/fetch';
import { createContext } from './context.ts';
import { appRouter } from './router.ts';
function handler(request) {
return fetchRequestHandler({
endpoint: '/trpc',
req: request,
router: appRouter,
createContext,
});
}
Deno.serve(handler);
server.ts
ts
import { fetchRequestHandler } from 'npm:@trpc/server/adapters/fetch';
import { createContext } from './context.ts';
import { appRouter } from './router.ts';
function handler(request) {
return fetchRequestHandler({
endpoint: '/trpc',
req: request,
router: appRouter,
createContext,
});
}
Deno.serve(handler);

Exécutez deno run --allow-net=:8000 --allow-env ./server.ts et vos endpoints seront accessibles via HTTP !

EndpointHTTP URI
getUserGET http://localhost:8000/trpc/getUserById?input=INPUT

where INPUT is a URI-encoded JSON string.
createUserPOST http://localhost:8000/trpc/createUser

with req.body of type User

Next.js Edge Runtime​

Voir un exemple complet ici.

Remix​

app/routes/trpc.$trpc.ts
ts
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node';
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '~/server/context';
import { appRouter } from '~/server/router';
 
export const loader = async (args: LoaderFunctionArgs) => {
return handleRequest(args);
};
export const action = async (args: ActionFunctionArgs) => {
return handleRequest(args);
};
function handleRequest(args: LoaderFunctionArgs | ActionFunctionArgs) {
return fetchRequestHandler({
endpoint: '/trpc',
req: args.request,
router: appRouter,
createContext,
});
}
app/routes/trpc.$trpc.ts
ts
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node';
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '~/server/context';
import { appRouter } from '~/server/router';
 
export const loader = async (args: LoaderFunctionArgs) => {
return handleRequest(args);
};
export const action = async (args: ActionFunctionArgs) => {
return handleRequest(args);
};
function handleRequest(args: LoaderFunctionArgs | ActionFunctionArgs) {
return fetchRequestHandler({
endpoint: '/trpc',
req: args.request,
router: appRouter,
createContext,
});
}

SolidStart​

src/routes/api/trpc/[trpc].ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import type { APIEvent } from '@solidjs/start/server';
import { createContext } from '../../server/context';
import { appRouter } from '../../server/router';
 
const handler = (event: APIEvent) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req: event.request,
router: appRouter,
createContext,
});
export { handler as GET, handler as POST };
src/routes/api/trpc/[trpc].ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import type { APIEvent } from '@solidjs/start/server';
import { createContext } from '../../server/context';
import { appRouter } from '../../server/router';
 
const handler = (event: APIEvent) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req: event.request,
router: appRouter,
createContext,
});
export { handler as GET, handler as POST };

Vercel Edge Runtime​

note

Consultez la documentation officielle Vercel Edge Runtime pour plus d'informations.

astuce

Voir notre exemple d'application Vercel Edge Runtime fonctionnel.

Installer les dépendances​

sh
npm install -g edge-runtime
sh
npm install -g edge-runtime

Créer une fonction Edge Runtime​

server.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from './context';
import { appRouter } from './router';
 
// Vercel Edge Runtime uses Service Worker-style addEventListener
addEventListener('fetch', (event: any) => {
return event.respondWith(
fetchRequestHandler({
endpoint: '/trpc',
req: event.request,
router: appRouter,
createContext,
}),
);
});
server.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from './context';
import { appRouter } from './router';
 
// Vercel Edge Runtime uses Service Worker-style addEventListener
addEventListener('fetch', (event: any) => {
return event.respondWith(
fetchRequestHandler({
endpoint: '/trpc',
req: event.request,
router: appRouter,
createContext,
}),
);
});

Exécutez edge-runtime --listen server.ts --port 3000 et vos endpoints seront accessibles via HTTP !

EndpointHTTP URI
getUserGET http://localhost:3000/trpc/getUserById?input=INPUT

where INPUT is a URI-encoded JSON string.
createUserPOST http://localhost:3000/trpc/createUser

with req.body of type User