获取/边缘运行时适配器
你可以在遵循 WinterCG(特别是 最低通用 Web 平台 API 规范)的任何边缘运行时中创建 tRPC 服务器。
¥You can create a tRPC server within any edge runtime that follow the WinterCG, specifically the Minimum Common Web Platform API specification.
其中一些运行时包括但不限于:
¥Some of these runtimes includes, but not limited to:
Cloudflare Workers
Deno 部署
¥Deno Deploy
Vercel Edge 运行时(和 Next.js Edge 运行时)
¥Vercel Edge Runtime (& Next.js Edge Runtime)
这也使得可以轻松集成到使用 Web 平台 API 来表示请求和响应的框架中,例如:
¥This also makes it easy to integrate into frameworks that uses the web platform APIs to represent requests and responses, such as:
Astro(SSR 模式)
¥Astro (SSR mode)
Remix
SolidStart
示例应用
¥Example apps
描述 | 链接 |
---|---|
Cloudflare Workers 示例 | 来源 |
Deno 部署示例 | 来源 |
Next.js Edge 运行时示例 | 来源 |
Vercel Edge 运行时示例 | 来源 |
如何将 tRPC 服务器与边缘运行时结合使用
¥How to use tRPC server with an edge runtime
tRPC 提供了 获取适配器,它使用原生 Request
和 Response
API 作为输入和输出。tRPC 特定的代码在所有运行时都是相同的,唯一的区别在于返回响应的方式。
¥tRPC provides a fetch adapter that uses the native Request
and Response
APIs as input and output. The tRPC-specific code is the same across all runtimes, the only difference being how the response is returned.
tRPC 包含一个用于开箱即用的原生 获取 API 适配器。该适配器允许你将 tRPC 路由转换为返回 Response
对象的 Request
处理程序。
¥tRPC includes an adapter for the native Fetch API out of the box. This adapter lets you convert your tRPC router into a Request
handler that returns Response
objects.
所需的 Web API
¥Required Web APIs
tRPC 服务器使用以下 Fetch API:
¥tRPC server uses the following Fetch APIs:
Request
、Response
fetch
Headers
URL
如果你的运行时支持这些 API,你可以 使用 tRPC 服务器。
¥If your runtime supports these APIs, you can use tRPC server.
有趣的事实:这也意味着你可以在浏览器中使用 tRPC 服务器!
¥Fun fact: that also means you can use a tRPC server in your browser!
通用设置
¥Common setup
安装依赖
¥Install dependencies
如果你使用 Deno Deploy,则可以跳过此步骤。
¥You can skip this step if you use Deno Deploy.
- npm
- yarn
- pnpm
- bun
sh
npm install @trpc/server zod
sh
npm install @trpc/server zod
sh
yarn add @trpc/server zod
sh
yarn add @trpc/server zod
sh
pnpm add @trpc/server zod
sh
pnpm add @trpc/server zod
sh
bun add @trpc/server zod
sh
bun add @trpc/server zod
Zod 不是必需的依赖,但它在下面的示例路由中使用。
¥Zod isn't a required dependency, but it's used in the sample router below.
创建路由
¥Create the router
首先,你需要一个 router 来处理你的查询、突变和订阅。
¥First of all you need a router to handle your queries, mutations and subscriptions.
下面给出了一个示例路由,将其保存在名为 router.ts
.txt 的文件中。
¥A sample router is given below, save it in a file named router.ts
.
router.ts
router.tsts
import { initTRPC } from '@trpc/server';import { z } from 'zod';import { 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 APIexport type AppRouter = typeof appRouter;
router.tsts
import { initTRPC } from '@trpc/server';import { z } from 'zod';import { 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 APIexport type AppRouter = typeof appRouter;
如果你的路由文件开始变得太大,请将你的路由拆分为多个子路由,每个子路由都在自己的文件中实现。然后将 合并它们 变成单根 appRouter
。
¥If your router file starts getting too big, split your router into several subrouters each implemented in its own file. Then merge them into a single root appRouter
.
创建上下文
¥Create the context
然后你需要为每个请求创建一个 context。
¥Then you need a context that will be created for each request.
下面给出了一个示例上下文,将其保存在名为 context.ts
的文件中:
¥A sample context is given below, save it in a file named context.ts
:
context.ts
context.tsts
import { 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.tsts
import { 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>>;
特定于运行时的设置
¥Runtimes-specific setup
Astro
src/pages/trpc/[trpc].tsts
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].tsts
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
你需要 Wrangler CLI 才能运行 Cloudflare Workers。
¥You need the Wrangler CLI to run Cloudflare Workers.
创建 Cloudflare Worker
¥Create Cloudflare Worker
server.tsts
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.tsts
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,});},};
运行 wrangler dev server.ts
,你的端点将通过 HTTP 可用!
¥Run wrangler dev server.ts
and your endpoints will be available via HTTP!
端点 | HTTP URI |
---|---|
getUser | GET http://localhost:8787/trpc/getUserById?input=INPUT ,其中 INPUT 是 URI 编码的 JSON 字符串。 |
createUser | POST http://localhost:8787/trpc/createUser 与 User 类型的 req.body |
Deno Oak
这假设你已经安装并设置了 Deno。请参阅他们的 入门指南 了解更多信息。
¥This assumes you have Deno installed and setup. Refer to their getting started guide for more information.
更新 router.ts
中的导入
¥Update the imports in router.ts
router.tsts
import { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
router.tsts
import { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
更新 context.ts
中的导入
¥Update the imports in context.ts
context.tsts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.tsts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
将 fetchRequestHandler
与 app.ts
中的橡木一起使用
¥Use fetchRequestHandler
with Oak in app.ts
app.tsts
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.tsts
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 部署
¥Deno Deploy
这假设你已经安装并设置了 Deno。请参阅他们的 入门指南 了解更多信息。
¥This assumes you have Deno installed and setup. Refer to their getting started guide for more information.
有关工作示例,请参阅我们的示例 Deno 部署应用。
¥See our example Deno Deploy app for a working example.
更新 router.ts
中的导入
¥Update the imports in router.ts
router.tsts
import { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
router.tsts
import { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
更新 context.ts
中的导入
¥Update the imports in context.ts
context.tsts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.tsts
import { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
创建 Deno 部署函数
¥Create Deno Deploy Function
server.tsts
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.tsts
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);
运行 deno run --allow-net=:8000 --allow-env ./server.ts
,你的端点将通过 HTTP 可用!
¥Run deno run --allow-net=:8000 --allow-env ./server.ts
and your endpoints will be available via HTTP!
端点 | HTTP URI |
---|---|
getUser | GET http://localhost:8000/trpc/getUserById?input=INPUT ,其中 INPUT 是 URI 编码的 JSON 字符串。 |
createUser | POST http://localhost:8000/trpc/createUser 与 User 类型的 req.body |
Next.js 边缘运行时
¥Next.js Edge Runtime
请参阅完整示例 此处。
¥See a full example here.
Remix
app/routes/trpc/$trpc.tsts
import type { ActionArgs, LoaderArgs } 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: LoaderArgs) => {return handleRequest(args);};export const action = async (args: ActionArgs) => {return handleRequest(args);};function handleRequest(args: LoaderArgs | ActionArgs) {return fetchRequestHandler({endpoint: '/trpc',req: args.request,router: appRouter,createContext,});}
app/routes/trpc/$trpc.tsts
import type { ActionArgs, LoaderArgs } 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: LoaderArgs) => {return handleRequest(args);};export const action = async (args: ActionArgs) => {return handleRequest(args);};function handleRequest(args: LoaderArgs | ActionArgs) {return fetchRequestHandler({endpoint: '/trpc',req: args.request,router: appRouter,createContext,});}
SolidStart
src/routes/api/trpc/[trpc].tsts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';import type { APIEvent } from 'solid-start';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].tsts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';import type { APIEvent } from 'solid-start';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 边缘运行时
¥Vercel Edge Runtime
更多信息请参见官方 Vercel Edge 运行时文档。
¥See the official Vercel Edge Runtime documentation for more information.
有关工作示例,请参阅我们的示例 Vercel Edge 运行时应用。
¥See our example Vercel Edge Runtime app for a working example.
安装依赖
¥Install dependencies
- npm
- yarn
- pnpm
- bun
sh
npm install -g edge-runtime
sh
npm install -g edge-runtime
sh
yarn global add edge-runtime
sh
yarn global add edge-runtime
sh
pnpm add -g edge-runtime
sh
pnpm add -g edge-runtime
sh
bun add -g edge-runtime
sh
bun add -g edge-runtime
创建边缘运行时函数
¥Create Edge Runtime Function
server.tsts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';import { createContext } from './context';import { appRouter } from './router';addEventListener('fetch', (event) => {return event.respondWith(fetchRequestHandler({endpoint: '/trpc',req: event.request,router: appRouter,createContext,}),);});
server.tsts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';import { createContext } from './context';import { appRouter } from './router';addEventListener('fetch', (event) => {return event.respondWith(fetchRequestHandler({endpoint: '/trpc',req: event.request,router: appRouter,createContext,}),);});
运行 edge-runtime --listen server.ts --port 3000
,你的端点将通过 HTTP 可用!
¥Run edge-runtime --listen server.ts --port 3000
and your endpoints will be available via HTTP!
端点 | HTTP URI |
---|---|
getUser | GET http://localhost:3000/trpc/getUserById?input=INPUT ,其中 INPUT 是 URI 编码的 JSON 字符串。 |
createUser | POST http://localhost:3000/trpc/createUser 与 User 类型的 req.body |