express-zod-safe 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,14 +117,16 @@ app.post('/user/:userId', validate({ handler, params, query, body }), (req, res)
117
117
  });
118
118
  ```
119
119
 
120
- If you plan to use the same error handler across every route, use the `setGlobalErrorHandler`:
120
+ If you plan to use the same error handler across every route, use `setGlobalOptions`:
121
121
 
122
122
 
123
123
  ```ts
124
- import { setGlobalErrorHandler } from 'express-zod-safe';
124
+ import { setGlobalOptions } from 'express-zod-safe';
125
125
 
126
- setGlobalErrorHandler((errors, req, res) => {
127
- // Your error handling here
126
+ setGlobalOptions({
127
+ handler: (errors, req, res) => {
128
+ // Your error handling here
129
+ }
128
130
  })
129
131
  ```
130
132
 
@@ -210,6 +212,43 @@ app.post('/user', validate({ body, params }), (req, res) => {
210
212
  });
211
213
  ```
212
214
 
215
+ To enable this behaviour globally without the need to explicitly set `z.any()` in each instance, use `setGlobalOptions`:
216
+
217
+ ```ts
218
+ import { setGlobalOptions } from 'express-zod-safe';
219
+
220
+ setGlobalOptions({
221
+ missingSchemaBehavior: 'any'
222
+ });
223
+ ```
224
+
225
+ ### ⚠️ Default Schema Object Strictness
226
+ When a plain JavaScript object is supplied instead of a Zod schema object, the default behaviour is to assume `z.strictObject`. This means that additional keys will cause validation to fail. To override this behaviour, use `z.object()` explicitly:
227
+
228
+ ```ts
229
+ // z.object allows additional keys
230
+ const body = z.object({
231
+ name: z.string(),
232
+ email: z.string().email(),
233
+ });
234
+
235
+ app.post('/user', validate({ body }), (req, res) => {
236
+ // ...
237
+ });
238
+ ```
239
+
240
+ *Note: in both instances, additional keys will be stripped from the output. The difference lies in whether additional keys throw a validation error or are silently removed.*
241
+
242
+ To enable this behaviour globally without the need to explicitly set `z.object()` in each instance, use `setGlobalOptions`:
243
+
244
+ ```ts
245
+ import { setGlobalOptions } from 'express-zod-safe';
246
+
247
+ setGlobalOptions({
248
+ defaultSchemaObject: 'lax'
249
+ });
250
+ ```
251
+
213
252
  ## ⭐️ Show your support
214
253
 
215
254
  Give a ⭐️ on GitHub if this project helped you!
package/dist/index.d.mts CHANGED
@@ -3,11 +3,101 @@ import { ZodType, ZodRawShape, ZodError, z } from 'zod';
3
3
 
4
4
  declare const types: readonly ["query", "params", "body"];
5
5
  declare const defaultErrorHandler: ErrorRequestHandler;
6
+ interface ValidateRequestGlobalOptions {
7
+ /**
8
+ * The error handler to use for all routes if no handler is provided in the schema.
9
+ */
10
+ handler: ErrorRequestHandler;
11
+ /**
12
+ * The default schema object type to use for validation when a plain object is provided.
13
+ *
14
+ * When using `validate({ query: { a: z.string() } })`:
15
+ * - `'strict'` (default): Uses `z.strictObject`, which rejects extra properties.
16
+ * For example, `GET /?a=1&b=2` will fail validation.
17
+ * - `'lax'`: Uses `z.object`, which allows extra properties.
18
+ * For example, `GET /?a=1&b=2` will succeed, and `req.query` will only contain `{ a: '1' }`.
19
+ *
20
+ * Note: If you pass a Zod object directly (e.g., `validate({ query: z.object({ a: z.string() }) })`),
21
+ * this option has no effect as the provided Zod object is used as-is.
22
+ *
23
+ * @default 'strict'
24
+ * @example
25
+ * ```ts
26
+ * // Allow extra properties in query params
27
+ * setGlobalOptions({ defaultSchemaObject: 'lax' });
28
+ *
29
+ * app.get('/user', validate({ query: { id: z.string() } }), (req, res) => {
30
+ * // GET /user?id=123&extra=value will succeed
31
+ * // req.query will be { id: '123' }
32
+ * });
33
+ * ```
34
+ */
35
+ defaultSchemaObject: 'strict' | 'lax';
36
+ /**
37
+ * The behavior when a schema is not provided for a particular input type (params, query, or body).
38
+ *
39
+ * - `'empty'` (default): Validates against an empty strict object (`z.strictObject({})`), which rejects any input.
40
+ * - `'any'`: Skips validation entirely for that input type, allowing any data to pass through.
41
+ * This is useful when using nested routers where different parts of the route validate different inputs.
42
+ *
43
+ * @default 'empty'
44
+ */
45
+ missingSchemaBehavior: 'empty' | 'any';
46
+ }
47
+ /**
48
+ * The default global options for request validation.
49
+ *
50
+ * Default values:
51
+ * - `defaultSchemaObject: 'strict'`
52
+ * - `missingSchemaBehavior: 'empty'`
53
+ * - `handler`: The default error handler sends a 400 status with an array of validation errors (see: {@link defaultErrorHandler}):
54
+ * ```ts
55
+ * (errors, _req, res) => {
56
+ * res.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));
57
+ * }
58
+ * ```
59
+ */
60
+ declare const DEFAULT_OPTIONS: ValidateRequestGlobalOptions;
61
+ /**
62
+ * Sets the global {@link options} for request validation.
63
+ *
64
+ * @param newOptions Partial options to merge with the current global options.
65
+ * @example
66
+ * // Change the error handler
67
+ * setGlobalOptions({
68
+ * handler: (errors, req, res) => {
69
+ * res.status(422).json({ validationErrors: errors });
70
+ * }
71
+ * });
72
+ *
73
+ * // Change default schema object type
74
+ * setGlobalOptions({ defaultSchemaObject: 'lax' });
75
+ *
76
+ * // Change missing schema behavior
77
+ * setGlobalOptions({ missingSchemaBehavior: 'any' });
78
+ *
79
+ * // Change all options
80
+ * setGlobalOptions({
81
+ * handler: customHandler,
82
+ * defaultSchemaObject: 'lax',
83
+ * missingSchemaBehavior: 'any'
84
+ * });
85
+ */
86
+ declare const setGlobalOptions: (newOptions: Partial<ValidateRequestGlobalOptions>) => void;
6
87
  /**
7
88
  * Generates a middleware function for Express.js that validates request params, query, and body.
8
89
  * This function uses Zod schemas to perform validation against the provided schema definitions.
9
90
  *
10
- * @param schemas - An object containing Zod schemas for params, query, and body. Optional handler for custom error handling.
91
+ * **Missing Schema Behavior**: If a schema is not provided for a particular input type (params, query, or body),
92
+ * the behavior is controlled by the {@link ValidateRequestGlobalOptions.missingSchemaBehavior} option:
93
+ * - `'empty'` (default): Validates against an empty strict object, rejecting any input
94
+ * - `'any'`: Skips validation entirely, allowing any data to pass through
95
+ *
96
+ * This allows you to validate only the parts of the request you care about when using nested routers.
97
+ *
98
+ * @param schemas - An object containing Zod schemas for params, query, and body. All fields are optional.
99
+ * If a field is omitted, behavior depends on {@link ValidateRequestGlobalOptions.missingSchemaBehavior}.
100
+ * Optional handler for custom error handling.
11
101
  * @returns An Express.js middleware function that validates the request based on the provided schemas.
12
102
  * It attaches validated data to the request object and sends error details if validation fails.
13
103
  * @template TParams - Type definition for params schema.
@@ -40,9 +130,18 @@ declare const defaultErrorHandler: ErrorRequestHandler;
40
130
  * res.send('User data is valid!');
41
131
  * });
42
132
  *
133
+ * // Only validate params, allow any query or body
134
+ * setGlobalOptions({ missingSchemaBehavior: 'any' });
135
+ * app.use('/:id', validate({ params: { id: z.string().uuid() } }), nestedRouter);
136
+ *
43
137
  * app.listen(3000, () => console.log('Server running on port 3000'));
44
138
  */
45
139
  declare function validate<TParams extends ValidationSchema, TQuery extends ValidationSchema, TBody extends ValidationSchema>(schemas: CompleteValidationSchema<TParams, TQuery, TBody>): RequestHandler<ZodOutput<TParams>, any, ZodOutput<TBody>, ZodOutput<TQuery>>;
140
+ /**
141
+ * Sets the global error handler for all routes.
142
+ * @param handler The error handler to set.
143
+ * @deprecated Use {@link setGlobalOptions} instead.
144
+ */
46
145
  declare function setGlobalErrorHandler(handler: ErrorRequestHandler): void;
47
146
  /**
48
147
  * Describes the types of data that can be validated: 'query', 'params', or 'body'.
@@ -125,4 +224,4 @@ type WeakRequestHandler = RequestHandler<Unvalidated, Unvalidated, Unvalidated,
125
224
  */
126
225
  type ValidatedRequest<T extends CompleteValidationSchema> = Request<ZodOutput<T['params']>, any, ZodOutput<T['body']>, ZodOutput<T['query']>>;
127
226
 
128
- export { type CompleteValidationSchema, type ErrorListItem, type ErrorRequestHandler, type Unvalidated, type ValidatedRequest, type ValidationSchema, type WeakRequestHandler, type ZodOutput, validate as default, defaultErrorHandler, setGlobalErrorHandler };
227
+ export { type CompleteValidationSchema, DEFAULT_OPTIONS, type ErrorListItem, type ErrorRequestHandler, type Unvalidated, type ValidateRequestGlobalOptions, type ValidatedRequest, type ValidationSchema, type WeakRequestHandler, type ZodOutput, validate as default, defaultErrorHandler, setGlobalErrorHandler, setGlobalOptions };
package/dist/index.d.ts CHANGED
@@ -3,11 +3,101 @@ import { ZodType, ZodRawShape, ZodError, z } from 'zod';
3
3
 
4
4
  declare const types: readonly ["query", "params", "body"];
5
5
  declare const defaultErrorHandler: ErrorRequestHandler;
6
+ interface ValidateRequestGlobalOptions {
7
+ /**
8
+ * The error handler to use for all routes if no handler is provided in the schema.
9
+ */
10
+ handler: ErrorRequestHandler;
11
+ /**
12
+ * The default schema object type to use for validation when a plain object is provided.
13
+ *
14
+ * When using `validate({ query: { a: z.string() } })`:
15
+ * - `'strict'` (default): Uses `z.strictObject`, which rejects extra properties.
16
+ * For example, `GET /?a=1&b=2` will fail validation.
17
+ * - `'lax'`: Uses `z.object`, which allows extra properties.
18
+ * For example, `GET /?a=1&b=2` will succeed, and `req.query` will only contain `{ a: '1' }`.
19
+ *
20
+ * Note: If you pass a Zod object directly (e.g., `validate({ query: z.object({ a: z.string() }) })`),
21
+ * this option has no effect as the provided Zod object is used as-is.
22
+ *
23
+ * @default 'strict'
24
+ * @example
25
+ * ```ts
26
+ * // Allow extra properties in query params
27
+ * setGlobalOptions({ defaultSchemaObject: 'lax' });
28
+ *
29
+ * app.get('/user', validate({ query: { id: z.string() } }), (req, res) => {
30
+ * // GET /user?id=123&extra=value will succeed
31
+ * // req.query will be { id: '123' }
32
+ * });
33
+ * ```
34
+ */
35
+ defaultSchemaObject: 'strict' | 'lax';
36
+ /**
37
+ * The behavior when a schema is not provided for a particular input type (params, query, or body).
38
+ *
39
+ * - `'empty'` (default): Validates against an empty strict object (`z.strictObject({})`), which rejects any input.
40
+ * - `'any'`: Skips validation entirely for that input type, allowing any data to pass through.
41
+ * This is useful when using nested routers where different parts of the route validate different inputs.
42
+ *
43
+ * @default 'empty'
44
+ */
45
+ missingSchemaBehavior: 'empty' | 'any';
46
+ }
47
+ /**
48
+ * The default global options for request validation.
49
+ *
50
+ * Default values:
51
+ * - `defaultSchemaObject: 'strict'`
52
+ * - `missingSchemaBehavior: 'empty'`
53
+ * - `handler`: The default error handler sends a 400 status with an array of validation errors (see: {@link defaultErrorHandler}):
54
+ * ```ts
55
+ * (errors, _req, res) => {
56
+ * res.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));
57
+ * }
58
+ * ```
59
+ */
60
+ declare const DEFAULT_OPTIONS: ValidateRequestGlobalOptions;
61
+ /**
62
+ * Sets the global {@link options} for request validation.
63
+ *
64
+ * @param newOptions Partial options to merge with the current global options.
65
+ * @example
66
+ * // Change the error handler
67
+ * setGlobalOptions({
68
+ * handler: (errors, req, res) => {
69
+ * res.status(422).json({ validationErrors: errors });
70
+ * }
71
+ * });
72
+ *
73
+ * // Change default schema object type
74
+ * setGlobalOptions({ defaultSchemaObject: 'lax' });
75
+ *
76
+ * // Change missing schema behavior
77
+ * setGlobalOptions({ missingSchemaBehavior: 'any' });
78
+ *
79
+ * // Change all options
80
+ * setGlobalOptions({
81
+ * handler: customHandler,
82
+ * defaultSchemaObject: 'lax',
83
+ * missingSchemaBehavior: 'any'
84
+ * });
85
+ */
86
+ declare const setGlobalOptions: (newOptions: Partial<ValidateRequestGlobalOptions>) => void;
6
87
  /**
7
88
  * Generates a middleware function for Express.js that validates request params, query, and body.
8
89
  * This function uses Zod schemas to perform validation against the provided schema definitions.
9
90
  *
10
- * @param schemas - An object containing Zod schemas for params, query, and body. Optional handler for custom error handling.
91
+ * **Missing Schema Behavior**: If a schema is not provided for a particular input type (params, query, or body),
92
+ * the behavior is controlled by the {@link ValidateRequestGlobalOptions.missingSchemaBehavior} option:
93
+ * - `'empty'` (default): Validates against an empty strict object, rejecting any input
94
+ * - `'any'`: Skips validation entirely, allowing any data to pass through
95
+ *
96
+ * This allows you to validate only the parts of the request you care about when using nested routers.
97
+ *
98
+ * @param schemas - An object containing Zod schemas for params, query, and body. All fields are optional.
99
+ * If a field is omitted, behavior depends on {@link ValidateRequestGlobalOptions.missingSchemaBehavior}.
100
+ * Optional handler for custom error handling.
11
101
  * @returns An Express.js middleware function that validates the request based on the provided schemas.
12
102
  * It attaches validated data to the request object and sends error details if validation fails.
13
103
  * @template TParams - Type definition for params schema.
@@ -40,9 +130,18 @@ declare const defaultErrorHandler: ErrorRequestHandler;
40
130
  * res.send('User data is valid!');
41
131
  * });
42
132
  *
133
+ * // Only validate params, allow any query or body
134
+ * setGlobalOptions({ missingSchemaBehavior: 'any' });
135
+ * app.use('/:id', validate({ params: { id: z.string().uuid() } }), nestedRouter);
136
+ *
43
137
  * app.listen(3000, () => console.log('Server running on port 3000'));
44
138
  */
45
139
  declare function validate<TParams extends ValidationSchema, TQuery extends ValidationSchema, TBody extends ValidationSchema>(schemas: CompleteValidationSchema<TParams, TQuery, TBody>): RequestHandler<ZodOutput<TParams>, any, ZodOutput<TBody>, ZodOutput<TQuery>>;
140
+ /**
141
+ * Sets the global error handler for all routes.
142
+ * @param handler The error handler to set.
143
+ * @deprecated Use {@link setGlobalOptions} instead.
144
+ */
46
145
  declare function setGlobalErrorHandler(handler: ErrorRequestHandler): void;
47
146
  /**
48
147
  * Describes the types of data that can be validated: 'query', 'params', or 'body'.
@@ -127,4 +226,4 @@ type ValidatedRequest<T extends CompleteValidationSchema> = Request<ZodOutput<T[
127
226
 
128
227
  // @ts-ignore
129
228
  export = validate;
130
- export { type CompleteValidationSchema, type ErrorListItem, type ErrorRequestHandler, type Unvalidated, type ValidatedRequest, type ValidationSchema, type WeakRequestHandler, type ZodOutput, defaultErrorHandler, setGlobalErrorHandler };
229
+ export { type CompleteValidationSchema, DEFAULT_OPTIONS, type ErrorListItem, type ErrorRequestHandler, type Unvalidated, type ValidateRequestGlobalOptions, type ValidatedRequest, type ValidationSchema, type WeakRequestHandler, type ZodOutput, defaultErrorHandler, setGlobalErrorHandler, setGlobalOptions };
package/dist/index.js CHANGED
@@ -5,7 +5,15 @@ var types = ["query", "params", "body"];
5
5
  var defaultErrorHandler = (errors, _req, res) => {
6
6
  res.status(400).send(errors.map((error) => ({ type: error.type, errors: error.errors.issues })));
7
7
  };
8
- var globalErrorHandler = defaultErrorHandler;
8
+ var DEFAULT_OPTIONS = {
9
+ handler: defaultErrorHandler,
10
+ defaultSchemaObject: "strict",
11
+ missingSchemaBehavior: "empty"
12
+ };
13
+ var options = DEFAULT_OPTIONS;
14
+ var setGlobalOptions = (newOptions) => {
15
+ Object.assign(options, newOptions);
16
+ };
9
17
  function isZodType(schema) {
10
18
  return !!schema && typeof schema.safeParseAsync === "function";
11
19
  }
@@ -24,11 +32,18 @@ if (descriptor) {
24
32
  });
25
33
  }
26
34
  function validate(schemas) {
35
+ const zodObject = options.defaultSchemaObject === "strict" ? _zod.z.strictObject : _zod.z.object;
36
+ const missingSchemaHandler = options.missingSchemaBehavior === "empty" ? zodObject({}) : _zod.z.any();
27
37
  const validation = {
28
- params: isZodType(schemas.params) ? schemas.params : _zod.z.strictObject(_nullishCoalesce(schemas.params, () => ( {}))),
29
- query: isZodType(schemas.query) ? schemas.query : _zod.z.strictObject(_nullishCoalesce(schemas.query, () => ( {}))),
30
- body: isZodType(schemas.body) ? schemas.body : _zod.z.strictObject(_nullishCoalesce(schemas.body, () => ( {})))
38
+ params: missingSchemaHandler,
39
+ query: missingSchemaHandler,
40
+ body: missingSchemaHandler
31
41
  };
42
+ for (const type of types) {
43
+ if (schemas[type]) {
44
+ validation[type] = isZodType(schemas[type]) ? schemas[type] : zodObject(schemas[type]);
45
+ }
46
+ }
32
47
  return async (req, res, next) => {
33
48
  const errors = [];
34
49
  for (const type of types) {
@@ -37,18 +52,20 @@ function validate(schemas) {
37
52
  else errors.push({ type, errors: parsed.error });
38
53
  }
39
54
  if (errors.length > 0) {
40
- const handler = _nullishCoalesce(schemas.handler, () => ( globalErrorHandler));
55
+ const handler = _nullishCoalesce(schemas.handler, () => ( options.handler));
41
56
  return handler(errors, req, res, next);
42
57
  }
43
58
  return next();
44
59
  };
45
60
  }
46
61
  function setGlobalErrorHandler(handler) {
47
- globalErrorHandler = handler;
62
+ options.handler = handler;
48
63
  }
49
64
 
50
65
 
51
66
 
52
67
 
53
- exports.default = validate; exports.defaultErrorHandler = defaultErrorHandler; exports.setGlobalErrorHandler = setGlobalErrorHandler;
68
+
69
+
70
+ exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS; exports.default = validate; exports.defaultErrorHandler = defaultErrorHandler; exports.setGlobalErrorHandler = setGlobalErrorHandler; exports.setGlobalOptions = setGlobalOptions;
54
71
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/express-zod-safe/express-zod-safe/dist/index.js","../src/index.ts"],"names":[],"mappings":"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","file":"/home/runner/work/express-zod-safe/express-zod-safe/dist/index.js","sourcesContent":[null,"/// <reference types=\"./express.d.ts\" />\nimport type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport express from 'express';\nimport { type ZodError, type ZodRawShape, type ZodType, z } from 'zod';\n\nconst types = ['query', 'params', 'body'] as const;\n\nexport const defaultErrorHandler: ErrorRequestHandler = (errors, _req, res) => {\n\tres.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));\n};\n\nlet globalErrorHandler = defaultErrorHandler;\n\n/**\n * A ZodType type guard.\n * @param schema The Zod schema to check.\n * @returns Whether the provided schema is a ZodType.\n */\nfunction isZodType(schema: unknown): schema is ZodType {\n\treturn !!schema && typeof (schema as ZodType).safeParseAsync === 'function';\n}\n\n// Override express@^5 request.query getter to provider setter\nconst descriptor = Object.getOwnPropertyDescriptor(express.request, 'query');\nif (descriptor) {\n\tObject.defineProperty(express.request, 'query', {\n\t\tget(this: Request) {\n\t\t\tif (Object.hasOwn(this, '_query')) return this._query;\n\t\t\treturn descriptor?.get?.call(this);\n\t\t},\n\t\tset(this: Request, query: unknown) {\n\t\t\tthis._query = query;\n\t\t},\n\t\tconfigurable: true,\n\t\tenumerable: true\n\t});\n}\n\n/**\n * Generates a middleware function for Express.js that validates request params, query, and body.\n * This function uses Zod schemas to perform validation against the provided schema definitions.\n *\n * @param schemas - An object containing Zod schemas for params, query, and body. Optional handler for custom error handling.\n * @returns An Express.js middleware function that validates the request based on the provided schemas.\n * It attaches validated data to the request object and sends error details if validation fails.\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n * @example\n * // Example usage in an Express.js route\n * import express from 'express';\n * import validate from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Define your Zod schemas\n * const params = {\n * userId: z.string().uuid(),\n * };\n * const query = {\n * age: z.coerce.number().optional(),\n * };\n * const body = {\n * name: z.string(),\n * email: z.string().email(),\n * };\n *\n * // Use the validate middleware in your route\n * app.post('/user/:userId', validate({ params, query, body }), (req, res) => {\n * // Your route logic here\n * res.send('User data is valid!');\n * });\n *\n * app.listen(3000, () => console.log('Server running on port 3000'));\n */\nexport default function validate<TParams extends ValidationSchema, TQuery extends ValidationSchema, TBody extends ValidationSchema>(\n\tschemas: CompleteValidationSchema<TParams, TQuery, TBody>\n): RequestHandler<ZodOutput<TParams>, any, ZodOutput<TBody>, ZodOutput<TQuery>> {\n\t// Create validation objects for each type\n\tconst validation = {\n\t\tparams: isZodType(schemas.params) ? schemas.params : z.strictObject(schemas.params ?? {}),\n\t\tquery: isZodType(schemas.query) ? schemas.query : z.strictObject(schemas.query ?? {}),\n\t\tbody: isZodType(schemas.body) ? schemas.body : z.strictObject(schemas.body ?? {})\n\t};\n\n\treturn async (req, res, next): Promise<void> => {\n\t\tconst errors: ErrorListItem[] = [];\n\n\t\t// Validate all types (params, query, body)\n\t\tfor (const type of types) {\n\t\t\tconst parsed = await validation[type].safeParseAsync(req[type] ?? {});\n\t\t\tif (parsed.success) req[type] = parsed.data as any;\n\t\t\telse errors.push({ type, errors: parsed.error });\n\t\t}\n\n\t\t// Return all errors if there are any\n\t\tif (errors.length > 0) {\n\t\t\t// If a custom error handler is provided, use it\n\t\t\tconst handler = schemas.handler ?? globalErrorHandler;\n\t\t\treturn handler(errors, req, res, next);\n\t\t}\n\n\t\treturn next();\n\t};\n}\n\nexport function setGlobalErrorHandler(handler: ErrorRequestHandler): void {\n\tglobalErrorHandler = handler;\n}\n\n/**\n * Describes the types of data that can be validated: 'query', 'params', or 'body'.\n */\ntype DataType = (typeof types)[number];\n\n/**\n * Defines the structure of an error item, containing the type of validation that failed (params, query, or body)\n * and the associated ZodError.\n */\nexport interface ErrorListItem {\n\ttype: DataType;\n\terrors: ZodError;\n}\n\nexport type Unvalidated = unknown;\n\n/**\n * Represents an Express.js error request handler where the params, query and body are of unknown type as validation failed.\n */\nexport type ErrorRequestHandler<\n\tP = Unvalidated,\n\tResBody = any,\n\tReqBody = Unvalidated,\n\tReqQuery = unknown,\n\tLocalsObj extends Record<string, any> = Record<string, any>\n> = (\n\terr: ErrorListItem[],\n\treq: Request<P, ResBody, ReqBody, ReqQuery, LocalsObj>,\n\tres: Response<ResBody, LocalsObj>,\n\tnext: NextFunction\n) => void | Promise<void>;\n\n/**\n * Represents a generic type for route validation, which can be applied to params, query, or body.\n * Each key-value pair represents a field and its corresponding Zod validation schema.\n */\nexport type ValidationSchema = ZodType | ZodRawShape;\n\n/**\n * Defines the structure for the schemas provided to the validate middleware.\n * Each property corresponds to a different part of the request (params, query, body)\n * and should be a record of Zod types for validation. Optional handler for custom error handling.\n *\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n */\nexport interface CompleteValidationSchema<\n\tTParams extends ValidationSchema = ValidationSchema,\n\tTQuery extends ValidationSchema = ValidationSchema,\n\tTBody extends ValidationSchema = ValidationSchema\n> {\n\thandler?: ErrorRequestHandler;\n\tparams?: TParams;\n\tquery?: TQuery;\n\tbody?: TBody;\n}\n\n/**\n * Represents the output type of a Zod validation schema.\n * This is used to infer the TypeScript type from a Zod schema,\n * providing typesafe access to the validated data.\n *\n * @template T - The validation type (params, query, or body).\n */\nexport type ZodOutput<T extends ValidationSchema | undefined> = T extends ValidationSchema\n\t? z.output<T extends ZodRawShape ? z.ZodObject<T> : T>\n\t: Unvalidated;\n\n/**\n * A utility type to ensure other middleware types don't conflict with the validate middleware.\n */\nexport type WeakRequestHandler = RequestHandler<Unvalidated, Unvalidated, Unvalidated, Unvalidated>;\n\n/**\n * A utility type to ensure the Request is typed correctly.\n * @template T - The validation schema to be applied to the request params, query and body.\n * @example\n * import { ValidatedRequest } from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const schema = {\n * \tquery: {\n * \t\tname: z.string().min(3).max(10),\n * \t\tage: z.coerce.number().min(18)\n * \t},\n * \tbody: {\n * \t\ttitle: z.string().max(4)\n * \t},\n * \tparams: {\n * \t\tid: z.coerce.number()\n * \t}\n * };\n *\n * const requestHandler = (req: ValidatedRequest<typeof schema>, res: Response) => {\n * \tconst { name, age } = req.query;\n * \tconst { id } = req.params;\n * const { title } = req.body;\n *\n * \tres.send(`Hello ${title} ${name}! (Your age is ${age} and your ID is ${id})`);\n * };\n *\n * app.post('/handler/:id', validate(schema), requestHandler);\n */\nexport type ValidatedRequest<T extends CompleteValidationSchema> = Request<\n\tZodOutput<T['params']>,\n\tany,\n\tZodOutput<T['body']>,\n\tZodOutput<T['query']>\n>;\n"]}
1
+ {"version":3,"sources":["c:\\Users\\angus\\Documents\\Development\\express-zod-safe\\dist\\index.js"],"names":[],"mappings":"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","file":"C:\\Users\\angus\\Documents\\Development\\express-zod-safe\\dist\\index.js","sourcesContent":[null]}
package/dist/index.mjs CHANGED
@@ -5,7 +5,15 @@ var types = ["query", "params", "body"];
5
5
  var defaultErrorHandler = (errors, _req, res) => {
6
6
  res.status(400).send(errors.map((error) => ({ type: error.type, errors: error.errors.issues })));
7
7
  };
8
- var globalErrorHandler = defaultErrorHandler;
8
+ var DEFAULT_OPTIONS = {
9
+ handler: defaultErrorHandler,
10
+ defaultSchemaObject: "strict",
11
+ missingSchemaBehavior: "empty"
12
+ };
13
+ var options = DEFAULT_OPTIONS;
14
+ var setGlobalOptions = (newOptions) => {
15
+ Object.assign(options, newOptions);
16
+ };
9
17
  function isZodType(schema) {
10
18
  return !!schema && typeof schema.safeParseAsync === "function";
11
19
  }
@@ -24,11 +32,18 @@ if (descriptor) {
24
32
  });
25
33
  }
