Skip to main content

trpc

  • trpc/trpc
  • @trpc/next - NextJS
  • spec
  • 参考
    • jlalmes/trpc-openapi
      • 使用 meta 定义路由
        • .meta({openapi: { method: 'GET', path: '/say-hello', headers: [] } })
      • 使用 zod 定义 input 和 output
      • 创建新的路由
      • 路由忽略大小写,忽略 Trailing slashes
      • API Handler
        • createOpenApiNextHandler
        • createOpenApiHttpHandler - node:http
        • createExpressMiddleware
        • ⚠️ 暂不支持 fastify - jlalmes/trpc-openapi#87
      • generateOpenApiDocument 生成 Schema
caution
info
npm add @trpc/client @trpc/server
import * as trpc from '@trpc/server';
import { z } from 'zod';

const appRouter = trpc
.router()
.query('getUser', {
input: (val: unknown) => {
if (typeof val === 'string') return val;
throw new Error(`Invalid input: ${typeof val}`);
},
async resolve(req) {
req.input; // string
return { id: req.input, name: 'Bilbo' };
},
})
.mutation('createUser', {
// validate input with Zod
input: z.object({ name: z.string().min(5) }),
async resolve(req) {
// use your ORM of choice
return await UserModel.create({
data: req.input,
});
},
});

export type AppRouter = typeof appRouter;
  • 适配 - https://github.com/trpc/trpc/tree/main/packages/server/src/adapters
    • next
      • createNextApiHandler
    • standalone
      • createHTTPHandler
      • createHTTPServer
    • ws
      • applyWSSHandler
      • 基于 ws 包
    • fastify
      • fastifyTRPCPlugin
      • fastifyRequestHandler
    • express
      • createExpressMiddleware
    • node-http
      • nodeHTTPRequestHandler
    • aws-lambda
    • fetch
      • fetchRequestHandler
    • lambda

fastify

context.ts
import { inferAsyncReturnType } from '@trpc/server';
import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';

export function createContext({ req, res }: CreateFastifyContextOptions) {
const user = { name: req.headers.username ?? 'anonymous' };

return { req, res, user };
}

export type Context = inferAsyncReturnType<typeof createContext>;
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
import fastify from 'fastify';
import { createContext } from './context';
import { appRouter } from './router';
import ws from '@fastify/websocket';

const server = fastify({
maxParamLength: 5000,
});

// 支持 subscription
server.register(ws);

server.register(fastifyTRPCPlugin, {
prefix: '/trpc',
trpcOptions: { router: appRouter, createContext },
});

(async () => {
try {
await server.listen(3000);
} catch (err) {
server.log.error(err);
process.exit(1);
}
})();

openapi

import { initTRPC } from '@trpc/server';
import { OpenApiMeta } from 'trpc-openapi';
const t = initTRPC.meta<OpenApiMeta>().create();
export const appRouter = t.router({
sayHello: t.procedure
// 定义接口
.meta({ /* 👉 */ openapi: { method: 'GET', path: '/say-hello' } })
.input(z.object({ name: z.string() }))
.output(z.object({ greeting: z.string() }))
.query(({ input }) => {
return { greeting: `Hello ${input.name}!` };
});
});

// 生成
export const openApiDocument = generateOpenApiDocument(appRouter, {
title: 'tRPC OpenAPI',
version: '1.0.0',
baseUrl: 'http://localhost:3000',
});

import http from 'http';
import { createOpenApiHttpHandler } from 'trpc-openapi';

// 服务端
const server = http.createServer(createOpenApiHttpHandler({ router: appRouter })); /* 👈 */
server.listen(3000);

FAQ

Rollup typing

typebox

import { TypeCompiler } from '@sinclair/typebox/compiler';
import { Type, TSchema } from '@sinclair/typebox';
import { initTRPC } from '@trpc/server';

export function Compile<T extends TSchema>(schema: T, references: TSchema[] = []) {
const check = TypeCompiler.Compile(schema, references);
return (input: unknown) => {
if (check.Check(input)) return input;
throw Error('Invalid Input');
};
}

const t = initTRPC.create();

const appRouter = t.router({
hello: t.procedure.input(Compile(Type.Number())).query(({ input }) => {
console.log(input);
}),
});