@naturalcycles/backend-lib 9.9.0 → 9.10.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/dist/index.d.ts CHANGED
@@ -28,8 +28,8 @@ export * from './server/serverStatusMiddleware.js';
28
28
  export * from './server/simpleRequestLoggerMiddleware.js';
29
29
  export * from './server/startServer.js';
30
30
  export * from './server/startServer.model.js';
31
- export * from './server/validation/validateMiddleware.js';
31
+ export * from './server/validation/ajvValidateRequest.js';
32
32
  export * from './server/validation/validateRequest.js';
33
- export * from './server/validation/zodValidateMiddleware.js';
33
+ export * from './server/validation/zodValidateRequest.js';
34
34
  export * from './util.js';
35
35
  export { onFinished };
package/dist/index.js CHANGED
@@ -28,8 +28,8 @@ export * from './server/serverStatusMiddleware.js';
28
28
  export * from './server/simpleRequestLoggerMiddleware.js';
29
29
  export * from './server/startServer.js';
30
30
  export * from './server/startServer.model.js';
31
- export * from './server/validation/validateMiddleware.js';
31
+ export * from './server/validation/ajvValidateRequest.js';
32
32
  export * from './server/validation/validateRequest.js';
33
- export * from './server/validation/zodValidateMiddleware.js';
33
+ export * from './server/validation/zodValidateRequest.js';
34
34
  export * from './util.js';
35
35
  export { onFinished };
