Fetch / 边缘运行时适配器
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
您可以在遵循 WinterCG 规范的任何边缘运行时中创建 tRPC 服务器,特别是符合 最小通用 Web 平台 API 规范的运行时。
部分运行时包括(但不限于):
-
Cloudflare Workers
-
Deno Deploy
-
Vercel Edge Runtime (& Next.js Edge Runtime)
这同时也简化了与以下框架的集成,这些框架采用 Web 平台 API 来表示请求和响应:
-
Astro (SSR 模式)
-
Remix
-
SolidStart
示例应用
| Description | Links |
|---|---|
| Cloudflare Workers example | Source |
| Deno Deploy example | Source |
| Next.js Edge Runtime example | Source |
| Vercel Edge Runtime example | Source |
如何在边缘运行时中使用 tRPC 服务器
tRPC 提供了 fetch 适配器,它使用原生 Request 和 Response API 作为输入输出。所有运行时的 tRPC 核心代码相同,仅响应返回方式存在差异。
tRPC 开箱即用地提供了原生 Fetch API 适配器。该适配器可将您的 tRPC 路由转换为返回 Response 对象的 Request 处理器。
必需的 Web API
tRPC 服务器使用以下 Fetch API:
-
Request,Response -
fetch -
Headers -
URL
若您的运行时支持这些 API,即可使用 tRPC 服务器。
冷知识:这也意味着您能在浏览器中运行 tRPC 服务器!
通用设置
安装依赖
若使用 Deno Deploy 可跳过此步骤。
- npm
- yarn
- pnpm
- bun
- deno
npm install @trpc/server @trpc/client zod
yarn add @trpc/server @trpc/client zod
pnpm add @trpc/server @trpc/client zod
bun add @trpc/server @trpc/client zod
deno add npm:@trpc/server npm:@trpc/client npm:zod
Zod 并非必需依赖,但下方示例路由中会使用到。
若您使用 AI 编程代理,请安装 tRPC 技能以优化代码生成效果:
bashnpx @tanstack/intent@latest install
bashnpx @tanstack/intent@latest install
创建路由器
首先需要创建路由来处理查询、变更和订阅操作。
下面提供了示例路由器,将其保存为 router.ts 文件:
router.ts
router.tstsimport {initTRPC } from '@trpc/server';import {z } from 'zod';import type {Context } from './context';typeUser = {id : string;name : string;bio ?: string;};constusers :Record <string,User > = {};export constt =initTRPC .context <Context >().create ();export constappRouter =t .router ({getUserById :t .procedure .input (z .string ()).query ((opts ) => {returnusers [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 ) => {constid =Date .now ().toString ();constuser :User = {id , ...opts .input };users [user .id ] =user ;returnuser ;}),});// export type definition of APIexport typeAppRouter = typeofappRouter ;
router.tstsimport {initTRPC } from '@trpc/server';import {z } from 'zod';import type {Context } from './context';typeUser = {id : string;name : string;bio ?: string;};constusers :Record <string,User > = {};export constt =initTRPC .context <Context >().create ();export constappRouter =t .router ({getUserById :t .procedure .input (z .string ()).query ((opts ) => {returnusers [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 ) => {constid =Date .now ().toString ();constuser :User = {id , ...opts .input };users [user .id ] =user ;returnuser ;}),});// export type definition of APIexport typeAppRouter = typeofappRouter ;
若路由文件过大,可将其拆分为多个独立文件实现的子路由,然后合并为单一根路由 appRouter。
创建上下文
接着需要为每个请求创建上下文。
下面提供了示例上下文,将其保存为 context.ts 文件:
context.ts
context.tstsimport type {FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';export functioncreateContext ({req ,resHeaders ,}:FetchCreateContextFnOptions ) {constuser = {name :req .headers .get ('username') ?? 'anonymous' };return {req ,resHeaders ,user };}export typeContext =Awaited <ReturnType <typeofcreateContext >>;
context.tstsimport type {FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';export functioncreateContext ({req ,resHeaders ,}:FetchCreateContextFnOptions ) {constuser = {name :req .headers .get ('username') ?? 'anonymous' };return {req ,resHeaders ,user };}export typeContext =Awaited <ReturnType <typeofcreateContext >>;
运行时特定设置
Astro
src/pages/trpc/[trpc].tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import type {APIRoute } from 'astro';import {createContext } from '../../server/context';import {appRouter } from '../../server/router';export constALL :APIRoute = (opts ) => {returnfetchRequestHandler ({endpoint : '/trpc',req :opts .request ,router :appRouter ,createContext ,});};
src/pages/trpc/[trpc].tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import type {APIRoute } from 'astro';import {createContext } from '../../server/context';import {appRouter } from '../../server/router';export constALL :APIRoute = (opts ) => {returnfetchRequestHandler ({endpoint : '/trpc',req :opts .request ,router :appRouter ,createContext ,});};
Cloudflare Worker
运行 Cloudflare Workers 需安装 Wrangler CLI。
创建 Cloudflare Worker
server.tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import {createContext } from './context';import {appRouter } from './router';export default {asyncfetch (request :Request ):Promise <Response > {returnfetchRequestHandler ({endpoint : '/trpc',req :request ,router :appRouter ,createContext ,});},};
server.tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import {createContext } from './context';import {appRouter } from './router';export default {asyncfetch (request :Request ):Promise <Response > {returnfetchRequestHandler ({endpoint : '/trpc',req :request ,router :appRouter ,createContext ,});},};
执行 wrangler dev server.ts 命令后,您的端点将通过 HTTP 提供服务!
| Endpoint | HTTP URI |
|---|---|
getUser | GET http://localhost:8787/trpc/getUserById?input=INPUT where INPUT is a URI-encoded JSON string. |
createUser | POST http://localhost:8787/trpc/createUser with req.body of type User |
Deno Oak
本指南假设您已安装并配置好 Deno 环境。更多信息请参考 Deno 的入门指南。
更新 router.ts 中的导入语句
router.tstsimport { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
router.tstsimport { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
更新 context.ts 中的导入语句
context.tstsimport { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.tstsimport { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
在 Oak 中使用 fetchRequestHandler(位于 app.ts)
app.tstsimport { 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.tstsimport { 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
本指南假设您已安装并配置好 Deno 环境。更多信息请参考 Deno 的入门指南。
完整示例请参考我们的 Deno Deploy 应用示例。
更新 router.ts 中的导入语句
router.tstsimport { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
router.tstsimport { initTRPC } from 'npm:@trpc/server';import { z } from 'npm:zod';import { Context } from './context.ts';
更新 context.ts 中的导入语句
context.tstsimport { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
context.tstsimport { FetchCreateContextFnOptions } from 'npm:@trpc/server/adapters/fetch';
创建 Deno Deploy 函数
server.tstsimport { 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.tstsimport { 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,您的 API 端点将通过 HTTP 提供服务!
| Endpoint | HTTP URI |
|---|---|
getUser | GET http://localhost:8000/trpc/getUserById?input=INPUT where INPUT is a URI-encoded JSON string. |
createUser | POST http://localhost:8000/trpc/createUser with req.body of type User |
Next.js Edge Runtime
完整示例请参考此处。
Remix
app/routes/trpc.$trpc.tstsimport 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 constloader = async (args :LoaderFunctionArgs ) => {returnhandleRequest (args );};export constaction = async (args :ActionFunctionArgs ) => {returnhandleRequest (args );};functionhandleRequest (args :LoaderFunctionArgs |ActionFunctionArgs ) {returnfetchRequestHandler ({endpoint : '/trpc',req :args .request ,router :appRouter ,createContext ,});}
app/routes/trpc.$trpc.tstsimport 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 constloader = async (args :LoaderFunctionArgs ) => {returnhandleRequest (args );};export constaction = async (args :ActionFunctionArgs ) => {returnhandleRequest (args );};functionhandleRequest (args :LoaderFunctionArgs |ActionFunctionArgs ) {returnfetchRequestHandler ({endpoint : '/trpc',req :args .request ,router :appRouter ,createContext ,});}
SolidStart
src/routes/api/trpc/[trpc].tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import type {APIEvent } from '@solidjs/start/server';import {createContext } from '../../server/context';import {appRouter } from '../../server/router';consthandler = (event :APIEvent ) =>fetchRequestHandler ({endpoint : '/api/trpc',req :event .request ,router :appRouter ,createContext ,});export {handler asGET ,handler asPOST };
src/routes/api/trpc/[trpc].tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import type {APIEvent } from '@solidjs/start/server';import {createContext } from '../../server/context';import {appRouter } from '../../server/router';consthandler = (event :APIEvent ) =>fetchRequestHandler ({endpoint : '/api/trpc',req :event .request ,router :appRouter ,createContext ,});export {handler asGET ,handler asPOST };
Vercel Edge Runtime
更多信息请参阅官方 Vercel Edge Runtime 文档。
完整示例请参考我们的 Vercel Edge Runtime 应用示例。
安装依赖
- npm
- yarn
- pnpm
- bun
shnpm install -g edge-runtime
shnpm install -g edge-runtime
shyarn global add edge-runtime
shyarn global add edge-runtime
shpnpm add -g edge-runtime
shpnpm add -g edge-runtime
shbun add -g edge-runtime
shbun add -g edge-runtime
创建 Edge Runtime 函数
server.tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import {createContext } from './context';import {appRouter } from './router';// Vercel Edge Runtime uses Service Worker-style addEventListeneraddEventListener ('fetch', (event : any) => {returnevent .respondWith (fetchRequestHandler ({endpoint : '/trpc',req :event .request ,router :appRouter ,createContext ,}),);});
server.tstsimport {fetchRequestHandler } from '@trpc/server/adapters/fetch';import {createContext } from './context';import {appRouter } from './router';// Vercel Edge Runtime uses Service Worker-style addEventListeneraddEventListener ('fetch', (event : any) => {returnevent .respondWith (fetchRequestHandler ({endpoint : '/trpc',req :event .request ,router :appRouter ,createContext ,}),);});
执行命令 edge-runtime --listen server.ts --port 3000,您的 API 端点将通过 HTTP 提供服务!
| Endpoint | HTTP URI |
|---|---|
getUser | GET http://localhost:3000/trpc/getUserById?input=INPUT where INPUT is a URI-encoded JSON string. |
createUser | POST http://localhost:3000/trpc/createUser with req.body of type User |