|
@@ -1,14 +1,124 @@
|
|
|
import { Context } from 'hono'
|
|
import { Context } from 'hono'
|
|
|
import { z } from '@hono/zod-openapi'
|
|
import { z } from '@hono/zod-openapi'
|
|
|
|
|
+import { ErrorSchema, ZodIssueSchema, ZodErrorSchema } from '../schema/error.schema'
|
|
|
|
|
|
|
|
-export const ErrorSchema = z.object({
|
|
|
|
|
- code: z.number().openapi({
|
|
|
|
|
- example: 400,
|
|
|
|
|
- }),
|
|
|
|
|
- message: z.string().openapi({
|
|
|
|
|
- example: 'Bad Request',
|
|
|
|
|
- }),
|
|
|
|
|
-})
|
|
|
|
|
|
|
+export { ErrorSchema, ZodIssueSchema, ZodErrorSchema }
|
|
|
|
|
+
|
|
|
|
|
+// 类型安全的Zod错误处理函数
|
|
|
|
|
+export function handleZodError(error: z.ZodError): z.infer<typeof ZodErrorSchema> {
|
|
|
|
|
+ const issues = error.issues.map(issue => {
|
|
|
|
|
+ // 基础字段 - 过滤掉symbol类型的path,转换null为字符串
|
|
|
|
|
+ const mappedIssue: z.infer<typeof ZodIssueSchema> = {
|
|
|
|
|
+ code: issue.code,
|
|
|
|
|
+ path: issue.path.map(p => {
|
|
|
|
|
+ if (typeof p === 'string' || typeof p === 'number') {
|
|
|
|
|
+ return p
|
|
|
|
|
+ }
|
|
|
|
|
+ // 将symbol和null转换为字符串
|
|
|
|
|
+ return String(p)
|
|
|
|
|
+ }),
|
|
|
|
|
+ message: issue.message,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 根据错误类型添加特定字段
|
|
|
|
|
+ if ('expected' in issue && issue.expected !== undefined) {
|
|
|
|
|
+ mappedIssue.expected = String(issue.expected)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('received' in issue && issue.received !== undefined) {
|
|
|
|
|
+ mappedIssue.received = String(issue.received)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('origin' in issue && issue.origin !== undefined) {
|
|
|
|
|
+ mappedIssue.origin = String(issue.origin)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('minimum' in issue && issue.minimum !== undefined) {
|
|
|
|
|
+ mappedIssue.minimum = Number(issue.minimum)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('maximum' in issue && issue.maximum !== undefined) {
|
|
|
|
|
+ mappedIssue.maximum = Number(issue.maximum)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('inclusive' in issue && issue.inclusive !== undefined) {
|
|
|
|
|
+ mappedIssue.inclusive = Boolean(issue.inclusive)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('fatal' in issue && issue.fatal !== undefined) {
|
|
|
|
|
+ mappedIssue.fatal = Boolean(issue.fatal)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('type' in issue && issue.type !== undefined) {
|
|
|
|
|
+ mappedIssue.type = String(issue.type)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('exact' in issue && issue.exact !== undefined) {
|
|
|
|
|
+ mappedIssue.exact = Boolean(issue.exact)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('validation' in issue && issue.validation !== undefined) {
|
|
|
|
|
+ mappedIssue.validation = String(issue.validation)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('keys' in issue && issue.keys !== undefined && Array.isArray(issue.keys)) {
|
|
|
|
|
+ mappedIssue.keys = issue.keys.map(key => String(key))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('options' in issue && issue.options !== undefined && Array.isArray(issue.options)) {
|
|
|
|
|
+ mappedIssue.options = issue.options.map(opt =>
|
|
|
|
|
+ typeof opt === 'string' || typeof opt === 'number' ? opt : String(opt)
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('multipleOf' in issue && issue.multipleOf !== undefined) {
|
|
|
|
|
+ mappedIssue.multipleOf = Number(issue.multipleOf)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('input' in issue && issue.input !== undefined) {
|
|
|
|
|
+ mappedIssue.input = issue.input
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('unionErrors' in issue && issue.unionErrors !== undefined && Array.isArray(issue.unionErrors)) {
|
|
|
|
|
+ mappedIssue.unionErrors = issue.unionErrors
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('argumentsError' in issue && issue.argumentsError !== undefined) {
|
|
|
|
|
+ mappedIssue.argumentsError = issue.argumentsError
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ('returnTypeError' in issue && issue.returnTypeError !== undefined) {
|
|
|
|
|
+ mappedIssue.returnTypeError = issue.returnTypeError
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return mappedIssue
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ code: 400,
|
|
|
|
|
+ message: '参数错误',
|
|
|
|
|
+ errors: issues,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 简化的Zod错误处理函数(用于路由)
|
|
|
|
|
+export function createZodErrorResponse(error: z.ZodError) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ code: 400,
|
|
|
|
|
+ message: '参数错误',
|
|
|
|
|
+ errors: error.issues.map(issue => ({
|
|
|
|
|
+ code: issue.code,
|
|
|
|
|
+ path: issue.path,
|
|
|
|
|
+ message: issue.message,
|
|
|
|
|
+ // 可选字段 - 根据实际需要添加
|
|
|
|
|
+ ...('expected' in issue && issue.expected !== undefined && { expected: String(issue.expected) }),
|
|
|
|
|
+ ...('received' in issue && issue.received !== undefined && { received: String(issue.received) }),
|
|
|
|
|
+ ...('minimum' in issue && issue.minimum !== undefined && { minimum: Number(issue.minimum) }),
|
|
|
|
|
+ ...('maximum' in issue && issue.maximum !== undefined && { maximum: Number(issue.maximum) }),
|
|
|
|
|
+ ...('inclusive' in issue && issue.inclusive !== undefined && { inclusive: Boolean(issue.inclusive) }),
|
|
|
|
|
+ }))
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
export const errorHandler = async (err: Error, c: Context) => {
|
|
export const errorHandler = async (err: Error, c: Context) => {
|
|
|
return c.json(
|
|
return c.json(
|