@fishka/express 0.9.16 → 0.9.17
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 +39 -46
- package/dist/cjs/api.types.d.ts +5 -5
- package/dist/cjs/api.types.js.map +1 -1
- package/dist/cjs/route-table.d.ts +18 -13
- package/dist/cjs/route-table.js +6 -6
- package/dist/cjs/route-table.js.map +1 -1
- package/dist/cjs/router.d.ts +37 -27
- package/dist/cjs/router.js +92 -82
- package/dist/cjs/router.js.map +1 -1
- package/dist/cjs/utils/type-validators.d.ts +22 -15
- package/dist/cjs/utils/type-validators.js +25 -14
- package/dist/cjs/utils/type-validators.js.map +1 -1
- package/dist/esm/api.types.d.ts +5 -5
- package/dist/esm/api.types.js.map +1 -1
- package/dist/esm/route-table.d.ts +18 -13
- package/dist/esm/route-table.js +6 -6
- package/dist/esm/route-table.js.map +1 -1
- package/dist/esm/router.d.ts +37 -27
- package/dist/esm/router.js +92 -82
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/utils/type-validators.d.ts +22 -15
- package/dist/esm/utils/type-validators.js +21 -11
- package/dist/esm/utils/type-validators.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* URL parameter validators for Express path/query params.
|
|
3
3
|
* All params are strings from Express, so validation starts with string.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { ParamValidator } from '../api.types';
|
|
6
6
|
/** Makes validator optional - returns undefined if value missing */
|
|
7
|
-
export declare function optional<T>(validator:
|
|
7
|
+
export declare function optional<T>(validator: ParamValidator<T>): ParamValidator<T | undefined>;
|
|
8
8
|
/** Operator that transforms string to T */
|
|
9
9
|
export type ParamOperator<T> = (value: string) => T;
|
|
10
10
|
/** Operator that transforms T to R */
|
|
@@ -14,18 +14,18 @@ export type Operator<T, R = T> = (value: T) => R;
|
|
|
14
14
|
* Operators are applied in sequence to validate/transform the value.
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* transform() // string
|
|
18
|
+
* transform(toInt) // number
|
|
19
|
+
* transform(toInt, min(1)) // number >= 1
|
|
20
|
+
* transform(minLength(3)) // string with min length
|
|
21
|
+
* transform(trim, lowercase) // trimmed lowercase string
|
|
22
22
|
*/
|
|
23
|
-
export declare function
|
|
24
|
-
export declare function
|
|
25
|
-
export declare function
|
|
26
|
-
export declare function
|
|
27
|
-
export declare function
|
|
28
|
-
export declare function
|
|
23
|
+
export declare function transform(): ParamValidator<string>;
|
|
24
|
+
export declare function transform<A>(op1: ParamOperator<A>): ParamValidator<A>;
|
|
25
|
+
export declare function transform<A, B>(op1: ParamOperator<A>, op2: Operator<A, B>): ParamValidator<B>;
|
|
26
|
+
export declare function transform<A, B, C>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>): ParamValidator<C>;
|
|
27
|
+
export declare function transform<A, B, C, D>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>): ParamValidator<D>;
|
|
28
|
+
export declare function transform<A, B, C, D, E>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>): ParamValidator<E>;
|
|
29
29
|
/** Parses string to integer */
|
|
30
30
|
export declare const toInt: (message?: string) => ParamOperator<number>;
|
|
31
31
|
/** Parses string to number */
|
|
@@ -52,7 +52,14 @@ export declare const min: (n: number, message?: string) => Operator<number>;
|
|
|
52
52
|
export declare const max: (n: number, message?: string) => Operator<number>;
|
|
53
53
|
/** Requires value to be in range [minVal, maxVal] */
|
|
54
54
|
export declare const range: (minVal: number, maxVal: number, message?: string) => Operator<number>;
|
|
55
|
-
/** Adds custom validation */
|
|
56
|
-
export declare const
|
|
55
|
+
/** Adds custom validation with predicate */
|
|
56
|
+
export declare const assert: <T>(predicate: (value: T) => boolean, message: string) => Operator<T>;
|
|
57
57
|
/** Transforms the value */
|
|
58
58
|
export declare const map: <T, R>(fn: (value: T) => R) => Operator<T, R>;
|
|
59
|
+
/**
|
|
60
|
+
* Creates a simple validator that returns error message or undefined.
|
|
61
|
+
* Can be used directly in transform().
|
|
62
|
+
* @example
|
|
63
|
+
* transform(validator(s => s === 'valid' ? undefined : 'Invalid ID'))
|
|
64
|
+
*/
|
|
65
|
+
export declare function validator<T>(validateFn: (value: T) => string | undefined): (value: T) => T;
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* All params are strings from Express, so validation starts with string.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.map = exports.
|
|
7
|
+
exports.map = exports.assert = exports.range = exports.max = exports.min = exports.uppercase = exports.lowercase = exports.trim = exports.matches = exports.maxLength = exports.minLength = exports.oneOf = exports.toBool = exports.toNumber = exports.toInt = void 0;
|
|
8
8
|
exports.optional = optional;
|
|
9
|
-
exports.
|
|
9
|
+
exports.transform = transform;
|
|
10
|
+
exports.validator = validator;
|
|
10
11
|
const assertions_1 = require("@fishka/assertions");
|
|
11
12
|
/** Makes validator optional - returns undefined if value missing */
|
|
12
13
|
function optional(validator) {
|
|
@@ -17,7 +18,7 @@ function optional(validator) {
|
|
|
17
18
|
return validator(value);
|
|
18
19
|
};
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function transform(...operators) {
|
|
21
22
|
return (value) => {
|
|
22
23
|
(0, assertions_1.assertTruthy)(typeof value === 'string', `Expected string, got ${typeof value}`);
|
|
23
24
|
let result = value;
|
|
@@ -27,11 +28,10 @@ function param(...operators) {
|
|
|
27
28
|
return result;
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
|
-
// ============================================================================
|
|
31
31
|
// String → T operators (first in chain)
|
|
32
|
-
// ============================================================================
|
|
33
32
|
/** Parses string to integer */
|
|
34
33
|
const toInt = (message) => (value) => {
|
|
34
|
+
(0, assertions_1.assertTruthy)(value !== undefined && value !== null && value !== '', message ?? 'Expected integer, got undefined or empty');
|
|
35
35
|
const num = Number(value);
|
|
36
36
|
(0, assertions_1.assertTruthy)(Number.isInteger(num), message ?? `Expected integer, got '${value}'`);
|
|
37
37
|
return num;
|
|
@@ -39,6 +39,7 @@ const toInt = (message) => (value) => {
|
|
|
39
39
|
exports.toInt = toInt;
|
|
40
40
|
/** Parses string to number */
|
|
41
41
|
const toNumber = (message) => (value) => {
|
|
42
|
+
(0, assertions_1.assertTruthy)(value !== undefined && value !== null && value !== '', message ?? 'Expected number, got undefined or empty');
|
|
42
43
|
const num = Number(value);
|
|
43
44
|
(0, assertions_1.assertTruthy)(!isNaN(num), message ?? `Expected number, got '${value}'`);
|
|
44
45
|
return num;
|
|
@@ -46,6 +47,7 @@ const toNumber = (message) => (value) => {
|
|
|
46
47
|
exports.toNumber = toNumber;
|
|
47
48
|
/** Parses string to boolean ('true'/'false') */
|
|
48
49
|
const toBool = (message) => (value) => {
|
|
50
|
+
(0, assertions_1.assertTruthy)(value !== undefined && value !== null && value !== '', message ?? 'Expected boolean, got undefined or empty');
|
|
49
51
|
(0, assertions_1.assertTruthy)(value === 'true' || value === 'false', message ?? `Expected 'true' or 'false', got '${value}'`);
|
|
50
52
|
return value === 'true';
|
|
51
53
|
};
|
|
@@ -56,9 +58,7 @@ const oneOf = (...allowedValues) => (value) => {
|
|
|
56
58
|
return value;
|
|
57
59
|
};
|
|
58
60
|
exports.oneOf = oneOf;
|
|
59
|
-
// ============================================================================
|
|
60
61
|
// String operators (string → string)
|
|
61
|
-
// ============================================================================
|
|
62
62
|
/** Requires minimum string length */
|
|
63
63
|
const minLength = (n, message) => (value) => {
|
|
64
64
|
(0, assertions_1.assertTruthy)(value.length >= n, message ?? `Must be at least ${n} characters`);
|
|
@@ -86,9 +86,7 @@ exports.lowercase = lowercase;
|
|
|
86
86
|
/** Converts string to uppercase */
|
|
87
87
|
const uppercase = (value) => value.toUpperCase();
|
|
88
88
|
exports.uppercase = uppercase;
|
|
89
|
-
// ============================================================================
|
|
90
89
|
// Number operators (number → number)
|
|
91
|
-
// ============================================================================
|
|
92
90
|
/** Requires minimum value */
|
|
93
91
|
const min = (n, message) => (value) => {
|
|
94
92
|
(0, assertions_1.assertTruthy)(value >= n, message ?? `Must be at least ${n}`);
|
|
@@ -107,16 +105,29 @@ const range = (minVal, maxVal, message) => (value) => {
|
|
|
107
105
|
return value;
|
|
108
106
|
};
|
|
109
107
|
exports.range = range;
|
|
110
|
-
// ============================================================================
|
|
111
108
|
// Generic operators
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const check = (predicate, message) => (value) => {
|
|
109
|
+
/** Adds custom validation with predicate */
|
|
110
|
+
const assert = (predicate, message) => (value) => {
|
|
115
111
|
(0, assertions_1.assertTruthy)(predicate(value), message);
|
|
116
112
|
return value;
|
|
117
113
|
};
|
|
118
|
-
exports.
|
|
114
|
+
exports.assert = assert;
|
|
119
115
|
/** Transforms the value */
|
|
120
116
|
const map = (fn) => (value) => fn(value);
|
|
121
117
|
exports.map = map;
|
|
118
|
+
/**
|
|
119
|
+
* Creates a simple validator that returns error message or undefined.
|
|
120
|
+
* Can be used directly in transform().
|
|
121
|
+
* @example
|
|
122
|
+
* transform(validator(s => s === 'valid' ? undefined : 'Invalid ID'))
|
|
123
|
+
*/
|
|
124
|
+
function validator(validateFn) {
|
|
125
|
+
return (value) => {
|
|
126
|
+
const error = validateFn(value);
|
|
127
|
+
if (error !== undefined) {
|
|
128
|
+
(0, assertions_1.assertTruthy)(false, error);
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
122
133
|
//# sourceMappingURL=type-validators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-validators.js","sourceRoot":"","sources":["../../../src/utils/type-validators.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,4BAOC;
|
|
1
|
+
{"version":3,"file":"type-validators.js","sourceRoot":"","sources":["../../../src/utils/type-validators.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/api.types.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/** Validator function that validates and returns typed value */
|
|
2
|
-
export type
|
|
1
|
+
/** Validator function that validates and returns a typed value */
|
|
2
|
+
export type ParamValidator<T> = (value: unknown) => T;
|
|
3
3
|
/** Map of param name to type validator */
|
|
4
|
-
export type
|
|
4
|
+
export type ParamValidatorMap = Record<string, ParamValidator<unknown>>;
|
|
5
5
|
/** Infer validated types from validator map */
|
|
6
|
-
export type
|
|
6
|
+
export type ValidatedParams<T extends ParamValidatorMap | undefined> = T extends ParamValidatorMap ? {
|
|
7
7
|
[K in keyof T]: ReturnType<T[K]>;
|
|
8
|
-
} : Record<string,
|
|
8
|
+
} : Record<string, never>;
|
|
9
9
|
export declare class HttpError extends Error {
|
|
10
10
|
readonly status: number;
|
|
11
11
|
readonly details?: Record<string, unknown> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAalD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YACkB,MAAc,EAC9B,OAAe,EACC,OAAiC;QAEjD,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,WAAM,GAAN,MAAM,CAAQ;QAEd,YAAO,GAAP,OAAO,CAA0B;QAGjD,qDAAqD;QACrD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,MAAc,EAAE,OAAe;IACxE,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5D,CAAC;AA0BD,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAc,MAAS;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TypedValidatorMap } from './api.types';
|
|
2
1
|
import { DeleteEndpoint, GetEndpoint, PatchEndpoint, PostEndpoint, PutEndpoint, RequestContext, ResponseOrValue } from './router';
|
|
3
2
|
import { ExpressRouter } from './utils/express.utils';
|
|
4
3
|
/**
|
|
@@ -8,19 +7,25 @@ import { ExpressRouter } from './utils/express.utils';
|
|
|
8
7
|
export declare class RouteTable {
|
|
9
8
|
private readonly app;
|
|
10
9
|
constructor(app: ExpressRouter);
|
|
11
|
-
/** Register GET endpoint
|
|
12
|
-
get<Result
|
|
13
|
-
/** Register GET endpoint with function shorthand. */
|
|
10
|
+
/** Register a GET endpoint. */
|
|
11
|
+
get<Result>(path: string, endpoint: GetEndpoint<Result>): this;
|
|
12
|
+
/** Register a GET endpoint with function shorthand. */
|
|
14
13
|
get<Result>(path: string, run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>): this;
|
|
15
|
-
/** Register POST endpoint
|
|
16
|
-
post<
|
|
17
|
-
/** Register
|
|
18
|
-
|
|
19
|
-
/** Register
|
|
20
|
-
|
|
21
|
-
/** Register
|
|
22
|
-
|
|
23
|
-
/** Register
|
|
14
|
+
/** Register a POST endpoint. */
|
|
15
|
+
post<Result = void>(path: string, endpoint: PostEndpoint<Result>): this;
|
|
16
|
+
/** Register a POST endpoint with function shorthand. */
|
|
17
|
+
post<Result = void>(path: string, run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>): this;
|
|
18
|
+
/** Register a PATCH endpoint. */
|
|
19
|
+
patch<Result = void>(path: string, endpoint: PatchEndpoint<Result>): this;
|
|
20
|
+
/** Register a PATCH endpoint with function shorthand. */
|
|
21
|
+
patch<Result = void>(path: string, run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>): this;
|
|
22
|
+
/** Register a PUT endpoint. */
|
|
23
|
+
put<Result = void>(path: string, endpoint: PutEndpoint<Result>): this;
|
|
24
|
+
/** Register a PUT endpoint with function shorthand. */
|
|
25
|
+
put<Result = void>(path: string, run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>): this;
|
|
26
|
+
/** Register a DELETE endpoint with a full endpoint object. */
|
|
27
|
+
delete(path: string, endpoint: DeleteEndpoint): this;
|
|
28
|
+
/** Register a DELETE endpoint with function shorthand. */
|
|
24
29
|
delete(path: string, run: (ctx: RequestContext) => void | Promise<void>): this;
|
|
25
30
|
}
|
|
26
31
|
/**
|
package/dist/esm/route-table.js
CHANGED
|
@@ -12,18 +12,18 @@ export class RouteTable {
|
|
|
12
12
|
mountGet(this.app, path, endpoint);
|
|
13
13
|
return this;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
post(path, endpointOrRun) {
|
|
16
|
+
const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
|
|
17
17
|
mountPost(this.app, path, endpoint);
|
|
18
18
|
return this;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
patch(path, endpointOrRun) {
|
|
21
|
+
const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
|
|
22
22
|
mountPatch(this.app, path, endpoint);
|
|
23
23
|
return this;
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
put(path, endpointOrRun) {
|
|
26
|
+
const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
|
|
27
27
|
mountPut(this.app, path, endpoint);
|
|
28
28
|
return this;
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-table.js","sourceRoot":"","sources":["../../src/route-table.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"route-table.js","sourceRoot":"","sources":["../../src/route-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,SAAS,EACT,QAAQ,GAMT,MAAM,UAAU,CAAC;AAGlB;;;GAGG;AACH,MAAM,OAAO,UAAU;IACrB,YAA6B,GAAkB;QAAlB,QAAG,GAAH,GAAG,CAAe;IAAG,CAAC;IAQnD,GAAG,CACD,IAAY,EACZ,aAA0H;QAE1H,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAgC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,IAAI,CACF,IAAY,EACZ,aAA2H;QAE3H,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAiC,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,KAAK,CACH,IAAY,EACZ,aAA4H;QAE5H,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAkC,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,GAAG,CACD,IAAY,EACZ,aAA0H;QAE1H,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAgC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,MAAM,CACJ,IAAY,EACZ,aAA+E;QAE/E,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA0B,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|
package/dist/esm/router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Assertion
|
|
2
|
-
import { ApiResponse,
|
|
1
|
+
import { Assertion } from '@fishka/assertions';
|
|
2
|
+
import { ApiResponse, ParamValidator } from './api.types';
|
|
3
3
|
import { AuthUser } from './auth/auth.types';
|
|
4
4
|
import { ExpressRequest, ExpressResponse, ExpressRouter } from './utils/express.utils';
|
|
5
5
|
/** Express API allows handlers to return a response in the raw form. */
|
|
@@ -10,19 +10,36 @@ export type ResponseOrValue<ResponseEntity> = ApiResponse<ResponseEntity> | Resp
|
|
|
10
10
|
*/
|
|
11
11
|
export type EndpointMiddleware<Context = RequestContext> = (run: () => Promise<unknown>, context: Context) => Promise<unknown>;
|
|
12
12
|
/** Generic request context passed to all handlers. Database-agnostic and extensible. */
|
|
13
|
-
export interface RequestContext
|
|
14
|
-
/** Parsed and validated request body (for POST/PATCH/PUT handlers). */
|
|
15
|
-
body: Body;
|
|
13
|
+
export interface RequestContext {
|
|
16
14
|
/** Express Request object. */
|
|
17
15
|
req: ExpressRequest;
|
|
18
16
|
/** Express Response object. */
|
|
19
17
|
res: ExpressResponse;
|
|
20
18
|
/** Authenticated user (if any). Populated by auth middleware. */
|
|
21
19
|
authUser?: AuthUser;
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Get and validate a path parameter.
|
|
22
|
+
* @param name - Name of the path parameter
|
|
23
|
+
* @param validator - Optional validator. If not provided, returns the raw string value.
|
|
24
|
+
* @returns Validated value of type T (or string if no validator)
|
|
25
|
+
* @throws {HttpError} 400 Bad Request if validation fails
|
|
26
|
+
*/
|
|
27
|
+
path<T = string>(name: string, validator?: ParamValidator<T>): T;
|
|
28
|
+
/**
|
|
29
|
+
* Get and validate a query parameter.
|
|
30
|
+
* @param name - Name of the query parameter
|
|
31
|
+
* @param validator - Optional validator. If not provided, returns the raw string value or undefined.
|
|
32
|
+
* @returns Validated value of type T, or undefined if parameter is not present
|
|
33
|
+
* @throws {HttpError} 400 Bad Request if validation fails
|
|
34
|
+
*/
|
|
35
|
+
query<T = string>(name: string, validator?: ParamValidator<T>): T | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Get and validate the request body.
|
|
38
|
+
* @param validator - Validator function or object assertion
|
|
39
|
+
* @returns Validated body of type T
|
|
40
|
+
* @throws {HttpError} 400 Bad Request if validation fails
|
|
41
|
+
*/
|
|
42
|
+
body<T>(validator: Assertion<T>): T;
|
|
26
43
|
/**
|
|
27
44
|
* Generic state storage for middleware to attach data.
|
|
28
45
|
* Allows middleware to pass information to handlers and other middleware.
|
|
@@ -30,31 +47,24 @@ export interface RequestContext<Body = void, PathParams extends TypedValidatorMa
|
|
|
30
47
|
state: Map<string, unknown>;
|
|
31
48
|
}
|
|
32
49
|
/** Base interface with common endpoint properties. */
|
|
33
|
-
export interface EndpointBase<
|
|
34
|
-
/** Path parameter validators (typed). */
|
|
35
|
-
$path?: PathParams;
|
|
36
|
-
/** Query parameter validators (typed). */
|
|
37
|
-
$query?: QueryParams;
|
|
50
|
+
export interface EndpointBase<Result = unknown> {
|
|
38
51
|
/** Optional middleware to execute before the handler. */
|
|
39
52
|
middlewares?: Array<EndpointMiddleware>;
|
|
40
53
|
/** Handler function. Can be sync or async. */
|
|
41
|
-
run: (ctx: RequestContext
|
|
54
|
+
run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>;
|
|
42
55
|
}
|
|
43
56
|
/** Descriptor for GET list routes. */
|
|
44
|
-
export type GetListEndpoint<ResultElementType
|
|
57
|
+
export type GetListEndpoint<ResultElementType> = EndpointBase<Array<ResultElementType>>;
|
|
45
58
|
/** Descriptor for GET routes. */
|
|
46
|
-
export type GetEndpoint<Result
|
|
59
|
+
export type GetEndpoint<Result> = EndpointBase<Result>;
|
|
47
60
|
/** Descriptor for POST routes. */
|
|
48
|
-
export
|
|
49
|
-
/** Request body validator. */
|
|
50
|
-
$body: Body extends object ? ObjectAssertion<Body> : Assertion<Body>;
|
|
51
|
-
}
|
|
61
|
+
export type PostEndpoint<Result = void> = EndpointBase<Result>;
|
|
52
62
|
/** Same as POST. Used for full object updates. */
|
|
53
|
-
export type PutEndpoint<
|
|
63
|
+
export type PutEndpoint<Result = void> = EndpointBase<Result>;
|
|
54
64
|
/** Same as PUT. While PUT is used for the whole object update, PATCH is used for a partial update. */
|
|
55
|
-
export type PatchEndpoint<
|
|
65
|
+
export type PatchEndpoint<Result = void> = EndpointBase<Result>;
|
|
56
66
|
/** Descriptor for DELETE routes. */
|
|
57
|
-
export type DeleteEndpoint
|
|
67
|
+
export type DeleteEndpoint = EndpointBase<void>;
|
|
58
68
|
/** Union type for all route registration info objects. */
|
|
59
69
|
export type RouteRegistrationInfo = ({
|
|
60
70
|
method: 'get';
|
|
@@ -77,11 +87,11 @@ export type RouteRegistrationInfo = ({
|
|
|
77
87
|
/** Registers a GET route. */
|
|
78
88
|
export declare const mountGet: (app: ExpressRouter, path: string, endpoint: GetEndpoint<unknown> | GetListEndpoint<unknown>) => void;
|
|
79
89
|
/** Registers a POST route. */
|
|
80
|
-
export declare const mountPost: <
|
|
90
|
+
export declare const mountPost: <Result>(app: ExpressRouter, path: string, endpoint: PostEndpoint<Result>) => void;
|
|
81
91
|
/** Registers a PATCH route. */
|
|
82
|
-
export declare const mountPatch: <
|
|
92
|
+
export declare const mountPatch: <Result>(app: ExpressRouter, path: string, endpoint: PatchEndpoint<Result>) => void;
|
|
83
93
|
/** Registers a PUT route. */
|
|
84
|
-
export declare const mountPut: <
|
|
94
|
+
export declare const mountPut: <Result>(app: ExpressRouter, path: string, endpoint: PutEndpoint<Result>) => void;
|
|
85
95
|
/** Registers a DELETE route. */
|
|
86
96
|
export declare const mountDelete: (app: ExpressRouter, path: string, endpoint: DeleteEndpoint) => void;
|
|
87
97
|
/** Mounts a route with the given method, endpoint, and path. */
|
package/dist/esm/router.js
CHANGED
|
@@ -5,9 +5,94 @@ import { catchRouteErrors } from './error-handling';
|
|
|
5
5
|
import { HTTP_BAD_REQUEST, HTTP_OK } from './http-status-codes';
|
|
6
6
|
import { getRequestLocalStorage } from './thread-local/thread-local-storage';
|
|
7
7
|
import { wrapAsApiResponse } from './utils/conversion.utils';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/** Implementation of RequestContext with caching for validated parameters. */
|
|
9
|
+
class RequestContextImpl {
|
|
10
|
+
constructor(
|
|
11
|
+
/** Express request object. */
|
|
12
|
+
req,
|
|
13
|
+
/** Express response object. */
|
|
14
|
+
res,
|
|
15
|
+
/** Authenticated user (if any). */
|
|
16
|
+
authUser,
|
|
17
|
+
/** Request-scoped state storage. */
|
|
18
|
+
state = new Map()) {
|
|
19
|
+
this.req = req;
|
|
20
|
+
this.res = res;
|
|
21
|
+
this.authUser = authUser;
|
|
22
|
+
this.state = state;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validates a parameter with optional validator and caching.
|
|
26
|
+
* @param name Parameter name.
|
|
27
|
+
* @param rawValue Raw parameter value from request.
|
|
28
|
+
* @param validator Optional validator function.
|
|
29
|
+
* @param cache Cache map for this parameter type.
|
|
30
|
+
* @param isRequired Whether parameter is required (path=true, query=false).
|
|
31
|
+
* @returns Validated value or undefined for optional missing parameters.
|
|
32
|
+
*/
|
|
33
|
+
validateParam(name, rawValue, validator, isRequired) {
|
|
34
|
+
try {
|
|
35
|
+
let result;
|
|
36
|
+
if (validator) {
|
|
37
|
+
// Pass value to validator even if it's undefined/null/empty
|
|
38
|
+
result = validator(rawValue);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Without validator
|
|
42
|
+
if (rawValue === undefined || rawValue === null || rawValue === '') {
|
|
43
|
+
if (isRequired) {
|
|
44
|
+
assertHttp(false, HTTP_BAD_REQUEST, `Missing required parameter: ${name}`);
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
result = rawValue;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error instanceof HttpError)
|
|
54
|
+
throw error;
|
|
55
|
+
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
path(name, validator) {
|
|
59
|
+
const rawValue = this.req.params[name];
|
|
60
|
+
const result = this.validateParam(name, rawValue, validator, true);
|
|
61
|
+
assertHttp(result !== undefined, HTTP_BAD_REQUEST, `Missing required path parameter: ${name}`);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
query(name, validator) {
|
|
65
|
+
const parsedUrl = url.parse(this.req.url, true);
|
|
66
|
+
const rawValue = parsedUrl.query[name];
|
|
67
|
+
const value = Array.isArray(rawValue) ? rawValue[0] : rawValue;
|
|
68
|
+
return this.validateParam(name, value, validator, false);
|
|
69
|
+
}
|
|
70
|
+
body(validator) {
|
|
71
|
+
const apiRequest = this.req.body;
|
|
72
|
+
try {
|
|
73
|
+
// Handle validation based on whether the validator is an object or function
|
|
74
|
+
if (typeof validator === 'function') {
|
|
75
|
+
// It's a ValueAssertion (function) - call it directly
|
|
76
|
+
validator(apiRequest);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// It's an ObjectAssertion - use validateObject
|
|
80
|
+
const objectValidator = validator;
|
|
81
|
+
const isEmptyValidator = Object.keys(objectValidator).length === 0;
|
|
82
|
+
const errorMessage = validateObject(apiRequest, objectValidator, `${HTTP_BAD_REQUEST}: request body`, {
|
|
83
|
+
failOnUnknownFields: !isEmptyValidator,
|
|
84
|
+
});
|
|
85
|
+
assertHttp(!errorMessage, HTTP_BAD_REQUEST, errorMessage || 'Request body validation failed');
|
|
86
|
+
}
|
|
87
|
+
return apiRequest;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error instanceof HttpError)
|
|
91
|
+
throw error;
|
|
92
|
+
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
11
96
|
/** Registers a GET route. */
|
|
12
97
|
export const mountGet = (app, path, endpoint) => mount(app, { method: 'get', endpoint, path });
|
|
13
98
|
/** Registers a POST route. */
|
|
@@ -54,48 +139,12 @@ function createRouteHandler(method, endpoint) {
|
|
|
54
139
|
res.send(response);
|
|
55
140
|
};
|
|
56
141
|
}
|
|
57
|
-
/**
|
|
58
|
-
* @Internal
|
|
59
|
-
* Validates and builds typed path/query parameters using $path and $query validators.
|
|
60
|
-
*/
|
|
61
|
-
function buildValidatedParams(req, $path, $query) {
|
|
62
|
-
const pathResult = {};
|
|
63
|
-
const queryResult = {};
|
|
64
|
-
try {
|
|
65
|
-
// Validate path params
|
|
66
|
-
if ($path) {
|
|
67
|
-
for (const [key, validator] of Object.entries($path)) {
|
|
68
|
-
const value = req.params[key];
|
|
69
|
-
pathResult[key] = validator(value);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Validate query params
|
|
73
|
-
if ($query) {
|
|
74
|
-
const parsedUrl = url.parse(req.url, true);
|
|
75
|
-
for (const [key, validator] of Object.entries($query)) {
|
|
76
|
-
const rawValue = parsedUrl.query[key];
|
|
77
|
-
const value = Array.isArray(rawValue) ? rawValue[0] : rawValue;
|
|
78
|
-
queryResult[key] = validator(value);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
if (error instanceof HttpError)
|
|
84
|
-
throw error;
|
|
85
|
-
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
path: pathResult,
|
|
89
|
-
query: queryResult,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
142
|
/**
|
|
93
143
|
* @Internal
|
|
94
144
|
* Runs GET handler with optional middleware.
|
|
95
145
|
*/
|
|
96
146
|
async function executeGetEndpoint(route, req, res) {
|
|
97
|
-
const
|
|
98
|
-
const requestContext = newRequestContext(undefined, req, res, validated.path, validated.query);
|
|
147
|
+
const requestContext = new RequestContextImpl(req, res);
|
|
99
148
|
return await executeWithMiddleware(() => route.run(requestContext), route.middlewares || [], requestContext);
|
|
100
149
|
}
|
|
101
150
|
/**
|
|
@@ -103,8 +152,7 @@ async function executeGetEndpoint(route, req, res) {
|
|
|
103
152
|
* Runs DELETE handler with optional middleware.
|
|
104
153
|
*/
|
|
105
154
|
async function executeDeleteEndpoint(route, req, res) {
|
|
106
|
-
const
|
|
107
|
-
const requestContext = newRequestContext(undefined, req, res, validated.path, validated.query);
|
|
155
|
+
const requestContext = new RequestContextImpl(req, res);
|
|
108
156
|
await executeWithMiddleware(() => route.run(requestContext), route.middlewares || [], requestContext);
|
|
109
157
|
return undefined;
|
|
110
158
|
}
|
|
@@ -113,32 +161,8 @@ async function executeDeleteEndpoint(route, req, res) {
|
|
|
113
161
|
* Runs POST/PUT/PATCH handler with optional middleware.
|
|
114
162
|
*/
|
|
115
163
|
async function executeBodyEndpoint(route, req, res) {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
// Handle validation based on whether the validator is an object or function
|
|
120
|
-
if (typeof validator === 'function') {
|
|
121
|
-
// It's a ValueAssertion (function) - call it directly
|
|
122
|
-
validator(apiRequest);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// It's an ObjectAssertion - use validateObject
|
|
126
|
-
const objectValidator = validator;
|
|
127
|
-
const isEmptyValidator = Object.keys(objectValidator).length === 0;
|
|
128
|
-
const errorMessage = validateObject(apiRequest, objectValidator, `${HTTP_BAD_REQUEST}: request body`, {
|
|
129
|
-
failOnUnknownFields: !isEmptyValidator,
|
|
130
|
-
});
|
|
131
|
-
assertHttp(!errorMessage, HTTP_BAD_REQUEST, errorMessage || 'Request body validation failed');
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
if (error instanceof HttpError)
|
|
136
|
-
throw error;
|
|
137
|
-
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
138
|
-
}
|
|
139
|
-
const validated = buildValidatedParams(req, route.$path, route.$query);
|
|
140
|
-
const requestContext = newRequestContext(apiRequest, req, res, validated.path, validated.query);
|
|
141
|
-
return await executeWithMiddleware(() => route.run(requestContext), (route.middlewares || []), requestContext);
|
|
164
|
+
const requestContext = new RequestContextImpl(req, res);
|
|
165
|
+
return await executeWithMiddleware(() => route.run(requestContext), route.middlewares || [], requestContext);
|
|
142
166
|
}
|
|
143
167
|
/**
|
|
144
168
|
* @Internal
|
|
@@ -155,18 +179,4 @@ async function executeWithMiddleware(run, middlewares, context) {
|
|
|
155
179
|
};
|
|
156
180
|
return await current(0);
|
|
157
181
|
}
|
|
158
|
-
/**
|
|
159
|
-
* @Internal
|
|
160
|
-
* Creates a new RequestContext instance.
|
|
161
|
-
*/
|
|
162
|
-
function newRequestContext(requestBody, req, res, validatedPath, validatedQuery) {
|
|
163
|
-
return {
|
|
164
|
-
body: requestBody,
|
|
165
|
-
req,
|
|
166
|
-
res,
|
|
167
|
-
path: validatedPath,
|
|
168
|
-
query: validatedQuery,
|
|
169
|
-
state: new Map(),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
182
|
//# sourceMappingURL=router.js.map
|