forked from Goldii-locks/escrow-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate.ts
More file actions
106 lines (95 loc) · 2.96 KB
/
Copy pathvalidate.ts
File metadata and controls
106 lines (95 loc) · 2.96 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import type { NextFunction, Request, Response } from "express";
import { ZodError, ZodSchema } from "zod";
type Target = "params" | "body" | "query";
export type RequestWithValidatedQuery = Request & {
validatedQuery?: unknown;
};
export type ValidationErrorDetail = {
field: string;
message: string;
};
export function validate(
schema: ZodSchema,
target: Target = "params",
onReject?: (req: Request) => void,
) {
return (req: Request, res: Response, next: NextFunction): void => {
const result = schema.safeParse(req[target]);
if (!result.success) {
onReject?.(req);
const zodError = result.error as ZodError;
// Build details array from all Zod errors
const details: ValidationErrorDetail[] = zodError.errors.map((err) => {
// Use the first path element as the field name (e.g., "contractId", "index")
const field = Array.isArray(err.path) && err.path.length > 0
? String(err.path[0])
: "unknown";
return {
field,
message: err.message,
};
});
// Send ValidationError response with details array
res.status(400).json({
success: false,
error: "ValidationError",
message: "Invalid request parameters",
details,
});
return;
}
// Express 5 exposes req.query as a getter-only property, so validated
// query data is attached on a custom field instead of reassignment.
if (target === "query") {
(req as RequestWithValidatedQuery).validatedQuery = result.data;
} else {
req[target] = result.data;
}
next();
};
}
export function validateWithFields(
schema: ZodSchema,
target: Target = "params",
onReject?: (req: Request) => void,
) {
return (req: Request, res: Response, next: NextFunction): void => {
const result = schema.safeParse(req[target]);
if (!result.success) {
onReject?.(req);
const errors = (result.error as ZodError).errors;
const fields = errors.reduce((acc, err) => {
const path = err.path.join(".");
if (path) {
acc[path] = err.message;
} else {
acc["_root"] = err.message;
}
return acc;
}, {} as Record<string, string>);
// Same body as validate(), plus a `fields` map keyed by dotted path for
// clients that bind errors straight onto form inputs.
const details: ValidationErrorDetail[] = errors.map((err) => ({
field:
Array.isArray(err.path) && err.path.length > 0
? String(err.path[0])
: "unknown",
message: err.message,
}));
res.status(400).json({
success: false,
error: "ValidationError",
message: "Invalid request parameters",
details,
fields,
});
return;
}
if (target === "query") {
(req as RequestWithValidatedQuery).validatedQuery = result.data;
} else {
req[target] = result.data;
}
next();
};
}