Use Cases

tRPC API dengan Claude Code

Pelajari tentang trpc api menggunakan Claude Code. Dilengkapi tips praktis dan contoh kode.

tRPCでtype safetyなAPIpengembanganを実現

tRPC server dan client間 型 自動berbagi framework.Claude Code tRPC ルーター設計 dari プロシージャ implementasiま 、type safetyな構成 一貫 generate くれ.

dasar的なルーター構成

Claude Code ルーター 構成 依頼し.

> tRPC ルーター 設計して。
> penggunaCRUD、認証middleware、inputvalidasi付き dengan 。
import { initTRPC, TRPCError } from "@trpc/server";
import { z } from "zod";

type Context = {
  session: { userId: string; role: string } | null;
  db: PrismaClient;
};

const t = initTRPC.context<Context>().create();

// middleware
const isAuthenticated = t.middleware(({ ctx, next }) => {
  if (!ctx.session) {
    throw new TRPCError({ code: "UNAUTHORIZED" });
  }
  return next({ ctx: { ...ctx, session: ctx.session } });
});

const protectedProcedure = t.procedure.use(isAuthenticated);

// penggunaルーター
export const userRouter = t.router({
  list: protectedProcedure
    .input(
      z.object({
        page: z.number().int().positive().default(1),
        perPage: z.number().int().min(1).max(100).default(20),
        search: z.string().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const { page, perPage, search } = input;
      const where = search
        ? { name: { contains: search, mode: "insensitive" as const } }
        : {};

      const [users, total] = await Promise.all([
        ctx.db.user.findMany({
          where,
          skip: (page - 1) * perPage,
          take: perPage,
          orderBy: { createdAt: "desc" },
        }),
        ctx.db.user.count({ where }),
      ]);

      return { users, total, totalPages: Math.ceil(total / perPage) };
    }),

  getById: protectedProcedure
    .input(z.object({ id: z.string().uuid() }))
    .query(async ({ ctx, input }) => {
      const user = await ctx.db.user.findUnique({
        where: { id: input.id },
      });
      if (!user) throw new TRPCError({ code: "NOT_FOUND" });
      return user;
    }),

  create: protectedProcedure
    .input(
      z.object({
        name: z.string().min(2).max(50),
        email: z.string().email(),
        role: z.enum(["admin", "editor", "viewer"]),
      })
    )
    .mutation(async ({ ctx, input }) => {
      return ctx.db.user.create({ data: input });
    }),

  update: protectedProcedure
    .input(
      z.object({
        id: z.string().uuid(),
        name: z.string().min(2).max(50).optional(),
        email: z.string().email().optional(),
        role: z.enum(["admin", "editor", "viewer"]).optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { id, ...data } = input;
      return ctx.db.user.update({ where: { id }, data });
    }),
});

type safetyな呼び出し client側

tRPC 最大 keuntungan 、client側 server 型 そ まま使えるこ dan .

import { createTRPCReact } from "@trpc/react-query";
import type { AppRouter } from "../server/router";

export const trpc = createTRPCReact<AppRouter>();

function UserList() {
  const { data, isLoading } = trpc.user.list.useQuery({
    page: 1,
    perPage: 20,
  });

  const createUser = trpc.user.create.useMutation({
    onSuccess: () => {
      utils.user.list.invalidate();
    },
  });

  const utils = trpc.useUtils();

  if (isLoading) return <div>読み込み中...</div>;

  return (
    <div>
      {data?.users.map((user) => (
        <div key={user.id}>
          <span>{user.name}</span>
          <span>{user.email}</span>
        </div>
      ))}
    </div>
  );
}

設計 errorハンドリング

Claude Code errorハンドリング mekanisme juga 設計 juga らい.

import { TRPCError } from "@trpc/server";

// カスタムerrorformatter
const t = initTRPC.context<Context>().create({
  errorFormatter({ shape, error }) {
    return {
      ...shape,
      data: {
        ...shape.data,
        zodError:
          error.cause instanceof ZodError ? error.cause.flatten() : null,
      },
    };
  },
});

// error キャッチmiddleware
const errorHandler = t.middleware(async ({ next }) => {
  try {
    return await next();
  } catch (error) {
    if (error instanceof TRPCError) throw error;

    console.error("Unexpected error:", error);
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "予期せぬerror 発生しま",
    });
  }
});

subscription(リアルタイム通信)

WebSocket経由 リアルタイム通信 juga tRPC type safety implementasi bisa dilakukan.

import { observable } from "@trpc/server/observable";

export const notificationRouter = t.router({
  onNew: protectedProcedure.subscription(({ ctx }) => {
    return observable<Notification>((emit) => {
      const handler = (notification: Notification) => {
        if (notification.userId === ctx.session.userId) {
          emit.next(notification);
        }
      };

      eventEmitter.on("notification", handler);
      return () => eventEmitter.off("notification", handler);
    });
  }),
});

Summary

tRPC dan Claude Code 組み合わせ 、type safetyなfull-stackpengembangan 最速 実現 手段.Zod よるinputvalidasi dan integrasi 、runtime keamanan juga 同時 確保 bisa dilakukan.

inputvalidasi 詳細 Zodvalidasi実践panduan 、client側 データpengambilan TanStack Querypemanfaatanpanduan silakan lihat.tRPC公式dokumen juga 併せてkonfirmasiし.

#Claude Code #tRPC #TypeScript #API #type safety