Skip to main content
Version: 10.x

获取/边缘运行时适配器

你可以在遵循 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 提供了 获取适配器,它使用原生 RequestResponse 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:

  • RequestResponse

  • 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.

sh
npm install @trpc/server zod
sh
npm install @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.ts
ts
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 API
export type AppRouter = typeof appRouter;
router.ts
ts
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 API
export 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.ts
ts
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.ts
ts
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].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

注意

你需要 Wrangler CLI 才能运行 Cloudflare Workers。

¥You need the Wrangler CLI to run Cloudflare Workers.

创建 Cloudflare Worker

¥Create 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,
});
},
};

运行 wrangler dev server.ts,你的端点将通过 HTTP 可用!

¥Run wrangler dev server.ts and your endpoints will be available via HTTP!

端点HTTP URI
getUserGET http://localhost:8787/trpc/getUserById?input=INPUT

,其中 INPUT 是 URI 编码的 JSON 字符串。
createUserPOST 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.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';

更新 context.ts 中的导入

¥Update the imports in context.ts

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

fetchRequestHandlerapp.ts 中的橡木一起使用

¥Use fetchRequestHandler with Oak in 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 部署

¥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.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';

更新 context.ts 中的导入

¥Update the imports in context.ts

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

创建 Deno 部署函数

¥Create Deno Deploy Function

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);

运行 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
getUserGET http://localhost:8000/trpc/getUserById?input=INPUT

,其中 INPUT 是 URI 编码的 JSON 字符串。
createUserPOST http://localhost:8000/trpc/createUser

User 类型的 req.body

Next.js 边缘运行时

¥Next.js Edge Runtime

请参阅完整示例 此处

¥See a full example here.

Remix

app/routes/trpc/$trpc.ts
ts
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.ts
ts
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].ts
ts
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].ts
ts
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

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

创建边缘运行时函数

¥Create Edge Runtime Function

server.ts
ts
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.ts
ts
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
getUserGET http://localhost:3000/trpc/getUserById?input=INPUT

,其中 INPUT 是 URI 编码的 JSON 字符串。
createUserPOST http://localhost:3000/trpc/createUser

User 类型的 req.body