@fishka/express 0.9.14 → 0.9.15
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 +87 -39
- package/dist/cjs/api.types.d.ts +8 -21
- package/dist/cjs/api.types.js +1 -21
- package/dist/cjs/api.types.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/route-table.d.ts +14 -6
- package/dist/cjs/route-table.js +3 -0
- package/dist/cjs/route-table.js.map +1 -1
- package/dist/cjs/router.d.ts +18 -26
- package/dist/cjs/router.js +33 -53
- package/dist/cjs/router.js.map +1 -1
- package/dist/cjs/utils/type-validators.d.ts +58 -0
- package/dist/cjs/utils/type-validators.js +122 -0
- package/dist/cjs/utils/type-validators.js.map +1 -0
- package/dist/esm/api.types.d.ts +8 -21
- package/dist/esm/api.types.js +0 -18
- package/dist/esm/api.types.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/route-table.d.ts +14 -6
- package/dist/esm/route-table.js +3 -0
- package/dist/esm/route-table.js.map +1 -1
- package/dist/esm/router.d.ts +18 -26
- package/dist/esm/router.js +35 -55
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/utils/type-validators.d.ts +58 -0
- package/dist/esm/utils/type-validators.js +102 -0
- package/dist/esm/utils/type-validators.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL parameter validators for Express path/query params.
|
|
3
|
+
* All params are strings from Express, so validation starts with string.
|
|
4
|
+
*/
|
|
5
|
+
import { TypeValidator } from '../api.types';
|
|
6
|
+
/** Makes validator optional - returns undefined if value missing */
|
|
7
|
+
export declare function optional<T>(validator: TypeValidator<T>): TypeValidator<T | undefined>;
|
|
8
|
+
/** Operator that transforms string to T */
|
|
9
|
+
export type ParamOperator<T> = (value: string) => T;
|
|
10
|
+
/** Operator that transforms T to R */
|
|
11
|
+
export type Operator<T, R = T> = (value: T) => R;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a URL parameter validator. Input is always string (from Express).
|
|
14
|
+
* Operators are applied in sequence to validate/transform the value.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* param() // string
|
|
18
|
+
* param(toInt) // number
|
|
19
|
+
* param(toInt, min(1)) // number >= 1
|
|
20
|
+
* param(minLength(3)) // string with min length
|
|
21
|
+
* param(trim, lowercase) // trimmed lowercase string
|
|
22
|
+
*/
|
|
23
|
+
export declare function param(): TypeValidator<string>;
|
|
24
|
+
export declare function param<A>(op1: ParamOperator<A>): TypeValidator<A>;
|
|
25
|
+
export declare function param<A, B>(op1: ParamOperator<A>, op2: Operator<A, B>): TypeValidator<B>;
|
|
26
|
+
export declare function param<A, B, C>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>): TypeValidator<C>;
|
|
27
|
+
export declare function param<A, B, C, D>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>): TypeValidator<D>;
|
|
28
|
+
export declare function param<A, B, C, D, E>(op1: ParamOperator<A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>): TypeValidator<E>;
|
|
29
|
+
/** Parses string to integer */
|
|
30
|
+
export declare const toInt: (message?: string) => ParamOperator<number>;
|
|
31
|
+
/** Parses string to number */
|
|
32
|
+
export declare const toNumber: (message?: string) => ParamOperator<number>;
|
|
33
|
+
/** Parses string to boolean ('true'/'false') */
|
|
34
|
+
export declare const toBool: (message?: string) => ParamOperator<boolean>;
|
|
35
|
+
/** Validates value is one of allowed enum values */
|
|
36
|
+
export declare const oneOf: <T extends string>(...allowedValues: T[]) => ParamOperator<T>;
|
|
37
|
+
/** Requires minimum string length */
|
|
38
|
+
export declare const minLength: (n: number, message?: string) => ParamOperator<string>;
|
|
39
|
+
/** Requires maximum string length */
|
|
40
|
+
export declare const maxLength: (n: number, message?: string) => ParamOperator<string>;
|
|
41
|
+
/** Requires string to match regex */
|
|
42
|
+
export declare const matches: (regex: RegExp, message?: string) => ParamOperator<string>;
|
|
43
|
+
/** Trims whitespace from string */
|
|
44
|
+
export declare const trim: ParamOperator<string>;
|
|
45
|
+
/** Converts string to lowercase */
|
|
46
|
+
export declare const lowercase: ParamOperator<string>;
|
|
47
|
+
/** Converts string to uppercase */
|
|
48
|
+
export declare const uppercase: ParamOperator<string>;
|
|
49
|
+
/** Requires minimum value */
|
|
50
|
+
export declare const min: (n: number, message?: string) => Operator<number>;
|
|
51
|
+
/** Requires maximum value */
|
|
52
|
+
export declare const max: (n: number, message?: string) => Operator<number>;
|
|
53
|
+
/** Requires value to be in range [minVal, maxVal] */
|
|
54
|
+
export declare const range: (minVal: number, maxVal: number, message?: string) => Operator<number>;
|
|
55
|
+
/** Adds custom validation */
|
|
56
|
+
export declare const check: <T>(predicate: (value: T) => boolean, message: string) => Operator<T>;
|
|
57
|
+
/** Transforms the value */
|
|
58
|
+
export declare const map: <T, R>(fn: (value: T) => R) => Operator<T, R>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* URL parameter validators for Express path/query params.
|
|
4
|
+
* All params are strings from Express, so validation starts with string.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.map = exports.check = 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
|
+
exports.optional = optional;
|
|
9
|
+
exports.param = param;
|
|
10
|
+
const assertions_1 = require("@fishka/assertions");
|
|
11
|
+
/** Makes validator optional - returns undefined if value missing */
|
|
12
|
+
function optional(validator) {
|
|
13
|
+
return (value) => {
|
|
14
|
+
if (value === undefined || value === null || value === '') {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
return validator(value);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function param(...operators) {
|
|
21
|
+
return (value) => {
|
|
22
|
+
(0, assertions_1.assertTruthy)(typeof value === 'string', `Expected string, got ${typeof value}`);
|
|
23
|
+
let result = value;
|
|
24
|
+
for (const op of operators) {
|
|
25
|
+
result = op(result);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// String → T operators (first in chain)
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/** Parses string to integer */
|
|
34
|
+
const toInt = (message) => (value) => {
|
|
35
|
+
const num = Number(value);
|
|
36
|
+
(0, assertions_1.assertTruthy)(Number.isInteger(num), message ?? `Expected integer, got '${value}'`);
|
|
37
|
+
return num;
|
|
38
|
+
};
|
|
39
|
+
exports.toInt = toInt;
|
|
40
|
+
/** Parses string to number */
|
|
41
|
+
const toNumber = (message) => (value) => {
|
|
42
|
+
const num = Number(value);
|
|
43
|
+
(0, assertions_1.assertTruthy)(!isNaN(num), message ?? `Expected number, got '${value}'`);
|
|
44
|
+
return num;
|
|
45
|
+
};
|
|
46
|
+
exports.toNumber = toNumber;
|
|
47
|
+
/** Parses string to boolean ('true'/'false') */
|
|
48
|
+
const toBool = (message) => (value) => {
|
|
49
|
+
(0, assertions_1.assertTruthy)(value === 'true' || value === 'false', message ?? `Expected 'true' or 'false', got '${value}'`);
|
|
50
|
+
return value === 'true';
|
|
51
|
+
};
|
|
52
|
+
exports.toBool = toBool;
|
|
53
|
+
/** Validates value is one of allowed enum values */
|
|
54
|
+
const oneOf = (...allowedValues) => (value) => {
|
|
55
|
+
(0, assertions_1.assertTruthy)(allowedValues.includes(value), `Expected one of [${allowedValues.join(', ')}], got '${value}'`);
|
|
56
|
+
return value;
|
|
57
|
+
};
|
|
58
|
+
exports.oneOf = oneOf;
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// String operators (string → string)
|
|
61
|
+
// ============================================================================
|
|
62
|
+
/** Requires minimum string length */
|
|
63
|
+
const minLength = (n, message) => (value) => {
|
|
64
|
+
(0, assertions_1.assertTruthy)(value.length >= n, message ?? `Must be at least ${n} characters`);
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
exports.minLength = minLength;
|
|
68
|
+
/** Requires maximum string length */
|
|
69
|
+
const maxLength = (n, message) => (value) => {
|
|
70
|
+
(0, assertions_1.assertTruthy)(value.length <= n, message ?? `Must be at most ${n} characters`);
|
|
71
|
+
return value;
|
|
72
|
+
};
|
|
73
|
+
exports.maxLength = maxLength;
|
|
74
|
+
/** Requires string to match regex */
|
|
75
|
+
const matches = (regex, message) => (value) => {
|
|
76
|
+
(0, assertions_1.assertTruthy)(regex.test(value), message ?? `Must match pattern ${regex}`);
|
|
77
|
+
return value;
|
|
78
|
+
};
|
|
79
|
+
exports.matches = matches;
|
|
80
|
+
/** Trims whitespace from string */
|
|
81
|
+
const trim = (value) => value.trim();
|
|
82
|
+
exports.trim = trim;
|
|
83
|
+
/** Converts string to lowercase */
|
|
84
|
+
const lowercase = (value) => value.toLowerCase();
|
|
85
|
+
exports.lowercase = lowercase;
|
|
86
|
+
/** Converts string to uppercase */
|
|
87
|
+
const uppercase = (value) => value.toUpperCase();
|
|
88
|
+
exports.uppercase = uppercase;
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Number operators (number → number)
|
|
91
|
+
// ============================================================================
|
|
92
|
+
/** Requires minimum value */
|
|
93
|
+
const min = (n, message) => (value) => {
|
|
94
|
+
(0, assertions_1.assertTruthy)(value >= n, message ?? `Must be at least ${n}`);
|
|
95
|
+
return value;
|
|
96
|
+
};
|
|
97
|
+
exports.min = min;
|
|
98
|
+
/** Requires maximum value */
|
|
99
|
+
const max = (n, message) => (value) => {
|
|
100
|
+
(0, assertions_1.assertTruthy)(value <= n, message ?? `Must be at most ${n}`);
|
|
101
|
+
return value;
|
|
102
|
+
};
|
|
103
|
+
exports.max = max;
|
|
104
|
+
/** Requires value to be in range [minVal, maxVal] */
|
|
105
|
+
const range = (minVal, maxVal, message) => (value) => {
|
|
106
|
+
(0, assertions_1.assertTruthy)(value >= minVal && value <= maxVal, message ?? `Must be between ${minVal} and ${maxVal}`);
|
|
107
|
+
return value;
|
|
108
|
+
};
|
|
109
|
+
exports.range = range;
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Generic operators
|
|
112
|
+
// ============================================================================
|
|
113
|
+
/** Adds custom validation */
|
|
114
|
+
const check = (predicate, message) => (value) => {
|
|
115
|
+
(0, assertions_1.assertTruthy)(predicate(value), message);
|
|
116
|
+
return value;
|
|
117
|
+
};
|
|
118
|
+
exports.check = check;
|
|
119
|
+
/** Transforms the value */
|
|
120
|
+
const map = (fn) => (value) => fn(value);
|
|
121
|
+
exports.map = map;
|
|
122
|
+
//# sourceMappingURL=type-validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
export type
|
|
1
|
+
/** Validator function that validates and returns typed value */
|
|
2
|
+
export type TypeValidator<T> = (value: unknown) => T;
|
|
3
|
+
/** Map of param name to type validator */
|
|
4
|
+
export type TypedValidatorMap = Record<string, TypeValidator<unknown>>;
|
|
5
|
+
/** Infer validated types from validator map */
|
|
6
|
+
export type InferValidated<T extends TypedValidatorMap | undefined> = T extends TypedValidatorMap ? {
|
|
7
|
+
[K in keyof T]: ReturnType<T[K]>;
|
|
8
|
+
} : Record<string, never>;
|
|
3
9
|
export declare class HttpError extends Error {
|
|
4
10
|
readonly status: number;
|
|
5
11
|
readonly details?: Record<string, unknown> | undefined;
|
|
@@ -62,22 +68,3 @@ export interface ApiResponse<ResponseEntity = unknown> {
|
|
|
62
68
|
}
|
|
63
69
|
/** Converts an API response value into a standardized ApiResponse structure. */
|
|
64
70
|
export declare function response<T = unknown>(result: T): ApiResponse<T>;
|
|
65
|
-
/** Globally identified URL (path or query) parameter info. */
|
|
66
|
-
export interface UrlParameterInfo {
|
|
67
|
-
/** Optional global validator for this parameter. */
|
|
68
|
-
validator?: ValueAssertion<string>;
|
|
69
|
-
/** Description for documentation. */
|
|
70
|
-
description?: string;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Default documentation and validation for URL parameters.
|
|
74
|
-
* @Internal
|
|
75
|
-
*/
|
|
76
|
-
export declare const URL_PARAMETER_INFO: Record<string, UrlParameterInfo>;
|
|
77
|
-
/** Registers a new URL parameter. */
|
|
78
|
-
export declare function registerUrlParameter(name: string, info: UrlParameterInfo): void;
|
|
79
|
-
/**
|
|
80
|
-
* Asserts that the value is a registered URL parameter name.
|
|
81
|
-
* @Internal
|
|
82
|
-
*/
|
|
83
|
-
export declare function assertUrlParameter(name: unknown): asserts name is string;
|
package/dist/esm/api.types.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { assertTruthy } from '@fishka/assertions';
|
|
2
|
-
import { HTTP_BAD_REQUEST } from './http-status-codes';
|
|
3
2
|
export class HttpError extends Error {
|
|
4
3
|
constructor(status, message, details) {
|
|
5
4
|
super(message);
|
|
@@ -47,21 +46,4 @@ export function assertHttp(value, status, message) {
|
|
|
47
46
|
export function response(result) {
|
|
48
47
|
return { result };
|
|
49
48
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Default documentation and validation for URL parameters.
|
|
52
|
-
* @Internal
|
|
53
|
-
*/
|
|
54
|
-
export const URL_PARAMETER_INFO = {};
|
|
55
|
-
/** Registers a new URL parameter. */
|
|
56
|
-
export function registerUrlParameter(name, info) {
|
|
57
|
-
URL_PARAMETER_INFO[name] = info;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Asserts that the value is a registered URL parameter name.
|
|
61
|
-
* @Internal
|
|
62
|
-
*/
|
|
63
|
-
export function assertUrlParameter(name) {
|
|
64
|
-
assertHttp(typeof name === 'string', HTTP_BAD_REQUEST, 'Url parameter name must be a string');
|
|
65
|
-
assertHttp(URL_PARAMETER_INFO[name], HTTP_BAD_REQUEST, `Invalid URL parameter: '${name}'. Please register it using 'registerUrlParameter('${name}', ...)'`);
|
|
66
|
-
}
|
|
67
49
|
//# sourceMappingURL=api.types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAclD,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"}
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -13,4 +13,5 @@ export * from './router';
|
|
|
13
13
|
export * from './thread-local/thread-local-storage';
|
|
14
14
|
export * from './thread-local/thread-local-storage-middleware';
|
|
15
15
|
export * from './utils/express.utils';
|
|
16
|
+
export * from './utils/type-validators';
|
|
16
17
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,qCAAqC,CAAC;AACpD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,qCAAqC,CAAC;AACpD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TypedValidatorMap } from './api.types';
|
|
1
2
|
import { DeleteEndpoint, GetEndpoint, PatchEndpoint, PostEndpoint, PutEndpoint, RequestContext, ResponseOrValue } from './router';
|
|
2
3
|
import { ExpressRouter } from './utils/express.utils';
|
|
3
4
|
/**
|
|
@@ -7,12 +8,19 @@ import { ExpressRouter } from './utils/express.utils';
|
|
|
7
8
|
export declare class RouteTable {
|
|
8
9
|
private readonly app;
|
|
9
10
|
constructor(app: ExpressRouter);
|
|
10
|
-
|
|
11
|
-
get<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
/** Register GET endpoint with full type inference for path/query params. */
|
|
12
|
+
get<Result, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap>(path: string, endpoint: GetEndpoint<Result, PathParams, QueryParams>): this;
|
|
13
|
+
/** Register GET endpoint with function shorthand. */
|
|
14
|
+
get<Result>(path: string, run: (ctx: RequestContext) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>): this;
|
|
15
|
+
/** Register POST endpoint with full type inference for path/query params. */
|
|
16
|
+
post<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap>(path: string, endpoint: PostEndpoint<Body, Result, PathParams, QueryParams>): this;
|
|
17
|
+
/** Register PATCH endpoint with full type inference for path/query params. */
|
|
18
|
+
patch<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap>(path: string, endpoint: PatchEndpoint<Body, Result, PathParams, QueryParams>): this;
|
|
19
|
+
/** Register PUT endpoint with full type inference for path/query params. */
|
|
20
|
+
put<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap>(path: string, endpoint: PutEndpoint<Body, Result, PathParams, QueryParams>): this;
|
|
21
|
+
/** Register DELETE endpoint with full endpoint object. */
|
|
22
|
+
delete<PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap>(path: string, endpoint: DeleteEndpoint<PathParams, QueryParams>): this;
|
|
23
|
+
/** Register DELETE endpoint with function shorthand. */
|
|
16
24
|
delete(path: string, run: (ctx: RequestContext) => void | Promise<void>): this;
|
|
17
25
|
}
|
|
18
26
|
/**
|
package/dist/esm/route-table.js
CHANGED
|
@@ -12,14 +12,17 @@ export class RouteTable {
|
|
|
12
12
|
mountGet(this.app, path, endpoint);
|
|
13
13
|
return this;
|
|
14
14
|
}
|
|
15
|
+
/** Register POST endpoint with full type inference for path/query params. */
|
|
15
16
|
post(path, endpoint) {
|
|
16
17
|
mountPost(this.app, path, endpoint);
|
|
17
18
|
return this;
|
|
18
19
|
}
|
|
20
|
+
/** Register PATCH endpoint with full type inference for path/query params. */
|
|
19
21
|
patch(path, endpoint) {
|
|
20
22
|
mountPatch(this.app, path, endpoint);
|
|
21
23
|
return this;
|
|
22
24
|
}
|
|
25
|
+
/** Register PUT endpoint with full type inference for path/query params. */
|
|
23
26
|
put(path, endpoint) {
|
|
24
27
|
mountPut(this.app, path, endpoint);
|
|
25
28
|
return this;
|
|
@@ -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":"AACA,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;IAYnD,GAAG,CAKD,IAAY,EACZ,aAEyF;QAEzF,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;IAED,6EAA6E;IAC7E,IAAI,CAKF,IAAY,EAAE,QAA6D;QAC3E,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA4C,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,KAAK,CAKH,IAAY,EAAE,QAA8D;QAC5E,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA6C,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,GAAG,CAKD,IAAY,EAAE,QAA4D;QAC1E,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA2C,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAWD,MAAM,CAIJ,IAAY,EACZ,aAAwG;QAExG,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
1
|
import { Assertion, ObjectAssertion } from '@fishka/assertions';
|
|
2
|
-
import { ApiResponse,
|
|
2
|
+
import { ApiResponse, InferValidated, TypedValidatorMap } 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,7 +10,7 @@ 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<Body = void> {
|
|
13
|
+
export interface RequestContext<Body = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> {
|
|
14
14
|
/** Parsed and validated request body (for POST/PATCH/PUT handlers). */
|
|
15
15
|
body: Body;
|
|
16
16
|
/** Express Request object. */
|
|
@@ -19,18 +19,10 @@ export interface RequestContext<Body = void> {
|
|
|
19
19
|
res: ExpressResponse;
|
|
20
20
|
/** Authenticated user (if any). Populated by auth middleware. */
|
|
21
21
|
authUser?: AuthUser;
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
params: {
|
|
27
|
-
get(key: string): string;
|
|
28
|
-
tryGet(key: string): string | undefined;
|
|
29
|
-
};
|
|
30
|
-
/** Query parameter access. */
|
|
31
|
-
query: {
|
|
32
|
-
get(key: string): string | undefined;
|
|
33
|
-
};
|
|
22
|
+
/** Validated path parameters (typed from $path validators). */
|
|
23
|
+
path: InferValidated<PathParams>;
|
|
24
|
+
/** Validated query parameters (typed from $query validators). */
|
|
25
|
+
query: InferValidated<QueryParams>;
|
|
34
26
|
/**
|
|
35
27
|
* Generic state storage for middleware to attach data.
|
|
36
28
|
* Allows middleware to pass information to handlers and other middleware.
|
|
@@ -38,31 +30,31 @@ export interface RequestContext<Body = void> {
|
|
|
38
30
|
state: Map<string, unknown>;
|
|
39
31
|
}
|
|
40
32
|
/** Base interface with common endpoint properties. */
|
|
41
|
-
export interface EndpointBase<
|
|
42
|
-
/** Path parameter
|
|
43
|
-
$path?:
|
|
44
|
-
/** Query parameter
|
|
45
|
-
$query?:
|
|
33
|
+
export interface EndpointBase<PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap, Body = void, Result = unknown> {
|
|
34
|
+
/** Path parameter validators (typed). */
|
|
35
|
+
$path?: PathParams;
|
|
36
|
+
/** Query parameter validators (typed). */
|
|
37
|
+
$query?: QueryParams;
|
|
46
38
|
/** Optional middleware to execute before the handler. */
|
|
47
39
|
middlewares?: Array<EndpointMiddleware>;
|
|
48
40
|
/** Handler function. Can be sync or async. */
|
|
49
|
-
run: (ctx:
|
|
41
|
+
run: (ctx: RequestContext<Body, PathParams, QueryParams>) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>;
|
|
50
42
|
}
|
|
51
43
|
/** Descriptor for GET list routes. */
|
|
52
|
-
export type GetListEndpoint<ResultElementType> = EndpointBase<
|
|
44
|
+
export type GetListEndpoint<ResultElementType, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, Array<ResultElementType>>;
|
|
53
45
|
/** Descriptor for GET routes. */
|
|
54
|
-
export type GetEndpoint<Result> = EndpointBase<
|
|
46
|
+
export type GetEndpoint<Result, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, Result>;
|
|
55
47
|
/** Descriptor for POST routes. */
|
|
56
|
-
export interface PostEndpoint<Body, Result = void> extends EndpointBase<
|
|
48
|
+
export interface PostEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> extends EndpointBase<PathParams, QueryParams, Body, Result> {
|
|
57
49
|
/** Request body validator. */
|
|
58
50
|
$body: Body extends object ? ObjectAssertion<Body> : Assertion<Body>;
|
|
59
51
|
}
|
|
60
52
|
/** Same as POST. Used for full object updates. */
|
|
61
|
-
export type PutEndpoint<Body, Result = void> = PostEndpoint<Body, Result>;
|
|
53
|
+
export type PutEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = PostEndpoint<Body, Result, PathParams, QueryParams>;
|
|
62
54
|
/** Same as PUT. While PUT is used for the whole object update, PATCH is used for a partial update. */
|
|
63
|
-
export type PatchEndpoint<Body, Result = void> = PutEndpoint<Body, Result>;
|
|
55
|
+
export type PatchEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = PutEndpoint<Body, Result, PathParams, QueryParams>;
|
|
64
56
|
/** Descriptor for DELETE routes. */
|
|
65
|
-
export type DeleteEndpoint = EndpointBase<
|
|
57
|
+
export type DeleteEndpoint<PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, void>;
|
|
66
58
|
/** Union type for all route registration info objects. */
|
|
67
59
|
export type RouteRegistrationInfo = ({
|
|
68
60
|
method: 'get';
|
package/dist/esm/router.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getMessageFromError, validateObject } from '@fishka/assertions';
|
|
2
2
|
import * as url from 'url';
|
|
3
|
-
import { assertHttp, HttpError
|
|
3
|
+
import { assertHttp, HttpError } from './api.types';
|
|
4
4
|
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';
|
|
@@ -56,51 +56,46 @@ function createRouteHandler(method, endpoint) {
|
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* @Internal
|
|
59
|
-
* Validates
|
|
59
|
+
* Validates and builds typed path/query parameters using $path and $query validators.
|
|
60
60
|
*/
|
|
61
|
-
function
|
|
61
|
+
function buildValidatedParams(req, $path, $query) {
|
|
62
|
+
const pathResult = {};
|
|
63
|
+
const queryResult = {};
|
|
62
64
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
callValueAssertion(value, globalValidator, `${HTTP_BAD_REQUEST}`);
|
|
69
|
-
}
|
|
70
|
-
// Run Local Validation.
|
|
71
|
-
const validator = $path?.[key];
|
|
72
|
-
if (validator) {
|
|
73
|
-
callValueAssertion(value, validator, `${HTTP_BAD_REQUEST}`);
|
|
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);
|
|
74
70
|
}
|
|
75
71
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// We only validate if it's a single value or handle array in validator.
|
|
84
|
-
// For simplicity, we pass value as is (unknown) to assertion.
|
|
85
|
-
callValueAssertion(value, globalValidator, `${HTTP_BAD_REQUEST}`);
|
|
86
|
-
}
|
|
87
|
-
const validator = $query?.[key];
|
|
88
|
-
if (validator) {
|
|
89
|
-
callValueAssertion(value, validator, `${HTTP_BAD_REQUEST}`);
|
|
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);
|
|
90
79
|
}
|
|
91
80
|
}
|
|
92
81
|
}
|
|
93
82
|
catch (error) {
|
|
83
|
+
if (error instanceof HttpError)
|
|
84
|
+
throw error;
|
|
94
85
|
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
95
86
|
}
|
|
87
|
+
return {
|
|
88
|
+
path: pathResult,
|
|
89
|
+
query: queryResult,
|
|
90
|
+
};
|
|
96
91
|
}
|
|
97
92
|
/**
|
|
98
93
|
* @Internal
|
|
99
94
|
* Runs GET handler with optional middleware.
|
|
100
95
|
*/
|
|
101
96
|
async function executeGetEndpoint(route, req, res) {
|
|
102
|
-
const
|
|
103
|
-
|
|
97
|
+
const validated = buildValidatedParams(req, route.$path, route.$query);
|
|
98
|
+
const requestContext = newRequestContext(undefined, req, res, validated.path, validated.query);
|
|
104
99
|
return await executeWithMiddleware(() => route.run(requestContext), route.middlewares || [], requestContext);
|
|
105
100
|
}
|
|
106
101
|
/**
|
|
@@ -108,8 +103,8 @@ async function executeGetEndpoint(route, req, res) {
|
|
|
108
103
|
* Runs DELETE handler with optional middleware.
|
|
109
104
|
*/
|
|
110
105
|
async function executeDeleteEndpoint(route, req, res) {
|
|
111
|
-
const
|
|
112
|
-
|
|
106
|
+
const validated = buildValidatedParams(req, route.$path, route.$query);
|
|
107
|
+
const requestContext = newRequestContext(undefined, req, res, validated.path, validated.query);
|
|
113
108
|
await executeWithMiddleware(() => route.run(requestContext), route.middlewares || [], requestContext);
|
|
114
109
|
return undefined;
|
|
115
110
|
}
|
|
@@ -123,12 +118,11 @@ async function executeBodyEndpoint(route, req, res) {
|
|
|
123
118
|
try {
|
|
124
119
|
// Handle validation based on whether the validator is an object or function
|
|
125
120
|
if (typeof validator === 'function') {
|
|
126
|
-
// It's a ValueAssertion (function)
|
|
127
|
-
|
|
121
|
+
// It's a ValueAssertion (function) - call it directly
|
|
122
|
+
validator(apiRequest);
|
|
128
123
|
}
|
|
129
124
|
else {
|
|
130
125
|
// It's an ObjectAssertion - use validateObject
|
|
131
|
-
// We strictly assume it is an object because of the type definition (function | object)
|
|
132
126
|
const objectValidator = validator;
|
|
133
127
|
const isEmptyValidator = Object.keys(objectValidator).length === 0;
|
|
134
128
|
const errorMessage = validateObject(apiRequest, objectValidator, `${HTTP_BAD_REQUEST}: request body`, {
|
|
@@ -142,9 +136,8 @@ async function executeBodyEndpoint(route, req, res) {
|
|
|
142
136
|
throw error;
|
|
143
137
|
throw new HttpError(HTTP_BAD_REQUEST, getMessageFromError(error));
|
|
144
138
|
}
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
requestContext.body = req.body;
|
|
139
|
+
const validated = buildValidatedParams(req, route.$path, route.$query);
|
|
140
|
+
const requestContext = newRequestContext(apiRequest, req, res, validated.path, validated.query);
|
|
148
141
|
return await executeWithMiddleware(() => route.run(requestContext), (route.middlewares || []), requestContext);
|
|
149
142
|
}
|
|
150
143
|
/**
|
|
@@ -166,26 +159,13 @@ async function executeWithMiddleware(run, middlewares, context) {
|
|
|
166
159
|
* @Internal
|
|
167
160
|
* Creates a new RequestContext instance.
|
|
168
161
|
*/
|
|
169
|
-
function newRequestContext(requestBody, req, res) {
|
|
162
|
+
function newRequestContext(requestBody, req, res, validatedPath, validatedQuery) {
|
|
170
163
|
return {
|
|
171
164
|
body: requestBody,
|
|
172
165
|
req,
|
|
173
166
|
res,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const value = req.params[key];
|
|
177
|
-
assertHttp(value, HTTP_BAD_REQUEST, `Path parameter '${key}' not found`);
|
|
178
|
-
return value;
|
|
179
|
-
},
|
|
180
|
-
tryGet: (key) => req.params[key],
|
|
181
|
-
},
|
|
182
|
-
query: {
|
|
183
|
-
get: (key) => {
|
|
184
|
-
const parsedUrl = url.parse(req.url, true);
|
|
185
|
-
const value = parsedUrl.query[key];
|
|
186
|
-
return Array.isArray(value) ? value[0] : value;
|
|
187
|
-
},
|
|
188
|
-
},
|
|
167
|
+
path: validatedPath,
|
|
168
|
+
query: validatedQuery,
|
|
189
169
|
state: new Map(),
|
|
190
170
|
};
|
|
191
171
|
}
|
package/dist/esm/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router.ts"],"names":[],"mappings":"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"}
|