@@ -0,0 +1,21 @@
1
+ import type { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib';
2
+ import type { BackendRequest } from '../server.model.js';
3
+ import type { ReqValidationOptions } from './validateRequest.js';
4
+ declare class AjvValidateRequest {
5
+ body<T>(req: BackendRequest, schema: AjvSchema<T>, opt?: ReqValidationOptions<AjvValidationError>): T;
6
+ query<T>(req: BackendRequest, schema: AjvSchema<T>, opt?: ReqValidationOptions<AjvValidationError>): T;
7
+ params<T>(req: BackendRequest, schema: AjvSchema<T>, opt?: ReqValidationOptions<AjvValidationError>): T;
8
+ /**
9
+ * Validates `req.headers` against the provided schema.
10
+ *
11
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
12
+ * i.e. schemas that cast values will not have any effect.
13
+ *
14
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
15
+ * Keep in mind that this will also remove all values that are not in the schema.
16
+ */
17
+ headers<T>(req: BackendRequest, schema: AjvSchema<T>, opt?: ReqValidationOptions<AjvValidationError>): T;
18
+ private validate;
19
+ }
20
+ export declare const ajvValidateRequest: AjvValidateRequest;
21
+ export {};
@@ -0,0 +1,71 @@
1
+ import { _get, AppError } from '@naturalcycles/js-lib';
2
+ class AjvValidateRequest {
3
+ body(req, schema, opt = {}) {
4
+ return this.validate(req, 'body', schema, opt);
5
+ }
6
+ query(req, schema, opt = {}) {
7
+ return this.validate(req, 'query', schema, opt);
8
+ }
9
+ params(req, schema, opt = {}) {
10
+ return this.validate(req, 'params', schema, opt);
11
+ }
12
+ /**
13
+ * Validates `req.headers` against the provided schema.
14
+ *
15
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
16
+ * i.e. schemas that cast values will not have any effect.
17
+ *
18
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
19
+ * Keep in mind that this will also remove all values that are not in the schema.
20
+ */
21
+ headers(req, schema, opt = {}) {
22
+ const options = {
23
+ keepOriginal: true,
24
+ ...opt,
25
+ };
26
+ return this.validate(req, 'headers', schema, options);
27
+ }
28
+ validate(req, reqProperty, schema, opt = {}) {
29
+ const value = { ...req[reqProperty] }; // destructure to avoid being mutated by Ajv
30
+ // It will mutate the `value`, but not the original object
31
+ const error = schema.getValidationError(value, {
32
+ objectName: `request ${reqProperty}`,
33
+ });
34
+ if (error) {
35
+ let report;
36
+ if (typeof opt.report === 'boolean') {
37
+ report = opt.report;
38
+ }
39
+ else if (typeof opt.report === 'function') {
40
+ report = opt.report(error);
41
+ }
42
+ if (opt.redactPaths) {
43
+ redact(opt.redactPaths, req[reqProperty], error);
44
+ }
45
+ throw new AppError(error.message, {
46
+ backendResponseStatusCode: 400,
47
+ report,
48
+ ...error.data,
49
+ });
50
+ }
51
+ // mutate req to replace the property with the value, converted by Joi
52
+ if (!opt.keepOriginal && reqProperty !== 'query') {
53
+ // query is read-only in Express 5
54
+ req[reqProperty] = value;
55
+ }
56
+ return value;
57
+ }
58
+ }
59
+ export const ajvValidateRequest = new AjvValidateRequest();
60
+ const REDACTED = 'REDACTED';
61
+ /**
62
+ * Mutates error
63
+ */
64
+ function redact(redactPaths, obj, error) {
65
+ redactPaths
66
+ .map(path => _get(obj, path))
67
+ .filter(Boolean)
68
+ .forEach(secret => {
69
+ error.message = error.message.replaceAll(secret, REDACTED);
70
+ });
71
+ }
@@ -1,17 +1,5 @@
1
1
  import { _get, AppError } from '@naturalcycles/js-lib';
2
2
  import { getValidationResult } from '@naturalcycles/nodejs-lib';
3
- const REDACTED = 'REDACTED';
4
- /**
5
- * Mutates error
6
- */
7
- function redact(redactPaths, obj, error) {
8
- redactPaths
9
- .map(path => _get(obj, path))
10
- .filter(Boolean)
11
- .forEach(secret => {
12
- error.message = error.message.replaceAll(secret, REDACTED);
13
- });
14
- }
15
3
  class ValidateRequest {
16
4
  body(req, schema, opt = {}) {
17
5
  return this.validate(req, 'body', schema, opt);
@@ -68,3 +56,15 @@ class ValidateRequest {
68
56
  }
69
57
  }
70
58
  export const validateRequest = new ValidateRequest();
59
+ const REDACTED = 'REDACTED';
60
+ /**
61
+ * Mutates error
62
+ */
63
+ function redact(redactPaths, obj, error) {
64
+ redactPaths
65
+ .map(path => _get(obj, path))
66
+ .filter(Boolean)
67
+ .forEach(secret => {
68
+ error.message = error.message.replaceAll(secret, REDACTED);
69
+ });
70
+ }
@@ -0,0 +1,21 @@
1
+ import { type ZodType, type ZodValidationError } from '@naturalcycles/js-lib/zod';
2
+ import type { BackendRequest } from '../server.model.js';
3
+ import type { ReqValidationOptions } from './validateRequest.js';
4
+ declare class ZodValidateRequest {
5
+ body<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
6
+ query<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
7
+ params<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
8
+ /**
9
+ * Validates `req.headers` against the provided schema.
10
+ *
11
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
12
+ * i.e. schemas that cast values will not have any effect.
13
+ *
14
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
15
+ * Keep in mind that this will also remove all values that are not in the schema.
16
+ */
17
+ headers<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
18
+ private validate;
19
+ }
20
+ export declare const zodValidateRequest: ZodValidateRequest;
21
+ export {};
@@ -0,0 +1,68 @@
1
+ import { _get, AppError } from '@naturalcycles/js-lib';
2
+ import { zSafeValidate } from '@naturalcycles/js-lib/zod';
3
+ class ZodValidateRequest {
4
+ body(req, schema, opt = {}) {
5
+ return this.validate(req, 'body', schema, opt);
6
+ }
7
+ query(req, schema, opt = {}) {
8
+ return this.validate(req, 'query', schema, opt);
9
+ }
10
+ params(req, schema, opt = {}) {
11
+ return this.validate(req, 'params', schema, opt);
12
+ }
13
+ /**
14
+ * Validates `req.headers` against the provided schema.
15
+ *
16
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
17
+ * i.e. schemas that cast values will not have any effect.
18
+ *
19
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
20
+ * Keep in mind that this will also remove all values that are not in the schema.
21
+ */
22
+ headers(req, schema, opt = {}) {
23
+ const options = {
24
+ keepOriginal: true,
25
+ ...opt,
26
+ };
27
+ return this.validate(req, 'headers', schema, options);
28
+ }
29
+ validate(req, reqProperty, schema, opt = {}) {
30
+ const { data, error } = zSafeValidate(req[reqProperty] || {}, schema);
31
+ if (error) {
32
+ let report;
33
+ if (typeof opt.report === 'boolean') {
34
+ report = opt.report;
35
+ }
36
+ else if (typeof opt.report === 'function') {
37
+ report = opt.report(error);
38
+ }
39
+ if (opt.redactPaths) {
40
+ redact(opt.redactPaths, req[reqProperty], error);
41
+ }
42
+ throw new AppError(error.message, {
43
+ backendResponseStatusCode: 400,
44
+ report,
45
+ ...error.data,
46
+ });
47
+ }
48
+ // mutate req to replace the property with the value, converted by Joi
49
+ if (!opt.keepOriginal && reqProperty !== 'query') {
50
+ // query is read-only in Express 5
51
+ req[reqProperty] = data;
52
+ }
53
+ return data;
54
+ }
55
+ }
56
+ export const zodValidateRequest = new ZodValidateRequest();
57
+ const REDACTED = 'REDACTED';
58
+ /**
59
+ * Mutates error
60
+ */
61
+ function redact(redactPaths, obj, error) {
62
+ redactPaths
63
+ .map(path => _get(obj, path))
64
+ .filter(Boolean)
65
+ .forEach(secret => {
66
+ error.message = error.message.replaceAll(secret, REDACTED);
67
+ });
68
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
3
  "type": "module",
4
- "version": "9.9.0",
4
+ "version": "9.10.0",
5
5
  "peerDependencies": {
6
6
  "@sentry/node": "^9"
7
7
  },
package/src/index.ts CHANGED
@@ -28,9 +28,9 @@ export * from './server/serverStatusMiddleware.js'
28
28
  export * from './server/simpleRequestLoggerMiddleware.js'
29
29
  export * from './server/startServer.js'
30
30
  export * from './server/startServer.model.js'
31
- export * from './server/validation/validateMiddleware.js'
31
+ export * from './server/validation/ajvValidateRequest.js'
32
32
  export * from './server/validation/validateRequest.js'
33
- export * from './server/validation/zodValidateMiddleware.js'
33
+ export * from './server/validation/zodValidateRequest.js'
34
34
  export * from './util.js'
35
35
 
36
36
  export { onFinished }
@@ -0,0 +1,107 @@
1
+ import { _get, AppError } from '@naturalcycles/js-lib'
2
+ import type { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib'
3
+ import type { BackendRequest } from '../server.model.js'
4
+ import type { ReqValidationOptions } from './validateRequest.js'
5
+
6
+ class AjvValidateRequest {
7
+ body<T>(
8
+ req: BackendRequest,
9
+ schema: AjvSchema<T>,
10
+ opt: ReqValidationOptions<AjvValidationError> = {},
11
+ ): T {
12
+ return this.validate(req, 'body', schema, opt)
13
+ }
14
+
15
+ query<T>(
16
+ req: BackendRequest,
17
+ schema: AjvSchema<T>,
18
+ opt: ReqValidationOptions<AjvValidationError> = {},
19
+ ): T {
20
+ return this.validate(req, 'query', schema, opt)
21
+ }
22
+
23
+ params<T>(
24
+ req: BackendRequest,
25
+ schema: AjvSchema<T>,
26
+ opt: ReqValidationOptions<AjvValidationError> = {},
27
+ ): T {
28
+ return this.validate(req, 'params', schema, opt)
29
+ }
30
+
31
+ /**
32
+ * Validates `req.headers` against the provided schema.
33
+ *
34
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
35
+ * i.e. schemas that cast values will not have any effect.
36
+ *
37
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
38
+ * Keep in mind that this will also remove all values that are not in the schema.
39
+ */
40
+ headers<T>(
41
+ req: BackendRequest,
42
+ schema: AjvSchema<T>,
43
+ opt: ReqValidationOptions<AjvValidationError> = {},
44
+ ): T {
45
+ const options: ReqValidationOptions<AjvValidationError> = {
46
+ keepOriginal: true,
47
+ ...opt,
48
+ }
49
+ return this.validate(req, 'headers', schema, options)
50
+ }
51
+
52
+ private validate<T>(
53
+ req: BackendRequest,
54
+ reqProperty: 'body' | 'params' | 'query' | 'headers',
55
+ schema: AjvSchema<T>,
56
+ opt: ReqValidationOptions<AjvValidationError> = {},
57
+ ): T {
58
+ const value: T = { ...req[reqProperty] } // destructure to avoid being mutated by Ajv
59
+ // It will mutate the `value`, but not the original object
60
+ const error = schema.getValidationError(value, {
61
+ objectName: `request ${reqProperty}`,
62
+ })
63
+
64
+ if (error) {
65
+ let report: boolean | undefined
66
+ if (typeof opt.report === 'boolean') {
67
+ report = opt.report
68
+ } else if (typeof opt.report === 'function') {
69
+ report = opt.report(error)
70
+ }
71
+
72
+ if (opt.redactPaths) {
73
+ redact(opt.redactPaths, req[reqProperty], error)
74
+ }
75
+
76
+ throw new AppError(error.message, {
77
+ backendResponseStatusCode: 400,
78
+ report,
79
+ ...error.data,
80
+ })
81
+ }
82
+
83
+ // mutate req to replace the property with the value, converted by Joi
84
+ if (!opt.keepOriginal && reqProperty !== 'query') {
85
+ // query is read-only in Express 5
86
+ req[reqProperty] = value
87
+ }
88
+
89
+ return value
90
+ }
91
+ }
92
+
93
+ export const ajvValidateRequest = new AjvValidateRequest()
94
+
95
+ const REDACTED = 'REDACTED'
96
+
97
+ /**
98
+ * Mutates error
99
+ */
100
+ function redact(redactPaths: string[], obj: any, error: Error): void {
101
+ redactPaths
102
+ .map(path => _get(obj, path) as string)
103
+ .filter(Boolean)
104
+ .forEach(secret => {
105
+ error.message = error.message.replaceAll(secret, REDACTED)
106
+ })
107
+ }
@@ -3,8 +3,6 @@ import type { AnySchema, JoiValidationError } from '@naturalcycles/nodejs-lib'
3
3
  import { getValidationResult } from '@naturalcycles/nodejs-lib'
4
4
  import type { BackendRequest } from '../server.model.js'
5
5
 
6
- const REDACTED = 'REDACTED'
7
-
8
6
  export interface ReqValidationOptions<ERR extends Error> {
9
7
  /**
10
8
  * Pass a 'dot-paths' (e.g `pw`, or `input.pw`) that needs to be redacted from the output, in case of error.
@@ -26,18 +24,6 @@ export interface ReqValidationOptions<ERR extends Error> {
26
24
  keepOriginal?: boolean
27
25
  }
28
26
 
29
- /**
30
- * Mutates error
31
- */
32
- function redact(redactPaths: string[], obj: any, error: Error): void {
33
- redactPaths
34
- .map(path => _get(obj, path) as string)
35
- .filter(Boolean)
36
- .forEach(secret => {
37
- error.message = error.message.replaceAll(secret, REDACTED)
38
- })
39
- }
40
-
41
27
  class ValidateRequest {
42
28
  body<T>(
43
29
  req: BackendRequest,
@@ -127,3 +113,17 @@ class ValidateRequest {
127
113
  }
128
114
 
129
115
  export const validateRequest = new ValidateRequest()
116
+
117
+ const REDACTED = 'REDACTED'
118
+
119
+ /**
120
+ * Mutates error
121
+ */
122
+ function redact(redactPaths: string[], obj: any, error: Error): void {
123
+ redactPaths
124
+ .map(path => _get(obj, path) as string)
125
+ .filter(Boolean)
126
+ .forEach(secret => {
127
+ error.message = error.message.replaceAll(secret, REDACTED)
128
+ })
129
+ }
@@ -0,0 +1,107 @@
1
+ import { _get, AppError } from '@naturalcycles/js-lib'
2
+ import { type ZodType, type ZodValidationError, zSafeValidate } from '@naturalcycles/js-lib/zod'
3
+ import type { BackendRequest } from '../server.model.js'
4
+ import type { ReqValidationOptions } from './validateRequest.js'
5
+
6
+ class ZodValidateRequest {
7
+ body<T>(
8
+ req: BackendRequest,
9
+ schema: ZodType<T>,
10
+ opt: ReqValidationOptions<ZodValidationError> = {},
11
+ ): T {
12
+ return this.validate(req, 'body', schema, opt)
13
+ }
14
+
15
+ query<T>(
16
+ req: BackendRequest,
17
+ schema: ZodType<T>,
18
+ opt: ReqValidationOptions<ZodValidationError> = {},
19
+ ): T {
20
+ return this.validate(req, 'query', schema, opt)
21
+ }
22
+
23
+ params<T>(
24
+ req: BackendRequest,
25
+ schema: ZodType<T>,
26
+ opt: ReqValidationOptions<ZodValidationError> = {},
27
+ ): T {
28
+ return this.validate(req, 'params', schema, opt)
29
+ }
30
+
31
+ /**
32
+ * Validates `req.headers` against the provided schema.
33
+ *
34
+ * Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
35
+ * i.e. schemas that cast values will not have any effect.
36
+ *
37
+ * If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
38
+ * Keep in mind that this will also remove all values that are not in the schema.
39
+ */
40
+ headers<T>(
41
+ req: BackendRequest,
42
+ schema: ZodType<T>,
43
+ opt: ReqValidationOptions<ZodValidationError> = {},
44
+ ): T {
45
+ const options: ReqValidationOptions<ZodValidationError> = {
46
+ keepOriginal: true,
47
+ ...opt,
48
+ }
49
+ return this.validate(req, 'headers', schema, options)
50
+ }
51
+
52
+ private validate<T>(
53
+ req: BackendRequest,
54
+ reqProperty: 'body' | 'params' | 'query' | 'headers',
55
+ schema: ZodType<T>,
56
+ opt: ReqValidationOptions<ZodValidationError> = {},
57
+ ): T {
58
+ const { data, error } = zSafeValidate(
59
+ req[reqProperty] || {},
60
+ schema,
61
+ // `request ${reqProperty}`,
62
+ )
63
+
64
+ if (error) {
65
+ let report: boolean | undefined
66
+ if (typeof opt.report === 'boolean') {
67
+ report = opt.report
68
+ } else if (typeof opt.report === 'function') {
69
+ report = opt.report(error)
70
+ }
71
+
72
+ if (opt.redactPaths) {
73
+ redact(opt.redactPaths, req[reqProperty], error)
74
+ }
75
+
76
+ throw new AppError(error.message, {
77
+ backendResponseStatusCode: 400,
78
+ report,
79
+ ...error.data,
80
+ })
81
+ }
82
+
83
+ // mutate req to replace the property with the value, converted by Joi
84
+ if (!opt.keepOriginal && reqProperty !== 'query') {
85
+ // query is read-only in Express 5
86
+ req[reqProperty] = data
87
+ }
88
+
89
+ return data
90
+ }
91
+ }
92
+
93
+ export const zodValidateRequest = new ZodValidateRequest()
94
+
95
+ const REDACTED = 'REDACTED'
96
+
97
+ /**
98
+ * Mutates error
99
+ */
100
+ function redact(redactPaths: string[], obj: any, error: Error): void {
101
+ redactPaths
102
+ .map(path => _get(obj, path) as string)
103
+ .filter(Boolean)
104
+ .forEach(secret => {
105
+ error.message = error.message.replaceAll(secret, REDACTED)
106
+ })
107
+ }
@@ -1,9 +0,0 @@
1
- import type { JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib';
2
- import type { AjvValidationError } from '@naturalcycles/nodejs-lib';
3
- import { AjvSchema } from '@naturalcycles/nodejs-lib';
4
- import type { BackendRequestHandler } from '../server.model.js';
5
- import type { ReqValidationOptions } from './validateRequest.js';
6
- export declare function validateBody(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
7
- export declare function validateParams(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
8
- export declare function validateQuery(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
9
- export declare function validateHeaders(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
@@ -1,54 +0,0 @@
1
- import { _get, AppError } from '@naturalcycles/js-lib';
2
- import { AjvSchema } from '@naturalcycles/nodejs-lib';
3
- const REDACTED = 'REDACTED';
4
- export function validateBody(schema, opt = {}) {
5
- return validateObject('body', schema, opt);
6
- }
7
- export function validateParams(schema, opt = {}) {
8
- return validateObject('params', schema, opt);
9
- }
10
- export function validateQuery(schema, opt = {}) {
11
- return validateObject('query', schema, opt);
12
- }
13
- export function validateHeaders(schema, opt = {}) {
14
- return validateObject('headers', schema, opt);
15
- }
16
- /**
17
- * Validates req property (body, params or query).
18
- * Supports Joi schema or AjvSchema (from nodejs-lib).
19
- * Able to redact sensitive data from the error message.
20
- * Throws http 400 on error.
21
- */
22
- function validateObject(prop, schema, opt = {}) {
23
- const ajvSchema = AjvSchema.create(schema, {
24
- objectName: `request ${prop}`,
25
- });
26
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
27
- return (req, _res, next) => {
28
- const error = ajvSchema.getValidationError(req[prop] || {});
29
- if (error) {
30
- const report = reportPredicate(error);
31
- if (opt.redactPaths) {
32
- redact(opt.redactPaths, req[prop], error);
33
- error.data.errors.length = 0; // clears the array
34
- }
35
- return next(new AppError(error.message, {
36
- backendResponseStatusCode: 400,
37
- report,
38
- ...error.data,
39
- }));
40
- }
41
- next();
42
- };
43
- }
44
- /**
45
- * Mutates error
46
- */
47
- function redact(redactPaths, obj, error) {
48
- redactPaths
49
- .map(path => _get(obj, path))
50
- .filter(Boolean)
51
- .forEach(secret => {
52
- error.message = error.message.replaceAll(secret, REDACTED);
53
- });
54
- }
@@ -1,10 +0,0 @@
1
- import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod';
2
- import type { BackendRequestHandler } from '../server.model.js';
3
- import type { ReqValidationOptions } from './validateRequest.js';
4
- /**
5
- * Validates req property (body, params or query).
6
- * Supports Joi schema or AjvSchema (from nodejs-lib).
7
- * Able to redact sensitive data from the error message.
8
- * Throws http 400 on error.
9
- */
10
- export declare function zodReqValidate(prop: 'body' | 'params' | 'query', schema: ZodType, opt?: ReqValidationOptions<ZodValidationError>): BackendRequestHandler;
@@ -1,37 +0,0 @@
1
- import { _get, AppError } from '@naturalcycles/js-lib';
2
- import { zSafeValidate } from '@naturalcycles/js-lib/zod';
3
- const REDACTED = 'REDACTED';
4
- /**
5
- * Validates req property (body, params or query).
6
- * Supports Joi schema or AjvSchema (from nodejs-lib).
7
- * Able to redact sensitive data from the error message.
8
- * Throws http 400 on error.
9
- */
10
- export function zodReqValidate(prop, schema, opt = {}) {
11
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
12
- return (req, _res, next) => {
13
- const { error } = zSafeValidate(req[prop] || {}, schema);
14
- if (!error) {
15
- return next();
16
- }
17
- const report = reportPredicate(error);
18
- if (opt.redactPaths) {
19
- redact(opt.redactPaths, req[prop], error);
20
- }
21
- return next(new AppError(error.message, {
22
- backendResponseStatusCode: 400,
23
- report,
24
- }));
25
- };
26
- }
27
- /**
28
- * Mutates error
29
- */
30
- function redact(redactPaths, obj, error) {
31
- redactPaths
32
- .map(path => _get(obj, path))
33
- .filter(Boolean)
34
- .forEach(secret => {
35
- error.message = error.message.replace(secret, REDACTED);
36
- });
37
- }
@@ -1,89 +0,0 @@
1
- import type { JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib'
2
- import { _get, AppError } from '@naturalcycles/js-lib'
3
- import type { AjvValidationError } from '@naturalcycles/nodejs-lib'
4
- import { AjvSchema } from '@naturalcycles/nodejs-lib'
5
- import type { BackendRequestHandler } from '../server.model.js'
6
- import type { ReqValidationOptions } from './validateRequest.js'
7
-
8
- const REDACTED = 'REDACTED'
9
-
10
- export function validateBody(
11
- schema: JsonSchema | JsonSchemaBuilder | AjvSchema,
12
- opt: ReqValidationOptions<AjvValidationError> = {},
13
- ): BackendRequestHandler {
14
- return validateObject('body', schema, opt)
15
- }
16
-
17
- export function validateParams(
18
- schema: JsonSchema | JsonSchemaBuilder | AjvSchema,
19
- opt: ReqValidationOptions<AjvValidationError> = {},
20
- ): BackendRequestHandler {
21
- return validateObject('params', schema, opt)
22
- }
23
-
24
- export function validateQuery(
25
- schema: JsonSchema | JsonSchemaBuilder | AjvSchema,
26
- opt: ReqValidationOptions<AjvValidationError> = {},
27
- ): BackendRequestHandler {
28
- return validateObject('query', schema, opt)
29
- }
30
-
31
- export function validateHeaders(
32
- schema: JsonSchema | JsonSchemaBuilder | AjvSchema,
33
- opt: ReqValidationOptions<AjvValidationError> = {},
34
- ): BackendRequestHandler {
35
- return validateObject('headers', schema, opt)
36
- }
37
-
38
- /**
39
- * Validates req property (body, params or query).
40
- * Supports Joi schema or AjvSchema (from nodejs-lib).
41
- * Able to redact sensitive data from the error message.
42
- * Throws http 400 on error.
43
- */
44
- function validateObject(
45
- prop: 'body' | 'params' | 'query' | 'headers',
46
- schema: JsonSchema | JsonSchemaBuilder | AjvSchema,
47
- opt: ReqValidationOptions<AjvValidationError> = {},
48
- ): BackendRequestHandler {
49
- const ajvSchema = AjvSchema.create(schema, {
50
- objectName: `request ${prop}`,
51
- })
52
-
53
- const reportPredicate =
54
- typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
55
-
56
- return (req, _res, next) => {
57
- const error = ajvSchema.getValidationError(req[prop] || {})
58
- if (error) {
59
- const report = reportPredicate(error)
60
-
61
- if (opt.redactPaths) {
62
- redact(opt.redactPaths, req[prop], error)
63
- error.data.errors.length = 0 // clears the array
64
- }
65
-
66
- return next(
67
- new AppError(error.message, {
68
- backendResponseStatusCode: 400,
69
- report,
70
- ...error.data,
71
- }),
72
- )
73
- }
74
-
75
- next()
76
- }
77
- }
78
-
79
- /**
80
- * Mutates error
81
- */
82
- function redact(redactPaths: string[], obj: any, error: Error): void {
83
- redactPaths
84
- .map(path => _get(obj, path) as string)
85
- .filter(Boolean)
86
- .forEach(secret => {
87
- error.message = error.message.replaceAll(secret, REDACTED)
88
- })
89
- }
@@ -1,54 +0,0 @@
1
- import { _get, AppError } from '@naturalcycles/js-lib'
2
- import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod'
3
- import { zSafeValidate } from '@naturalcycles/js-lib/zod'
4
- import type { BackendRequestHandler } from '../server.model.js'
5
- import type { ReqValidationOptions } from './validateRequest.js'
6
-
7
- const REDACTED = 'REDACTED'
8
-
9
- /**
10
- * Validates req property (body, params or query).
11
- * Supports Joi schema or AjvSchema (from nodejs-lib).
12
- * Able to redact sensitive data from the error message.
13
- * Throws http 400 on error.
14
- */
15
- export function zodReqValidate(
16
- prop: 'body' | 'params' | 'query',
17
- schema: ZodType,
18
- opt: ReqValidationOptions<ZodValidationError> = {},
19
- ): BackendRequestHandler {
20
- const reportPredicate =
21
- typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
22
-
23
- return (req, _res, next) => {
24
- const { error } = zSafeValidate(req[prop] || {}, schema)
25
- if (!error) {
26
- return next()
27
- }
28
-
29
- const report = reportPredicate(error)
30
-
31
- if (opt.redactPaths) {
32
- redact(opt.redactPaths, req[prop], error)
33
- }
34
-
35
- return next(
36
- new AppError(error.message, {
37
- backendResponseStatusCode: 400,
38
- report,
39
- }),
40
- )
41
- }
42
- }
43
-
44
- /**
45
- * Mutates error
46
- */
47
- function redact(redactPaths: string[], obj: any, error: Error): void {
48
- redactPaths
49
- .map(path => _get(obj, path) as string)
50
- .filter(Boolean)
51
- .forEach(secret => {
52
- error.message = error.message.replace(secret, REDACTED)
53
- })
54
- }