import type { H3Event } from 'h3' import type { output, ZodObject, ZodType } from 'zod' async function readRawJson(event: H3Event): Promise> { const raw = await readRawBody(event, 'utf8') if (!raw) return {} try { return JSON.parse(raw) } catch { throw createError({ statusCode: 400, message: '请求体不是合法的 JSON' }) } } function validationError(issues: { path: PropertyKey[], message: string }[]) { const first = issues[0] return createError({ statusCode: 400, message: `参数错误:${first?.path.map(String).join('.') || ''} ${first?.message || ''}`.trim() }) } export async function readJson(event: H3Event, schema: ZodType): Promise { const parsed = schema.safeParse(await readRawJson(event)) if (!parsed.success) throw validationError(parsed.error.issues) return parsed.data } /** * 读取部分更新的请求体:只保留请求中实际出现的字段 * (zod 4 中 optional 包裹的 default 仍会生效,直接 partial() 会把缺省字段覆盖成默认值) */ export async function readPatch(event: H3Event, schema: S): Promise>> { const data = await readRawJson(event) const parsed = schema.partial().safeParse(data) if (!parsed.success) throw validationError(parsed.error.issues) const result = parsed.data as Record const out: Record = {} for (const k of Object.keys(data)) { if (k in result) out[k] = result[k] } return out as Partial> } export function param(event: H3Event, name = 'id') { const v = getRouterParam(event, name) if (!v) throw createError({ statusCode: 400, message: `缺少参数 ${name}` }) return v }