-
transformer
- Data Transformers,序列化响应数据和输入的参数
- 安装 superjson,版本 "superjson": "^2.2.2"
- 修改文件
src/trpc/client.tsx,src/trpc/query-client.tsx ,通过 import superjson from 'superjson'; 添加 superjson
-
Add auth to tRPC context
...
import superjson from 'superjson';
import { auth } from '@clerk/nextjs/server';
export const createTRPCContext = cache(async () => {
const { userId } = await auth();
return { clerkUserId: userId };
});
- 类型推导 Type Inference
- 不需要手动写类型,它会根据代码上下文,自动判断出变量、函数、返回值的类型
- 编译阶段就做好 “静态安全检查”,避免出现取错值、空值或者数据结构发生改变的状态
export type Context = Awaited<ReturnType<typeof createTRPCContext>>;
const t = initTRPC.context<Context>().create({
transformer: superjson,
});
-
Add protectedProcedure & rate limiting
t.procedure.use() 使用中间件鉴权
- clerk 与 数据库
users 的数据是同步的,所以都需要验证
- upstash - the Nextjs Example
- 版本信息:"@upstash/redis": "^1.35.3"、"@upstash/ratelimit": "^2.0.6"
import { Redis } from '@upstash/redis';
export const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
import { Ratelimit } from '@upstash/ratelimit'
import { redis } from './redis'
export const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, '10s'),
})
import { initTRPC, TRPCError } from '@trpc/server';
...
import { auth } from '@clerk/nextjs/server';
import { db } from '@/db';
import { eq } from 'drizzle-orm';
import { users } from '@/db/schema';
import { ratelimit } from '@/lib/ratelimit';
...
...
export const protectedProcedure = t.procedure.use(async function isAuthed(opts) {
const {ctx} = opts;
if (!ctx.clerkUserId) throw new TRPCError({ code: 'UNAUTHORIZED' });
const [user] = await db
.select()
.from(users)
.where(eq(users.clerkId, ctx.clerkUserId))
.limit(1);
if (!user) throw new TRPCError({ code: 'UNAUTHORIZED' });
const {success} = await ratelimit.limit(user.id);
if(!success) throw new TRPCError({code: 'TOO_MANY_REQUESTS'});
return opts.next({
ctx: {
...ctx,
user
},
})
})