File size: 1,502 Bytes
107b5c2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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);
    }
  };
}