Tube - tRPC Configuration

  • 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
    • tRPC context 包含所有 tRPC 过程都可以访问的数据,常见的数据有用户信息、权限、数据库连接等
    ...
    import superjson from 'superjson';
    import { auth } from '@clerk/nextjs/server';
    
    // 创建tRPC上下文
    // 该函数会在每个请求中被调用
    // cache() 会在服务端请求中缓存这个异步函数的结果,避免重复执行
    // auth() 获取用户信息
    export const createTRPCContext = cache(async () => {
      const { userId } = await auth(); 
      return { clerkUserId: userId };
    });
    
    • 类型推导 Type Inference
      • 不需要手动写类型,它会根据代码上下文,自动判断出变量、函数、返回值的类型
      • 编译阶段就做好 “静态安全检查”,避免出现取错值、空值或者数据结构发生改变的状态
    // tRPC类型推导
    // typeof createTRPCContext 结果:() => Promise<{ clerkUserId: string | null; }>
    // ReturnType<typeof createTRPCContext>  获取函数返回类型,是Promise类型
    // Awaited<> ts内置的类型工具,可提取Promise的返回值类型
    // 结合起来,最终的结果是 { clerkUserId: string | null; }
    export type Context = Awaited<ReturnType<typeof createTRPCContext>>;
    
    • 创建tRPC实例
    // 创建tRPC实例
    // 将 Context 类型注入到所有 procedure 的上下文中
    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"
// src/lib/redis.ts

import { Redis } from '@upstash/redis';

export const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
// src/lib/ratelimit.ts

import { Ratelimit } from '@upstash/ratelimit'
import { redis } from './redis'

export const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(10, '10s'), // 10 requests per 10 seconds
})
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';
...
...
// 中间件式鉴权
// t.procedure.use()  使用中间件的方式
export const protectedProcedure = t.procedure.use(async function isAuthed(opts) {
  const {ctx} = opts;

  if (!ctx.clerkUserId) throw new TRPCError({ code: 'UNAUTHORIZED' }); // 自动返回401

  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.clerkId, ctx.clerkUserId))
    .limit(1);
  
  if (!user) throw new TRPCError({ code: 'UNAUTHORIZED' }); // 自动返回401

  const {success} = await ratelimit.limit(user.id);

  if(!success) throw new TRPCError({code: 'TOO_MANY_REQUESTS'});

  // 请求继续,进入实际的处理函数(resolver)
  return opts.next({
    ctx: {
      ...ctx,
      user
    },
  })
})
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容