| import type { Request, Response, NextFunction } from 'express'; | |
| import { AnyZodObject, z } from 'zod'; | |
| import { badRequest } from '@hapi/boom'; | |
| function indent(str: string, spaces: number) { | |
| return str | |
| .split('\n') | |
| .map(line => ' '.repeat(spaces) + line) | |
| .join('\n'); | |
| } | |
| function extractZodMessage(error: any): string { | |
| if (Array.isArray(error)) { | |
| return error.map(extractZodMessage).join('\n'); | |
| } else { | |
| let union: string[] = []; | |
| if ('unionErrors' in error) { | |
| union = error.unionErrors.map(extractZodMessage); | |
| } else if ('issues' in error) { | |
| union = error.issues.map(extractZodMessage); | |
| } | |
| if ( | |
| 'message' in error && | |
| typeof error.message === 'string' && | |
| !error.message.includes('\n') | |
| ) { | |
| if (union.length === 0) return error.message; | |
| return error.message + '\n' + indent(union.join('\n'), 2); | |
| } else if (union.length > 0) { | |
| return union.join('\n'); | |
| } else { | |
| return ''; | |
| } | |
| } | |
| } | |
| export async function validate<T extends AnyZodObject>( | |
| req: Request, | |
| schema: T | |
| ): Promise<z.infer<T>> { | |
| try { | |
| return await schema.parseAsync(req); | |
| } catch (error: any) { | |
| throw badRequest(extractZodMessage(error)); | |
| } | |
| } | |
| export function wrap( | |
| fn: (req: Request, res: Response, next: NextFunction) => Promise<any> | |
| ) { | |
| return async function (req: Request, res: Response, next: NextFunction) { | |
| try { | |
| return await fn(req, res, next); | |
| } catch (err) { | |
| next(err); | |
| } | |
| }; | |
| } | |