26
34
  function validate(schemas) {
35
+ const zodObject = options.defaultSchemaObject === "strict" ? z.strictObject : z.object;
36
+ const missingSchemaHandler = options.missingSchemaBehavior === "empty" ? zodObject({}) : z.any();
27
37
  const validation = {
28
- params: isZodType(schemas.params) ? schemas.params : z.strictObject(schemas.params ?? {}),
29
- query: isZodType(schemas.query) ? schemas.query : z.strictObject(schemas.query ?? {}),
30
- body: isZodType(schemas.body) ? schemas.body : z.strictObject(schemas.body ?? {})
38
+ params: missingSchemaHandler,
39
+ query: missingSchemaHandler,
40
+ body: missingSchemaHandler
31
41
  };
42
+ for (const type of types) {
43
+ if (schemas[type]) {
44
+ validation[type] = isZodType(schemas[type]) ? schemas[type] : zodObject(schemas[type]);
45
+ }
46
+ }
32
47
  return async (req, res, next) => {
33
48
  const errors = [];
34
49
  for (const type of types) {
@@ -37,18 +52,20 @@ function validate(schemas) {
37
52
  else errors.push({ type, errors: parsed.error });
38
53
  }
39
54
  if (errors.length > 0) {
40
- const handler = schemas.handler ?? globalErrorHandler;
55
+ const handler = schemas.handler ?? options.handler;
41
56
  return handler(errors, req, res, next);
42
57
  }
43
58
  return next();
44
59
  };
45
60
  }
46
61
  function setGlobalErrorHandler(handler) {
47
- globalErrorHandler = handler;
62
+ options.handler = handler;
48
63
  }
49
64
  export {
65
+ DEFAULT_OPTIONS,
50
66
  validate as default,
51
67
  defaultErrorHandler,
52
- setGlobalErrorHandler
68
+ setGlobalErrorHandler,
69
+ setGlobalOptions
53
70
  };
54
71
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/// <reference types=\"./express.d.ts\" />\nimport type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport express from 'express';\nimport { type ZodError, type ZodRawShape, type ZodType, z } from 'zod';\n\nconst types = ['query', 'params', 'body'] as const;\n\nexport const defaultErrorHandler: ErrorRequestHandler = (errors, _req, res) => {\n\tres.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));\n};\n\nlet globalErrorHandler = defaultErrorHandler;\n\n/**\n * A ZodType type guard.\n * @param schema The Zod schema to check.\n * @returns Whether the provided schema is a ZodType.\n */\nfunction isZodType(schema: unknown): schema is ZodType {\n\treturn !!schema && typeof (schema as ZodType).safeParseAsync === 'function';\n}\n\n// Override express@^5 request.query getter to provider setter\nconst descriptor = Object.getOwnPropertyDescriptor(express.request, 'query');\nif (descriptor) {\n\tObject.defineProperty(express.request, 'query', {\n\t\tget(this: Request) {\n\t\t\tif (Object.hasOwn(this, '_query')) return this._query;\n\t\t\treturn descriptor?.get?.call(this);\n\t\t},\n\t\tset(this: Request, query: unknown) {\n\t\t\tthis._query = query;\n\t\t},\n\t\tconfigurable: true,\n\t\tenumerable: true\n\t});\n}\n\n/**\n * Generates a middleware function for Express.js that validates request params, query, and body.\n * This function uses Zod schemas to perform validation against the provided schema definitions.\n *\n * @param schemas - An object containing Zod schemas for params, query, and body. Optional handler for custom error handling.\n * @returns An Express.js middleware function that validates the request based on the provided schemas.\n * It attaches validated data to the request object and sends error details if validation fails.\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n * @example\n * // Example usage in an Express.js route\n * import express from 'express';\n * import validate from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Define your Zod schemas\n * const params = {\n * userId: z.string().uuid(),\n * };\n * const query = {\n * age: z.coerce.number().optional(),\n * };\n * const body = {\n * name: z.string(),\n * email: z.string().email(),\n * };\n *\n * // Use the validate middleware in your route\n * app.post('/user/:userId', validate({ params, query, body }), (req, res) => {\n * // Your route logic here\n * res.send('User data is valid!');\n * });\n *\n * app.listen(3000, () => console.log('Server running on port 3000'));\n */\nexport default function validate<TParams extends ValidationSchema, TQuery extends ValidationSchema, TBody extends ValidationSchema>(\n\tschemas: CompleteValidationSchema<TParams, TQuery, TBody>\n): RequestHandler<ZodOutput<TParams>, any, ZodOutput<TBody>, ZodOutput<TQuery>> {\n\t// Create validation objects for each type\n\tconst validation = {\n\t\tparams: isZodType(schemas.params) ? schemas.params : z.strictObject(schemas.params ?? {}),\n\t\tquery: isZodType(schemas.query) ? schemas.query : z.strictObject(schemas.query ?? {}),\n\t\tbody: isZodType(schemas.body) ? schemas.body : z.strictObject(schemas.body ?? {})\n\t};\n\n\treturn async (req, res, next): Promise<void> => {\n\t\tconst errors: ErrorListItem[] = [];\n\n\t\t// Validate all types (params, query, body)\n\t\tfor (const type of types) {\n\t\t\tconst parsed = await validation[type].safeParseAsync(req[type] ?? {});\n\t\t\tif (parsed.success) req[type] = parsed.data as any;\n\t\t\telse errors.push({ type, errors: parsed.error });\n\t\t}\n\n\t\t// Return all errors if there are any\n\t\tif (errors.length > 0) {\n\t\t\t// If a custom error handler is provided, use it\n\t\t\tconst handler = schemas.handler ?? globalErrorHandler;\n\t\t\treturn handler(errors, req, res, next);\n\t\t}\n\n\t\treturn next();\n\t};\n}\n\nexport function setGlobalErrorHandler(handler: ErrorRequestHandler): void {\n\tglobalErrorHandler = handler;\n}\n\n/**\n * Describes the types of data that can be validated: 'query', 'params', or 'body'.\n */\ntype DataType = (typeof types)[number];\n\n/**\n * Defines the structure of an error item, containing the type of validation that failed (params, query, or body)\n * and the associated ZodError.\n */\nexport interface ErrorListItem {\n\ttype: DataType;\n\terrors: ZodError;\n}\n\nexport type Unvalidated = unknown;\n\n/**\n * Represents an Express.js error request handler where the params, query and body are of unknown type as validation failed.\n */\nexport type ErrorRequestHandler<\n\tP = Unvalidated,\n\tResBody = any,\n\tReqBody = Unvalidated,\n\tReqQuery = unknown,\n\tLocalsObj extends Record<string, any> = Record<string, any>\n> = (\n\terr: ErrorListItem[],\n\treq: Request<P, ResBody, ReqBody, ReqQuery, LocalsObj>,\n\tres: Response<ResBody, LocalsObj>,\n\tnext: NextFunction\n) => void | Promise<void>;\n\n/**\n * Represents a generic type for route validation, which can be applied to params, query, or body.\n * Each key-value pair represents a field and its corresponding Zod validation schema.\n */\nexport type ValidationSchema = ZodType | ZodRawShape;\n\n/**\n * Defines the structure for the schemas provided to the validate middleware.\n * Each property corresponds to a different part of the request (params, query, body)\n * and should be a record of Zod types for validation. Optional handler for custom error handling.\n *\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n */\nexport interface CompleteValidationSchema<\n\tTParams extends ValidationSchema = ValidationSchema,\n\tTQuery extends ValidationSchema = ValidationSchema,\n\tTBody extends ValidationSchema = ValidationSchema\n> {\n\thandler?: ErrorRequestHandler;\n\tparams?: TParams;\n\tquery?: TQuery;\n\tbody?: TBody;\n}\n\n/**\n * Represents the output type of a Zod validation schema.\n * This is used to infer the TypeScript type from a Zod schema,\n * providing typesafe access to the validated data.\n *\n * @template T - The validation type (params, query, or body).\n */\nexport type ZodOutput<T extends ValidationSchema | undefined> = T extends ValidationSchema\n\t? z.output<T extends ZodRawShape ? z.ZodObject<T> : T>\n\t: Unvalidated;\n\n/**\n * A utility type to ensure other middleware types don't conflict with the validate middleware.\n */\nexport type WeakRequestHandler = RequestHandler<Unvalidated, Unvalidated, Unvalidated, Unvalidated>;\n\n/**\n * A utility type to ensure the Request is typed correctly.\n * @template T - The validation schema to be applied to the request params, query and body.\n * @example\n * import { ValidatedRequest } from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const schema = {\n * \tquery: {\n * \t\tname: z.string().min(3).max(10),\n * \t\tage: z.coerce.number().min(18)\n * \t},\n * \tbody: {\n * \t\ttitle: z.string().max(4)\n * \t},\n * \tparams: {\n * \t\tid: z.coerce.number()\n * \t}\n * };\n *\n * const requestHandler = (req: ValidatedRequest<typeof schema>, res: Response) => {\n * \tconst { name, age } = req.query;\n * \tconst { id } = req.params;\n * const { title } = req.body;\n *\n * \tres.send(`Hello ${title} ${name}! (Your age is ${age} and your ID is ${id})`);\n * };\n *\n * app.post('/handler/:id', validate(schema), requestHandler);\n */\nexport type ValidatedRequest<T extends CompleteValidationSchema> = Request<\n\tZodOutput<T['params']>,\n\tany,\n\tZodOutput<T['body']>,\n\tZodOutput<T['query']>\n>;\n"],"mappings":";AAEA,OAAO,aAAa;AACpB,SAAwD,SAAS;AAEjE,IAAM,QAAQ,CAAC,SAAS,UAAU,MAAM;AAEjC,IAAM,sBAA2C,CAAC,QAAQ,MAAM,QAAQ;AAC9E,MAAI,OAAO,GAAG,EAAE,KAAK,OAAO,IAAI,YAAU,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,OAAO,OAAO,EAAE,CAAC;AAC9F;AAEA,IAAI,qBAAqB;AAOzB,SAAS,UAAU,QAAoC;AACtD,SAAO,CAAC,CAAC,UAAU,OAAQ,OAAmB,mBAAmB;AAClE;AAGA,IAAM,aAAa,OAAO,yBAAyB,QAAQ,SAAS,OAAO;AAC3E,IAAI,YAAY;AACf,SAAO,eAAe,QAAQ,SAAS,SAAS;AAAA,IAC/C,MAAmB;AAClB,UAAI,OAAO,OAAO,MAAM,QAAQ,EAAG,QAAO,KAAK;AAC/C,aAAO,YAAY,KAAK,KAAK,IAAI;AAAA,IAClC;AAAA,IACA,IAAmB,OAAgB;AAClC,WAAK,SAAS;AAAA,IACf;AAAA,IACA,cAAc;AAAA,IACd,YAAY;AAAA,EACb,CAAC;AACF;AAyCe,SAAR,SACN,SAC+E;AAE/E,QAAM,aAAa;AAAA,IAClB,QAAQ,UAAU,QAAQ,MAAM,IAAI,QAAQ,SAAS,EAAE,aAAa,QAAQ,UAAU,CAAC,CAAC;AAAA,IACxF,OAAO,UAAU,QAAQ,KAAK,IAAI,QAAQ,QAAQ,EAAE,aAAa,QAAQ,SAAS,CAAC,CAAC;AAAA,IACpF,MAAM,UAAU,QAAQ,IAAI,IAAI,QAAQ,OAAO,EAAE,aAAa,QAAQ,QAAQ,CAAC,CAAC;AAAA,EACjF;AAEA,SAAO,OAAO,KAAK,KAAK,SAAwB;AAC/C,UAAM,SAA0B,CAAC;AAGjC,eAAW,QAAQ,OAAO;AACzB,YAAM,SAAS,MAAM,WAAW,IAAI,EAAE,eAAe,IAAI,IAAI,KAAK,CAAC,CAAC;AACpE,UAAI,OAAO,QAAS,KAAI,IAAI,IAAI,OAAO;AAAA,UAClC,QAAO,KAAK,EAAE,MAAM,QAAQ,OAAO,MAAM,CAAC;AAAA,IAChD;AAGA,QAAI,OAAO,SAAS,GAAG;AAEtB,YAAM,UAAU,QAAQ,WAAW;AACnC,aAAO,QAAQ,QAAQ,KAAK,KAAK,IAAI;AAAA,IACtC;AAEA,WAAO,KAAK;AAAA,EACb;AACD;AAEO,SAAS,sBAAsB,SAAoC;AACzE,uBAAqB;AACtB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/// <reference types='./express.d.ts' />\nimport type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport express from 'express';\nimport { type ZodError, type ZodRawShape, type ZodType, z } from 'zod';\n\nconst types = ['query', 'params', 'body'] as const;\n\nexport const defaultErrorHandler: ErrorRequestHandler = (errors, _req, res) => {\n\tres.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));\n};\n\nexport interface ValidateRequestGlobalOptions {\n\t/**\n\t * The error handler to use for all routes if no handler is provided in the schema.\n\t */\n\thandler: ErrorRequestHandler;\n\t/**\n\t * The default schema object type to use for validation when a plain object is provided.\n\t *\n\t * When using `validate({ query: { a: z.string() } })`:\n\t * - `'strict'` (default): Uses `z.strictObject`, which rejects extra properties.\n\t * For example, `GET /?a=1&b=2` will fail validation.\n\t * - `'lax'`: Uses `z.object`, which allows extra properties.\n\t * For example, `GET /?a=1&b=2` will succeed, and `req.query` will only contain `{ a: '1' }`.\n\t *\n\t * Note: If you pass a Zod object directly (e.g., `validate({ query: z.object({ a: z.string() }) })`),\n\t * this option has no effect as the provided Zod object is used as-is.\n\t *\n\t * @default 'strict'\n\t * @example\n\t * ```ts\n\t * // Allow extra properties in query params\n\t * setGlobalOptions({ defaultSchemaObject: 'lax' });\n\t *\n\t * app.get('/user', validate({ query: { id: z.string() } }), (req, res) => {\n\t * \t// GET /user?id=123&extra=value will succeed\n\t * \t// req.query will be { id: '123' }\n\t * });\n\t * ```\n\t */\n\tdefaultSchemaObject: 'strict' | 'lax';\n\t/**\n\t * The behavior when a schema is not provided for a particular input type (params, query, or body).\n\t *\n\t * - `'empty'` (default): Validates against an empty strict object (`z.strictObject({})`), which rejects any input.\n\t * - `'any'`: Skips validation entirely for that input type, allowing any data to pass through.\n\t * This is useful when using nested routers where different parts of the route validate different inputs.\n\t *\n\t * @default 'empty'\n\t */\n\tmissingSchemaBehavior: 'empty' | 'any';\n}\n\n/**\n * The default global options for request validation.\n *\n * Default values:\n * - `defaultSchemaObject: 'strict'`\n * - `missingSchemaBehavior: 'empty'`\n * - `handler`: The default error handler sends a 400 status with an array of validation errors (see: {@link defaultErrorHandler}):\n * ```ts\n * (errors, _req, res) => {\n * \tres.status(400).send(errors.map(error => ({ type: error.type, errors: error.errors.issues })));\n * }\n * ```\n */\nexport const DEFAULT_OPTIONS: ValidateRequestGlobalOptions = {\n\thandler: defaultErrorHandler,\n\tdefaultSchemaObject: 'strict',\n\tmissingSchemaBehavior: 'empty'\n};\n\n/**\n * The options object used by the validation middleware.\n * Initialised with {@link DEFAULT_OPTIONS} and can be modified using {@link setGlobalOptions}.\n */\nconst options: ValidateRequestGlobalOptions = DEFAULT_OPTIONS;\n\n/**\n * Sets the global {@link options} for request validation.\n *\n * @param newOptions Partial options to merge with the current global options.\n * @example\n * // Change the error handler\n * setGlobalOptions({\n * \thandler: (errors, req, res) => {\n * \t\tres.status(422).json({ validationErrors: errors });\n * \t}\n * });\n *\n * // Change default schema object type\n * setGlobalOptions({ defaultSchemaObject: 'lax' });\n *\n * // Change missing schema behavior\n * setGlobalOptions({ missingSchemaBehavior: 'any' });\n *\n * // Change all options\n * setGlobalOptions({\n * \thandler: customHandler,\n * \tdefaultSchemaObject: 'lax',\n * \tmissingSchemaBehavior: 'any'\n * });\n */\nexport const setGlobalOptions = (newOptions: Partial<ValidateRequestGlobalOptions>) => {\n\tObject.assign(options, newOptions);\n};\n\n/**\n * A ZodType type guard.\n * @param schema The Zod schema to check.\n * @returns Whether the provided schema is a ZodType.\n */\nfunction isZodType(schema: unknown): schema is ZodType {\n\treturn !!schema && typeof (schema as ZodType).safeParseAsync === 'function';\n}\n\n// Override express@^5 request.query getter to provider setter\nconst descriptor = Object.getOwnPropertyDescriptor(express.request, 'query');\nif (descriptor) {\n\tObject.defineProperty(express.request, 'query', {\n\t\tget(this: Request) {\n\t\t\tif (Object.hasOwn(this, '_query')) return this._query;\n\t\t\treturn descriptor?.get?.call(this);\n\t\t},\n\t\tset(this: Request, query: unknown) {\n\t\t\tthis._query = query;\n\t\t},\n\t\tconfigurable: true,\n\t\tenumerable: true\n\t});\n}\n\n/**\n * Generates a middleware function for Express.js that validates request params, query, and body.\n * This function uses Zod schemas to perform validation against the provided schema definitions.\n *\n * **Missing Schema Behavior**: If a schema is not provided for a particular input type (params, query, or body),\n * the behavior is controlled by the {@link ValidateRequestGlobalOptions.missingSchemaBehavior} option:\n * - `'empty'` (default): Validates against an empty strict object, rejecting any input\n * - `'any'`: Skips validation entirely, allowing any data to pass through\n *\n * This allows you to validate only the parts of the request you care about when using nested routers.\n *\n * @param schemas - An object containing Zod schemas for params, query, and body. All fields are optional.\n * If a field is omitted, behavior depends on {@link ValidateRequestGlobalOptions.missingSchemaBehavior}.\n * Optional handler for custom error handling.\n * @returns An Express.js middleware function that validates the request based on the provided schemas.\n * It attaches validated data to the request object and sends error details if validation fails.\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n * @example\n * // Example usage in an Express.js route\n * import express from 'express';\n * import validate from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Define your Zod schemas\n * const params = {\n * userId: z.string().uuid(),\n * };\n * const query = {\n * age: z.coerce.number().optional(),\n * };\n * const body = {\n * name: z.string(),\n * email: z.string().email(),\n * };\n *\n * // Use the validate middleware in your route\n * app.post('/user/:userId', validate({ params, query, body }), (req, res) => {\n * // Your route logic here\n * res.send('User data is valid!');\n * });\n *\n * // Only validate params, allow any query or body\n * setGlobalOptions({ missingSchemaBehavior: 'any' });\n * app.use('/:id', validate({ params: { id: z.string().uuid() } }), nestedRouter);\n *\n * app.listen(3000, () => console.log('Server running on port 3000'));\n */\nexport default function validate<TParams extends ValidationSchema, TQuery extends ValidationSchema, TBody extends ValidationSchema>(\n\tschemas: CompleteValidationSchema<TParams, TQuery, TBody>\n): RequestHandler<ZodOutput<TParams>, any, ZodOutput<TBody>, ZodOutput<TQuery>> {\n\t// Set validation objects for each type\n\tconst zodObject = options.defaultSchemaObject === 'strict' ? z.strictObject : z.object;\n\n\t// Initialise validation objects for each type\n\tconst missingSchemaHandler = options.missingSchemaBehavior === 'empty' ? zodObject({}) : z.any();\n\tconst validation: Record<DataType, ZodType> = {\n\t\tparams: missingSchemaHandler,\n\t\tquery: missingSchemaHandler,\n\t\tbody: missingSchemaHandler\n\t};\n\n\tfor (const type of types) {\n\t\tif (schemas[type]) {\n\t\t\tvalidation[type] = isZodType(schemas[type]) ? schemas[type] : zodObject(schemas[type]);\n\t\t}\n\t}\n\n\treturn async (req, res, next): Promise<void> => {\n\t\tconst errors: ErrorListItem[] = [];\n\n\t\t// Validate all types (params, query, body)\n\t\tfor (const type of types) {\n\t\t\tconst parsed = await validation[type].safeParseAsync(req[type] ?? {});\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: type specified in function signature\n\t\t\tif (parsed.success) req[type] = parsed.data as any;\n\t\t\telse errors.push({ type, errors: parsed.error });\n\t\t}\n\n\t\t// Return all errors if there are any\n\t\tif (errors.length > 0) {\n\t\t\t// If a custom error handler is provided, use it\n\t\t\tconst handler = schemas.handler ?? options.handler;\n\t\t\treturn handler(errors, req, res, next);\n\t\t}\n\n\t\treturn next();\n\t};\n}\n\n/**\n * Sets the global error handler for all routes.\n * @param handler The error handler to set.\n * @deprecated Use {@link setGlobalOptions} instead.\n */\nexport function setGlobalErrorHandler(handler: ErrorRequestHandler): void {\n\toptions.handler = handler;\n}\n\n/**\n * Describes the types of data that can be validated: 'query', 'params', or 'body'.\n */\ntype DataType = (typeof types)[number];\n\n/**\n * Defines the structure of an error item, containing the type of validation that failed (params, query, or body)\n * and the associated ZodError.\n */\nexport interface ErrorListItem {\n\ttype: DataType;\n\terrors: ZodError;\n}\n\nexport type Unvalidated = unknown;\n\n/**\n * Represents an Express.js error request handler where the params, query and body are of unknown type as validation failed.\n */\nexport type ErrorRequestHandler<\n\tP = Unvalidated,\n\tResBody = any,\n\tReqBody = Unvalidated,\n\tReqQuery = unknown,\n\tLocalsObj extends Record<string, any> = Record<string, any>\n> = (\n\terr: ErrorListItem[],\n\treq: Request<P, ResBody, ReqBody, ReqQuery, LocalsObj>,\n\tres: Response<ResBody, LocalsObj>,\n\tnext: NextFunction\n) => void | Promise<void>;\n\n/**\n * Represents a generic type for route validation, which can be applied to params, query, or body.\n * Each key-value pair represents a field and its corresponding Zod validation schema.\n */\nexport type ValidationSchema = ZodType | ZodRawShape;\n\n/**\n * Defines the structure for the schemas provided to the validate middleware.\n * Each property corresponds to a different part of the request (params, query, body)\n * and should be a record of Zod types for validation. Optional handler for custom error handling.\n *\n * @template TParams - Type definition for params schema.\n * @template TQuery - Type definition for query schema.\n * @template TBody - Type definition for body schema.\n */\nexport interface CompleteValidationSchema<\n\tTParams extends ValidationSchema = ValidationSchema,\n\tTQuery extends ValidationSchema = ValidationSchema,\n\tTBody extends ValidationSchema = ValidationSchema\n> {\n\thandler?: ErrorRequestHandler;\n\tparams?: TParams;\n\tquery?: TQuery;\n\tbody?: TBody;\n}\n\n/**\n * Represents the output type of a Zod validation schema.\n * This is used to infer the TypeScript type from a Zod schema,\n * providing typesafe access to the validated data.\n *\n * @template T - The validation type (params, query, or body).\n */\nexport type ZodOutput<T extends ValidationSchema | undefined> = T extends ValidationSchema\n\t? z.output<T extends ZodRawShape ? z.ZodObject<T> : T>\n\t: Unvalidated;\n\n/**\n * A utility type to ensure other middleware types don't conflict with the validate middleware.\n */\nexport type WeakRequestHandler = RequestHandler<Unvalidated, Unvalidated, Unvalidated, Unvalidated>;\n\n/**\n * A utility type to ensure the Request is typed correctly.\n * @template T - The validation schema to be applied to the request params, query and body.\n * @example\n * import { ValidatedRequest } from 'express-zod-safe';\n * import { z } from 'zod';\n *\n * const schema = {\n * \tquery: {\n * \t\tname: z.string().min(3).max(10),\n * \t\tage: z.coerce.number().min(18)\n * \t},\n * \tbody: {\n * \t\ttitle: z.string().max(4)\n * \t},\n * \tparams: {\n * \t\tid: z.coerce.number()\n * \t}\n * };\n *\n * const requestHandler = (req: ValidatedRequest<typeof schema>, res: Response) => {\n * \tconst { name, age } = req.query;\n * \tconst { id } = req.params;\n * const { title } = req.body;\n *\n * \tres.send(`Hello ${title} ${name}! (Your age is ${age} and your ID is ${id})`);\n * };\n *\n * app.post('/handler/:id', validate(schema), requestHandler);\n */\nexport type ValidatedRequest<T extends CompleteValidationSchema> = Request<\n\tZodOutput<T['params']>,\n\tany,\n\tZodOutput<T['body']>,\n\tZodOutput<T['query']>\n>;\n"],"mappings":";AAEA,OAAO,aAAa;AACpB,SAAwD,SAAS;AAEjE,IAAM,QAAQ,CAAC,SAAS,UAAU,MAAM;AAEjC,IAAM,sBAA2C,CAAC,QAAQ,MAAM,QAAQ;AAC9E,MAAI,OAAO,GAAG,EAAE,KAAK,OAAO,IAAI,YAAU,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,OAAO,OAAO,EAAE,CAAC;AAC9F;AAyDO,IAAM,kBAAgD;AAAA,EAC5D,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,uBAAuB;AACxB;AAMA,IAAM,UAAwC;AA2BvC,IAAM,mBAAmB,CAAC,eAAsD;AACtF,SAAO,OAAO,SAAS,UAAU;AAClC;AAOA,SAAS,UAAU,QAAoC;AACtD,SAAO,CAAC,CAAC,UAAU,OAAQ,OAAmB,mBAAmB;AAClE;AAGA,IAAM,aAAa,OAAO,yBAAyB,QAAQ,SAAS,OAAO;AAC3E,IAAI,YAAY;AACf,SAAO,eAAe,QAAQ,SAAS,SAAS;AAAA,IAC/C,MAAmB;AAClB,UAAI,OAAO,OAAO,MAAM,QAAQ,EAAG,QAAO,KAAK;AAC/C,aAAO,YAAY,KAAK,KAAK,IAAI;AAAA,IAClC;AAAA,IACA,IAAmB,OAAgB;AAClC,WAAK,SAAS;AAAA,IACf;AAAA,IACA,cAAc;AAAA,IACd,YAAY;AAAA,EACb,CAAC;AACF;AAsDe,SAAR,SACN,SAC+E;AAE/E,QAAM,YAAY,QAAQ,wBAAwB,WAAW,EAAE,eAAe,EAAE;AAGhF,QAAM,uBAAuB,QAAQ,0BAA0B,UAAU,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI;AAC/F,QAAM,aAAwC;AAAA,IAC7C,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,EACP;AAEA,aAAW,QAAQ,OAAO;AACzB,QAAI,QAAQ,IAAI,GAAG;AAClB,iBAAW,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC;AAAA,IACtF;AAAA,EACD;AAEA,SAAO,OAAO,KAAK,KAAK,SAAwB;AAC/C,UAAM,SAA0B,CAAC;AAGjC,eAAW,QAAQ,OAAO;AACzB,YAAM,SAAS,MAAM,WAAW,IAAI,EAAE,eAAe,IAAI,IAAI,KAAK,CAAC,CAAC;AAEpE,UAAI,OAAO,QAAS,KAAI,IAAI,IAAI,OAAO;AAAA,UAClC,QAAO,KAAK,EAAE,MAAM,QAAQ,OAAO,MAAM,CAAC;AAAA,IAChD;AAGA,QAAI,OAAO,SAAS,GAAG;AAEtB,YAAM,UAAU,QAAQ,WAAW,QAAQ;AAC3C,aAAO,QAAQ,QAAQ,KAAK,KAAK,IAAI;AAAA,IACtC;AAEA,WAAO,KAAK;AAAA,EACb;AACD;AAOO,SAAS,sBAAsB,SAAoC;AACzE,UAAQ,UAAU;AACnB;","names":[]}
package/package.json CHANGED
@@ -1,61 +1,69 @@
1
1
  {
2
- "name": "express-zod-safe",
3
- "version": "3.1.0",
4
- "description": "TypeScript-friendly middleware designed for Express applications, leveraging the robustness of Zod schemas to validate incoming request bodies, parameters, and queries.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": {
11
- "types": "./dist/index.d.mts",
12
- "default": "./dist/index.mjs"
13
- },
14
- "require": {
15
- "types": "./dist/index.d.ts",
16
- "default": "./dist/index.js"
17
- }
18
- }
19
- },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/AngaBlue/express-zod-safe.git"
23
- },
24
- "keywords": [
25
- "zod",
26
- "express",
27
- "middleware",
28
- "validation",
29
- "guard",
30
- "typesafe"
31
- ],
32
- "author": {
33
- "name": "AngaBlue",
34
- "email": "contact@anga.blue",
35
- "url": "https://anga.blue"
36
- },
37
- "license": "MIT",
38
- "bugs": {
39
- "url": "https://github.com/AngaBlue/express-zod-safe/issues"
40
- },
41
- "homepage": "https://github.com/AngaBlue/express-zod-safe#readme",
42
- "devDependencies": {
43
- "@angablue/biome-config": "^1.1.0",
44
- "@biomejs/biome": "^2.1.2",
45
- "@types/node": "^24.1.0",
46
- "tsup": "^8.5.0",
47
- "typescript": "^5.8.3",
48
- "zod": "^4.0.10"
49
- },
50
- "peerDependencies": {
51
- "@types/express": "^4.0.0 || ^5.0.0",
52
- "express": "^4.0.0 || ^5.0.0",
53
- "zod": "^4.0.0"
54
- },
55
- "packageManager": "pnpm@10.17.0",
56
- "scripts": {
57
- "build": "tsup",
58
- "lint": "biome check --fix",
59
- "test": "pnpx tsx ./test/index.ts"
60
- }
61
- }
2
+ "name": "express-zod-safe",
3
+ "version": "3.2.0",
4
+ "description": "TypeScript-friendly middleware designed for Express applications, leveraging the robustness of Zod schemas to validate incoming request bodies, parameters, and queries.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "lint": "biome check --fix",
23
+ "test": "node --import=tsx --test test/index.test.ts && tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
24
+ "test:debug": "node --import=tsx --test --inspect-brk test/index.test.ts"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/AngaBlue/express-zod-safe.git"
29
+ },
30
+ "keywords": [
31
+ "zod",
32
+ "express",
33
+ "middleware",
34
+ "validation",
35
+ "guard",
36
+ "typesafe"
37
+ ],
38
+ "author": {
39
+ "name": "AngaBlue",
40
+ "email": "contact@anga.blue",
41
+ "url": "https://anga.blue"
42
+ },
43
+ "license": "MIT",
44
+ "bugs": {
45
+ "url": "https://github.com/AngaBlue/express-zod-safe/issues"
46
+ },
47
+ "homepage": "https://github.com/AngaBlue/express-zod-safe#readme",
48
+ "devDependencies": {
49
+ "@angablue/biome-config": "^1.1.1",
50
+ "@biomejs/biome": "^2.3.11",
51
+ "@types/node": "^25.0.8",
52
+ "tsup": "^8.5.1",
53
+ "tsx": "^4.21.0",
54
+ "typescript": "^5.9.3",
55
+ "zod": "^4.3.5"
56
+ },
57
+ "peerDependencies": {
58
+ "@types/express": "^4.0.0 || ^5.0.0",
59
+ "express": "^4.0.0 || ^5.0.0",
60
+ "zod": "^4.0.0"
61
+ },
62
+ "pnpm": {
63
+ "onlyBuiltDependencies": [
64
+ "@biomejs/biome",
65
+ "esbuild"
66
+ ]
67
+ },
68
+ "packageManager": "pnpm@10.28.0"
69
+ }