From f0ae8196cd0b2bd22d68035bd16402f999d2ba13 Mon Sep 17 00:00:00 2001 From: imbytecat Date: Sun, 18 Jan 2026 03:20:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=20zod=20=E5=90=88?= =?UTF-8?q?=E7=BA=A6=E5=AE=9E=E7=8E=B0=E7=B1=BB=E5=9E=8B=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E7=9A=84=20todo=20=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 @orpc/contract 依赖以支持合约定义和类型安全。 - 添加 @orpc/contract 依赖以支持契约定义和类型安全。 - 更新客户端类型定义并移除冗余的 APIRouterClient 引入,确保客户端实例类型与路由定义一致。 - 添加基于 zod 的类型安全接口定义,包含待办事项的增删改查操作契约及对应的输入输出验证规则。 - 使用合约定义重构 Todo 处理函数,统一接口输入输出验证并移除冗余的 Zod 模式定义。 - 更新导出模块,将路由功能改为导出合约定义。 - 移除未使用的导入和类型定义,精简路由配置文件。 --- bun.lock | 1 + package.json | 1 + src/orpc/client.ts | 10 ++++---- src/orpc/contract.ts | 49 +++++++++++++++++++++++++++++++++++++++ src/orpc/handlers/todo.ts | 48 +++++--------------------------------- src/orpc/index.ts | 2 +- src/orpc/router.ts | 3 --- 7 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 src/orpc/contract.ts diff --git a/bun.lock b/bun.lock index f143678..c582e2e 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "fullstack-starter", "dependencies": { "@orpc/client": "^1.13.4", + "@orpc/contract": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/tanstack-query": "^1.13.4", "@t3-oss/env-core": "^0.13.10", diff --git a/package.json b/package.json index d441238..c84ce47 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@orpc/client": "^1.13.4", + "@orpc/contract": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/tanstack-query": "^1.13.4", "@t3-oss/env-core": "^0.13.10", diff --git a/src/orpc/client.ts b/src/orpc/client.ts index 1c72e5b..5bdba99 100644 --- a/src/orpc/client.ts +++ b/src/orpc/client.ts @@ -1,10 +1,10 @@ import { createORPCClient } from '@orpc/client' import { RPCLink } from '@orpc/client/fetch' -import { createRouterClient } from '@orpc/server' +import { createRouterClient, type RouterClient } from '@orpc/server' import { createTanstackQueryUtils } from '@orpc/tanstack-query' import { createIsomorphicFn } from '@tanstack/react-start' import { getRequestHeaders } from '@tanstack/react-start/server' -import { type APIRouterClient, router } from '@/orpc' +import { router } from './router' const getORPCClient = createIsomorphicFn() .server(() => @@ -14,13 +14,13 @@ const getORPCClient = createIsomorphicFn() }), }), ) - .client(() => { + .client((): RouterClient => { const link = new RPCLink({ url: `${window.location.origin}/api/rpc`, }) - return createORPCClient(link) + return createORPCClient(link) }) -const client: APIRouterClient = getORPCClient() +const client: RouterClient = getORPCClient() export const orpc = createTanstackQueryUtils(client) diff --git a/src/orpc/contract.ts b/src/orpc/contract.ts new file mode 100644 index 0000000..bf05936 --- /dev/null +++ b/src/orpc/contract.ts @@ -0,0 +1,49 @@ +import { oc } from '@orpc/contract' +import { z } from 'zod' + +export const todoSchema = z.object({ + id: z.uuid(), + title: z.string(), + completed: z.boolean(), + createdAt: z.date(), + updatedAt: z.date(), +}) + +export const todoInsertSchema = z.object({ + title: z.string().min(1), + completed: z.boolean().optional(), +}) + +export const todoUpdateSchema = z.object({ + title: z.string().min(1).optional(), + completed: z.boolean().optional(), +}) + +export const todoContract = { + list: oc.input(z.void()).output(z.array(todoSchema)), + + create: oc.input(todoInsertSchema).output(todoSchema), + + update: oc + .input( + z.object({ + id: z.uuid(), + data: todoUpdateSchema, + }), + ) + .output(todoSchema), + + remove: oc + .input( + z.object({ + id: z.uuid(), + }), + ) + .output(z.void()), +} + +export const contract = { + todo: todoContract, +} + +export type Contract = typeof contract diff --git a/src/orpc/handlers/todo.ts b/src/orpc/handlers/todo.ts index 8415bb8..1864c84 100644 --- a/src/orpc/handlers/todo.ts +++ b/src/orpc/handlers/todo.ts @@ -1,31 +1,10 @@ -import { ORPCError, os } from '@orpc/server' +import { implement, ORPCError } from '@orpc/server' import { eq } from 'drizzle-orm' -import { - createInsertSchema, - createSelectSchema, - createUpdateSchema, -} from 'drizzle-zod' -import { z } from 'zod' import { todoTable } from '@/db/schema' +import { todoContract } from '@/orpc/contract' import { dbProvider } from '@/orpc/middlewares' -const selectSchema = createSelectSchema(todoTable) - -const insertSchema = createInsertSchema(todoTable).omit({ - id: true, - createdAt: true, - updatedAt: true, -}) - -const updateSchema = createUpdateSchema(todoTable).omit({ - id: true, - createdAt: true, - updatedAt: true, -}) - -export const list = os - .input(z.void()) - .output(z.array(selectSchema)) +export const list = implement(todoContract.list) .use(dbProvider) .handler(async ({ context }) => { const todos = await context.db.query.todoTable.findMany({ @@ -34,9 +13,7 @@ export const list = os return todos }) -export const create = os - .input(insertSchema) - .output(selectSchema) +export const create = implement(todoContract.create) .use(dbProvider) .handler(async ({ context, input }) => { const [newTodo] = await context.db @@ -51,14 +28,7 @@ export const create = os return newTodo }) -export const update = os - .input( - z.object({ - id: z.uuid(), - data: updateSchema, - }), - ) - .output(selectSchema) +export const update = implement(todoContract.update) .use(dbProvider) .handler(async ({ context, input }) => { const [updatedTodo] = await context.db @@ -74,13 +44,7 @@ export const update = os return updatedTodo }) -export const remove = os - .input( - z.object({ - id: z.uuid(), - }), - ) - .output(z.void()) +export const remove = implement(todoContract.remove) .use(dbProvider) .handler(async ({ context, input }) => { await context.db.delete(todoTable).where(eq(todoTable.id, input.id)) diff --git a/src/orpc/index.ts b/src/orpc/index.ts index 55bd9a5..ebe1c97 100644 --- a/src/orpc/index.ts +++ b/src/orpc/index.ts @@ -1,2 +1,2 @@ export * from './client' -export * from './router' +export * from './contract' diff --git a/src/orpc/router.ts b/src/orpc/router.ts index 6519a9d..70b205b 100644 --- a/src/orpc/router.ts +++ b/src/orpc/router.ts @@ -1,8 +1,5 @@ -import type { RouterClient } from '@orpc/server' import * as todo from './handlers/todo' export const router = { todo, } - -export type APIRouterClient = RouterClient