@fishka/express 0.9.16 → 0.9.18

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.
Files changed (46) hide show
  1. package/README.md +67 -48
  2. package/dist/cjs/api.types.d.ts +2 -14
  3. package/dist/cjs/api.types.js.map +1 -1
  4. package/dist/cjs/config.d.ts +8 -1
  5. package/dist/cjs/config.js +1 -0
  6. package/dist/cjs/config.js.map +1 -1
  7. package/dist/cjs/error-handling.d.ts +1 -1
  8. package/dist/cjs/error-handling.js +8 -10
  9. package/dist/cjs/error-handling.js.map +1 -1
  10. package/dist/cjs/route-table.d.ts +20 -21
  11. package/dist/cjs/route-table.js +11 -20
  12. package/dist/cjs/route-table.js.map +1 -1
  13. package/dist/cjs/router.d.ts +34 -36
  14. package/dist/cjs/router.js +109 -106
  15. package/dist/cjs/router.js.map +1 -1
  16. package/dist/cjs/thread-local/thread-local-storage-middleware.js +7 -1
  17. package/dist/cjs/thread-local/thread-local-storage-middleware.js.map +1 -1
  18. package/dist/cjs/utils/conversion.utils.d.ts +0 -8
  19. package/dist/cjs/utils/conversion.utils.js +0 -14
  20. package/dist/cjs/utils/conversion.utils.js.map +1 -1
  21. package/dist/cjs/utils/type-validators.d.ts +22 -15
  22. package/dist/cjs/utils/type-validators.js +25 -14
  23. package/dist/cjs/utils/type-validators.js.map +1 -1
  24. package/dist/esm/api.types.d.ts +2 -14
  25. package/dist/esm/api.types.js.map +1 -1
  26. package/dist/esm/config.d.ts +8 -1
  27. package/dist/esm/config.js +1 -0
  28. package/dist/esm/config.js.map +1 -1
  29. package/dist/esm/error-handling.d.ts +1 -1
  30. package/dist/esm/error-handling.js +8 -10
  31. package/dist/esm/error-handling.js.map +1 -1
  32. package/dist/esm/route-table.d.ts +20 -21
  33. package/dist/esm/route-table.js +12 -20
  34. package/dist/esm/route-table.js.map +1 -1
  35. package/dist/esm/router.d.ts +34 -36
  36. package/dist/esm/router.js +109 -100
  37. package/dist/esm/router.js.map +1 -1
  38. package/dist/esm/thread-local/thread-local-storage-middleware.js +7 -1
  39. package/dist/esm/thread-local/thread-local-storage-middleware.js.map +1 -1
  40. package/dist/esm/utils/conversion.utils.d.ts +0 -8
  41. package/dist/esm/utils/conversion.utils.js +0 -13
  42. package/dist/esm/utils/conversion.utils.js.map +1 -1
  43. package/dist/esm/utils/type-validators.d.ts +22 -15
  44. package/dist/esm/utils/type-validators.js +21 -11
  45. package/dist/esm/utils/type-validators.js.map +1 -1
  46. package/package.json +1 -1
package/README.md CHANGED
@@ -12,22 +12,19 @@ npm install @fishka/express
12
12
 
13
13
  ```typescript
14
14
  import express from 'express';
15
- import { createRouteTable, param, toInt } from '@fishka/express';
15
+ import { RouteTable, transform, toInt } from '@fishka/express';
16
16
  import { assertString } from '@fishka/assertions';
17
17
 
18
18
  const app = express();
19
19
  app.use(express.json());
20
20
 
21
- const routes = createRouteTable(app);
21
+ const routes = new RouteTable(app);
22
22
 
23
23
  // GET /users/:id - with typed path params
24
- routes.get('users/:id', {
25
- $path: { id: param(toInt()) },
26
- run: async ctx => ({
27
- id: ctx.path.id, // number - typed from $path
28
- name: 'John',
29
- }),
30
- });
24
+ routes.get('users/:id', async ctx => ({
25
+ id: ctx.path('id', transform(toInt())), // number - validated inline
26
+ name: 'John',
27
+ }));
31
28
 
32
29
  // GET /users - list all users
33
30
  routes.get('users', async () => [
@@ -36,10 +33,10 @@ routes.get('users', async () => [
36
33
  ]);
37
34
 
38
35
  // POST /users - with body validation
39
- routes.post<{ name: string }, { id: number }>('users', {
40
- $body: { name: v => assertString(v, 'name required') },
41
- run: async ctx => ({ id: 1 }),
42
- });
36
+ routes.post('users', async ctx => ({
37
+ id: 1,
38
+ name: ctx.body({ name: v => assertString(v, 'name required') }).name,
39
+ }));
43
40
 
44
41
  // DELETE /users/:id
45
42
  routes.delete('users/:id', async () => {});
@@ -49,38 +46,37 @@ app.listen(3000);
49
46
 
50
47
  ## URL Parameter Validation
51
48
 
52
- Use `param()` to validate and transform path/query parameters. All operators are composable:
49
+ Use `transform()` to validate and transform path/query parameters. All operators are composable:
53
50
 
54
51
  ```typescript
55
- import { param, toInt, minLength, matches, min, range, oneOf } from '@fishka/express';
56
-
57
- routes.get('users/:id', {
58
- $path: {
59
- id: param(toInt()), // string number
60
- },
61
- $query: {
62
- page: param(toInt(), min(1)), // number >= 1
63
- limit: param(toInt(), range(1, 100)), // number 1-100
64
- sort: param(oneOf('asc', 'desc')), // enum
65
- search: param(minLength(3)), // string min 3 chars
66
- },
67
- run: async ctx => ({
68
- id: ctx.path.id, // number
69
- page: ctx.query.page, // number
70
- sort: ctx.query.sort, // 'asc' | 'desc'
71
- }),
72
- });
52
+ import { transform, toInt, minLength, matches, min, range, oneOf } from '@fishka/express';
53
+
54
+ routes.get('users/:id', async ctx => ({
55
+ id: ctx.path('id', transform(toInt())), // string → number (required)
56
+ page: ctx.query('page', transform(toInt(), min(1))), // number >= 1, optional
57
+ limit: ctx.query('limit', transform(toInt(), range(1, 100))), // number 1-100, optional
58
+ sort: ctx.query('sort', transform(oneOf('asc', 'desc'))), // enum, optional
59
+ search: ctx.query('search', transform(minLength(3))), // string min 3 chars, optional
60
+ }));
73
61
  ```
74
62
 
63
+ ### Without Validators
64
+
65
+ - `ctx.path('name')` - returns string (throws 400 if missing)
66
+ - `ctx.query('name')` - returns string | undefined (returns undefined if missing/empty)
67
+ - Validators receive raw values (including undefined/null/empty) and can enforce requiredness
68
+
75
69
  ### Available Operators
76
70
 
77
71
  **Transformations (string → T):**
72
+
78
73
  - `toInt()` - parse to integer
79
74
  - `toNumber()` - parse to number
80
75
  - `toBool()` - parse 'true'/'false' to boolean
81
76
  - `oneOf('a', 'b')` - enum values
82
77
 
83
78
  **String validators:**
79
+
84
80
  - `minLength(n)` - minimum length
85
81
  - `maxLength(n)` - maximum length
86
82
  - `matches(/regex/)` - regex match
@@ -88,28 +84,30 @@ routes.get('users/:id', {
88
84
  - `lowercase` / `uppercase` - case transform
89
85
 
90
86
  **Number validators:**
87
+
91
88
  - `min(n)` - minimum value
92
89
  - `max(n)` - maximum value
93
90
  - `range(min, max)` - value range
94
91
 
95
92
  **Generic:**
96
- - `check(fn, msg)` - custom validation
93
+
94
+ - `transform(...ops)` - chain of validators/transformers
95
+ - `assert(predicate, msg)` - custom validation with predicate
96
+ - `validator(fn)` - custom validator returning string|undefined
97
97
  - `map(fn)` - transform value
98
98
 
99
99
  ### Optional Parameters
100
100
 
101
- Use `optional()` to make parameters optional:
101
+ Query parameters are optional by default. Use `ctx.query()` without a validator to get optional string values:
102
102
 
103
103
  ```typescript
104
- import { optional, param, toInt } from '@fishka/express';
104
+ import { transform, toInt } from '@fishka/express';
105
105
 
106
- routes.get('users', {
107
- $query: {
108
- page: optional(param(toInt())), // number | undefined
109
- },
110
- run: async ctx => {
111
- const page = ctx.query.page ?? 1;
112
- },
106
+ routes.get('users', async ctx => {
107
+ const page = ctx.query('page', transform(toInt())) ?? 1; // number | undefined
108
+ const search = ctx.query('search'); // string | undefined
109
+
110
+ return { page, search };
113
111
  });
114
112
  ```
115
113
 
@@ -163,7 +161,7 @@ Full initialization with TLS context, validation, and error handling:
163
161
 
164
162
  ```typescript
165
163
  import express from 'express';
166
- import { createRouteTable, createTlsMiddleware, catchAllMiddleware, param, toInt } from '@fishka/express';
164
+ import { RouteTable, createTlsMiddleware, catchAllMiddleware, transform, toInt } from '@fishka/express';
167
165
 
168
166
  const app = express();
169
167
 
@@ -171,17 +169,18 @@ const app = express();
171
169
  app.use(express.json());
172
170
 
173
171
  // 2. Initialize TLS context (Request IDs, etc.)
172
+ // Note: Request ID functionality is disabled by default.
173
+ // To enable it, call configureExpressApi({ requestIdHeader: 'x-request-id' }) first.
174
174
  app.use(createTlsMiddleware());
175
175
 
176
176
  // 3. Define routes with typed parameters
177
- const routes = createRouteTable(app);
177
+ const routes = new RouteTable(app);
178
178
 
179
179
  routes.get('health', async () => ({ status: 'UP' }));
180
180
 
181
- routes.get('users/:id', {
182
- $path: { id: param(toInt()) },
183
- run: async ctx => ({ id: ctx.path.id }),
184
- });
181
+ routes.get('users/:id', async ctx => ({
182
+ id: ctx.path('id', transform(toInt())),
183
+ }));
185
184
 
186
185
  // 4. Error handler - catches middleware/parsing errors
187
186
  app.use(catchAllMiddleware);
@@ -189,6 +188,26 @@ app.use(catchAllMiddleware);
189
188
  app.listen(3000);
190
189
  ```
191
190
 
191
+ ## Configuration
192
+
193
+ You can configure global settings using `configureExpressApi`:
194
+
195
+ ```typescript
196
+ import { configureExpressApi } from '@fishka/express';
197
+
198
+ // Request ID configuration (disabled by default)
199
+ configureExpressApi({
200
+ // Enable request ID with custom header name
201
+ requestIdHeader: 'x-request-id', // or 'x-correlation-id', 'trace-id', etc.
202
+
203
+ // Whether to trust request ID from client headers
204
+ trustRequestIdHeader: true, // default: true
205
+ });
206
+
207
+ // By default, request ID functionality is disabled.
208
+ // To enable it, you must set requestIdHeader.
209
+ ```
210
+
192
211
  ## Process Handlers
193
212
 
194
213
  Handle uncaught errors and graceful shutdown in one place:
@@ -1,11 +1,5 @@
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, string>;
1
+ /** Validator function that validates and returns a typed value */
2
+ export type ParamValidator<T> = (value: unknown) => T;
9
3
  export declare class HttpError extends Error {
10
4
  readonly status: number;
11
5
  readonly details?: Record<string, unknown> | undefined;
@@ -46,12 +40,6 @@ export declare function assertHttp(value: unknown, status: number, message: stri
46
40
  export interface ApiResponse<ResponseEntity = unknown> {
47
41
  /** Result of the call. A single entity for non-paginated ${by-id} requests or an array for list queries. */
48
42
  result: ResponseEntity;
49
- /**
50
- * Unique ID of the request.
51
- * Automatically added to every API response.
52
- * May be passed via 'x-request-id' header from client.
53
- */
54
- requestId?: string;
55
43
  /**
56
44
  * Response status code. Same as HTTP response status.
57
45
  * Default: 200 for successful responses or 500 for internal server errors.
@@ -1 +1 @@
1
- {"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":";;;AAyDA,gCAEC;AA2BD,4BAEC;AAxFD,mDAAkD;AAclD,MAAa,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;AAVD,8BAUC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,SAAgB,UAAU,CAAC,KAAc,EAAE,MAAc,EAAE,OAAe;IACxE,IAAA,yBAAY,EAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5D,CAAC;AA0BD,gFAAgF;AAChF,SAAgB,QAAQ,CAAc,MAAS;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"api.types.js","sourceRoot":"","sources":["../../src/api.types.ts"],"names":[],"mappings":";;;AAgDA,gCAEC;AAqBD,4BAEC;AAzED,mDAAkD;AAKlD,MAAa,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;AAVD,8BAUC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,SAAgB,UAAU,CAAC,KAAc,EAAE,MAAc,EAAE,OAAe;IACxE,IAAA,yBAAY,EAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5D,CAAC;AAoBD,gFAAgF;AAChF,SAAgB,QAAQ,CAAc,MAAS;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
@@ -1,8 +1,15 @@
1
1
  export interface GlobalExpressApiConfig {
2
+ /**
3
+ * Header name for request ID. If not set, request ID functionality is disabled.
4
+ * When set, enables request ID generation and propagation.
5
+ * Default: undefined (disabled)
6
+ */
7
+ requestIdHeader?: string;
2
8
  /**
3
9
  * Whether to trust and use the request ID from the request header.
4
- * If true, the middleware will look for 'x-request-id' and use it.
10
+ * If true, the middleware will look for the request ID header and use it.
5
11
  * If false, a new UUID will always be generated.
12
+ * Only applies when requestIdHeader is set.
6
13
  * Default: true
7
14
  */
8
15
  trustRequestIdHeader: boolean;
@@ -4,6 +4,7 @@ exports.configureExpressApi = configureExpressApi;
4
4
  exports.getExpressApiConfig = getExpressApiConfig;
5
5
  exports.resetExpressApiConfig = resetExpressApiConfig;
6
6
  const defaultConfig = {
7
+ requestIdHeader: undefined,
7
8
  trustRequestIdHeader: true,
8
9
  };
9
10
  let currentConfig = { ...defaultConfig };
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;AAoBA,kDAEC;AAKD,kDAEC;AAMD,sDAEC;AA3BD,MAAM,aAAa,GAA2B;IAC5C,oBAAoB,EAAE,IAAI;CAC3B,CAAC;AAEF,IAAI,aAAa,GAA2B,EAAE,GAAG,aAAa,EAAE,CAAC;AAEjE;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,MAAuC;IACzE,aAAa,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,EAA4B,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB;IACjC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB;IACnC,aAAa,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;AA6BA,kDAEC;AAKD,kDAEC;AAMD,sDAEC;AA5BD,MAAM,aAAa,GAA2B;IAC5C,eAAe,EAAE,SAAS;IAC1B,oBAAoB,EAAE,IAAI;CAC3B,CAAC;AAEF,IAAI,aAAa,GAA2B,EAAE,GAAG,aAAa,EAAE,CAAC;AAEjE;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,MAAuC;IACzE,aAAa,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,EAA4B,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB;IACjC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB;IACnC,aAAa,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC;AACvC,CAAC"}
@@ -3,7 +3,7 @@ import { ExpressFunction, ExpressRequest, ExpressResponse } from './utils/expres
3
3
  /**
4
4
  * @Internal
5
5
  * Wraps a route handler to catch and convert errors to API responses.
6
- * Applied automatically to all routes registered via createRouteTable().
6
+ * Applied automatically to all routes registered via RouteTable.
7
7
  *
8
8
  * Catches:
9
9
  * - Errors thrown in validators ($path, $query, $body)
@@ -5,22 +5,18 @@ exports.catchAllMiddleware = catchAllMiddleware;
5
5
  exports.installProcessHandlers = installProcessHandlers;
6
6
  const assertions_1 = require("@fishka/assertions");
7
7
  const api_types_1 = require("./api.types");
8
+ const config_1 = require("./config");
8
9
  const http_status_codes_1 = require("./http-status-codes");
9
10
  const thread_local_storage_1 = require("./thread-local/thread-local-storage");
10
- const conversion_utils_1 = require("./utils/conversion.utils");
11
11
  /**
12
12
  * Converts any error into a standardized API response format.
13
13
  * - HttpError: Uses the error's status code and message
14
14
  * - Other errors: Returns 500 with the error message or 'Internal error'
15
- * Attaches requestId from thread-local storage if available.
16
15
  */
17
16
  function buildApiResponse(error) {
18
- const tls = (0, thread_local_storage_1.getRequestLocalStorage)();
19
- const requestId = tls?.requestId;
20
17
  let response;
21
18
  if (error instanceof api_types_1.HttpError) {
22
19
  response = {
23
- ...(0, conversion_utils_1.wrapAsApiResponse)(undefined),
24
20
  error: error.message,
25
21
  status: error.status,
26
22
  details: error.details,
@@ -29,20 +25,16 @@ function buildApiResponse(error) {
29
25
  else {
30
26
  const errorMessage = (0, assertions_1.getMessageFromError)(error, '');
31
27
  response = {
32
- ...(0, conversion_utils_1.wrapAsApiResponse)(undefined),
33
28
  error: errorMessage && errorMessage.length > 0 ? errorMessage : 'Internal error',
34
29
  status: http_status_codes_1.HTTP_INTERNAL_SERVER_ERROR,
35
30
  };
36
31
  }
37
- if (requestId) {
38
- response.requestId = requestId;
39
- }
40
32
  return response;
41
33
  }
42
34
  /**
43
35
  * @Internal
44
36
  * Wraps a route handler to catch and convert errors to API responses.
45
- * Applied automatically to all routes registered via createRouteTable().
37
+ * Applied automatically to all routes registered via RouteTable.
46
38
  *
47
39
  * Catches:
48
40
  * - Errors thrown in validators ($path, $query, $body)
@@ -61,6 +53,12 @@ function catchRouteErrors(fn) {
61
53
  if (apiResponse.status >= http_status_codes_1.HTTP_INTERNAL_SERVER_ERROR) {
62
54
  console.error(`catchRouteErrors: ${req.path}`, error);
63
55
  }
56
+ // Добавляем requestId в заголовки, если он есть и функция включена
57
+ const tls = (0, thread_local_storage_1.getRequestLocalStorage)();
58
+ const headerName = (0, config_1.getExpressApiConfig)().requestIdHeader;
59
+ if (tls?.requestId && headerName) {
60
+ res.setHeader(headerName, tls.requestId);
61
+ }
64
62
  res.status(apiResponse.status);
65
63
  res.send(apiResponse);
66
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/error-handling.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/error-handling.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- import { TypedValidatorMap } from './api.types';
2
- import { DeleteEndpoint, GetEndpoint, PatchEndpoint, PostEndpoint, PutEndpoint, RequestContext, ResponseOrValue } from './router';
1
+ import { DeleteEndpoint, GetEndpoint, PatchEndpoint, PostEndpoint, PutEndpoint, RequestContext } from './router';
3
2
  import { ExpressRouter } from './utils/express.utils';
4
3
  /**
5
4
  * Helper utility for organizing and mounting routes.
@@ -8,24 +7,24 @@ 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 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. */
10
+ /** Register a GET endpoint. */
11
+ get<Result>(path: string, endpoint: GetEndpoint<Result>): this;
12
+ /** Register a GET endpoint with function shorthand. */
13
+ get<Result>(path: string, run: (ctx: RequestContext) => Result | Promise<Result>): this;
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) => Result | Promise<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) => Result | Promise<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) => Result | Promise<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
- /**
27
- * Factory function to create a new route table.
28
- * @param app Express application instance
29
- * @returns RouteTable instance with fluent API
30
- */
31
- export declare function createRouteTable(app: ExpressRouter): RouteTable;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RouteTable = void 0;
4
- exports.createRouteTable = createRouteTable;
5
4
  const router_1 = require("./router");
6
5
  /**
7
6
  * Helper utility for organizing and mounting routes.
@@ -13,37 +12,29 @@ class RouteTable {
13
12
  }
14
13
  get(path, endpointOrRun) {
15
14
  const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
16
- (0, router_1.mountGet)(this.app, path, endpoint);
15
+ (0, router_1.mount)(this.app, { method: 'get', endpoint: endpoint, path });
17
16
  return this;
18
17
  }
19
- /** Register POST endpoint with full type inference for path/query params. */
20
- post(path, endpoint) {
21
- (0, router_1.mountPost)(this.app, path, endpoint);
18
+ post(path, endpointOrRun) {
19
+ const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
20
+ (0, router_1.mount)(this.app, { method: 'post', endpoint: endpoint, path });
22
21
  return this;
23
22
  }
24
- /** Register PATCH endpoint with full type inference for path/query params. */
25
- patch(path, endpoint) {
26
- (0, router_1.mountPatch)(this.app, path, endpoint);
23
+ patch(path, endpointOrRun) {
24
+ const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
25
+ (0, router_1.mount)(this.app, { method: 'patch', endpoint: endpoint, path });
27
26
  return this;
28
27
  }
29
- /** Register PUT endpoint with full type inference for path/query params. */
30
- put(path, endpoint) {
31
- (0, router_1.mountPut)(this.app, path, endpoint);
28
+ put(path, endpointOrRun) {
29
+ const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
30
+ (0, router_1.mount)(this.app, { method: 'put', endpoint: endpoint, path });
32
31
  return this;
33
32
  }
34
33
  delete(path, endpointOrRun) {
35
34
  const endpoint = typeof endpointOrRun === 'function' ? { run: endpointOrRun } : endpointOrRun;
36
- (0, router_1.mountDelete)(this.app, path, endpoint);
35
+ (0, router_1.mount)(this.app, { method: 'delete', endpoint: endpoint, path });
37
36
  return this;
38
37
  }
39
38
  }
40
39
  exports.RouteTable = RouteTable;
41
- /**
42
- * Factory function to create a new route table.
43
- * @param app Express application instance
44
- * @returns RouteTable instance with fluent API
45
- */
46
- function createRouteTable(app) {
47
- return new RouteTable(app);
48
- }
49
40
  //# sourceMappingURL=route-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-table.js","sourceRoot":"","sources":["../../src/route-table.ts"],"names":[],"mappings":";;;AA6GA,4CAEC;AA9GD,qCAakB;AAGlB;;;GAGG;AACH,MAAa,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,IAAA,iBAAQ,EAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAgC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6EAA6E;IAC7E,IAAI,CAKF,IAAY,EAAE,QAA6D;QAC3E,IAAA,kBAAS,EAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA4C,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,KAAK,CAKH,IAAY,EAAE,QAA8D;QAC5E,IAAA,mBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA6C,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,GAAG,CAKD,IAAY,EAAE,QAA4D;QAC1E,IAAA,iBAAQ,EAAC,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,IAAA,oBAAW,EAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAA0B,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAjFD,gCAiFC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,GAAkB;IACjD,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"route-table.js","sourceRoot":"","sources":["../../src/route-table.ts"],"names":[],"mappings":";;;AAAA,qCAAwH;AAGxH;;;GAGG;AACH,MAAa,UAAU;IACrB,YAA6B,GAAkB;QAAlB,QAAG,GAAH,GAAG,CAAe;IAAG,CAAC;IAQnD,GAAG,CACD,IAAY,EACZ,aAAwF;QAExF,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,IAAA,cAAK,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAgC,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,IAAI,CACF,IAAY,EACZ,aAAyF;QAEzF,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,IAAA,cAAK,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAiC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,KAAK,CACH,IAAY,EACZ,aAA0F;QAE1F,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,IAAA,cAAK,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAkC,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,GAAG,CACD,IAAY,EACZ,aAAwF;QAExF,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,IAAA,cAAK,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAgC,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IAQD,MAAM,CAAC,IAAY,EAAE,aAA+E;QAClG,MAAM,QAAQ,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC9F,IAAA,cAAK,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAA0B,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA1ED,gCA0EC"}
@@ -1,28 +1,43 @@
1
- import { Assertion, ObjectAssertion } from '@fishka/assertions';
2
- import { ApiResponse, InferValidated, TypedValidatorMap } from './api.types';
1
+ import { Assertion } from '@fishka/assertions';
2
+ import { ParamValidator } from './api.types';
3
3
  import { AuthUser } from './auth/auth.types';
4
4
  import { ExpressRequest, ExpressResponse, ExpressRouter } from './utils/express.utils';
5
- /** Express API allows handlers to return a response in the raw form. */
6
- export type ResponseOrValue<ResponseEntity> = ApiResponse<ResponseEntity> | ResponseEntity;
7
5
  /**
8
6
  * Generic middleware hook for endpoint execution.
9
7
  * Allows custom logic like transaction management, authorization checks, etc.
10
8
  */
11
9
  export type EndpointMiddleware<Context = RequestContext> = (run: () => Promise<unknown>, context: Context) => Promise<unknown>;
12
10
  /** Generic request context passed to all handlers. Database-agnostic and extensible. */
13
- export interface RequestContext<Body = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> {
14
- /** Parsed and validated request body (for POST/PATCH/PUT handlers). */
15
- body: Body;
11
+ export interface RequestContext {
16
12
  /** Express Request object. */
17
13
  req: ExpressRequest;
18
14
  /** Express Response object. */
19
15
  res: ExpressResponse;
20
16
  /** Authenticated user (if any). Populated by auth middleware. */
21
17
  authUser?: AuthUser;
22
- /** Validated path parameters (typed from $path validators). */
23
- path: InferValidated<PathParams>;
24
- /** Validated query parameters (typed from $query validators). */
25
- query: InferValidated<QueryParams>;
18
+ /**
19
+ * Get and validate a path parameter.
20
+ * @param name - Name of the path parameter
21
+ * @param validator - Optional validator. If not provided, returns the raw string value.
22
+ * @returns Validated value of type T (or string if no validator)
23
+ * @throws {HttpError} 400 Bad Request if validation fails
24
+ */
25
+ path<T = string>(name: string, validator?: ParamValidator<T>): T;
26
+ /**
27
+ * Get and validate a query parameter.
28
+ * @param name - Name of the query parameter
29
+ * @param validator - Optional validator. If not provided, returns the raw string value or undefined.
30
+ * @returns Validated value of type T, or undefined if parameter is not present
31
+ * @throws {HttpError} 400 Bad Request if validation fails
32
+ */
33
+ query<T = string>(name: string, validator?: ParamValidator<T>): T | undefined;
34
+ /**
35
+ * Get and validate the request body.
36
+ * @param validator - Validator function or object assertion
37
+ * @returns Validated body of type T
38
+ * @throws {HttpError} 400 Bad Request if validation fails
39
+ */
40
+ body<T>(validator: Assertion<T>): T;
26
41
  /**
27
42
  * Generic state storage for middleware to attach data.
28
43
  * Allows middleware to pass information to handlers and other middleware.
@@ -30,31 +45,24 @@ export interface RequestContext<Body = void, PathParams extends TypedValidatorMa
30
45
  state: Map<string, unknown>;
31
46
  }
32
47
  /** Base interface with common endpoint properties. */
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;
48
+ export interface EndpointBase<Result = unknown> {
38
49
  /** Optional middleware to execute before the handler. */
39
50
  middlewares?: Array<EndpointMiddleware>;
40
51
  /** Handler function. Can be sync or async. */
41
- run: (ctx: RequestContext<Body, PathParams, QueryParams>) => ResponseOrValue<Result> | Promise<ResponseOrValue<Result>>;
52
+ run: (ctx: RequestContext) => Result | Promise<Result>;
42
53
  }
43
54
  /** Descriptor for GET list routes. */
44
- export type GetListEndpoint<ResultElementType, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, Array<ResultElementType>>;
55
+ export type GetListEndpoint<ResultElementType> = EndpointBase<Array<ResultElementType>>;
45
56
  /** Descriptor for GET routes. */
46
- export type GetEndpoint<Result, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, Result>;
57
+ export type GetEndpoint<Result> = EndpointBase<Result>;
47
58
  /** Descriptor for POST routes. */
48
- export interface PostEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> extends EndpointBase<PathParams, QueryParams, Body, Result> {
49
- /** Request body validator. */
50
- $body: Body extends object ? ObjectAssertion<Body> : Assertion<Body>;
51
- }
59
+ export type PostEndpoint<Result = void> = EndpointBase<Result>;
52
60
  /** Same as POST. Used for full object updates. */
53
- export type PutEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = PostEndpoint<Body, Result, PathParams, QueryParams>;
61
+ export type PutEndpoint<Result = void> = EndpointBase<Result>;
54
62
  /** Same as PUT. While PUT is used for the whole object update, PATCH is used for a partial update. */
55
- export type PatchEndpoint<Body, Result = void, PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = PutEndpoint<Body, Result, PathParams, QueryParams>;
63
+ export type PatchEndpoint<Result = void> = EndpointBase<Result>;
56
64
  /** Descriptor for DELETE routes. */
57
- export type DeleteEndpoint<PathParams extends TypedValidatorMap = TypedValidatorMap, QueryParams extends TypedValidatorMap = TypedValidatorMap> = EndpointBase<PathParams, QueryParams, void, void>;
65
+ export type DeleteEndpoint = EndpointBase<void>;
58
66
  /** Union type for all route registration info objects. */
59
67
  export type RouteRegistrationInfo = ({
60
68
  method: 'get';
@@ -74,15 +82,5 @@ export type RouteRegistrationInfo = ({
74
82
  }) & {
75
83
  path: string;
76
84
  };
77
- /** Registers a GET route. */
78
- export declare const mountGet: (app: ExpressRouter, path: string, endpoint: GetEndpoint<unknown> | GetListEndpoint<unknown>) => void;
79
- /** Registers a POST route. */
80
- export declare const mountPost: <Body, Result>(app: ExpressRouter, path: string, endpoint: PostEndpoint<Body, Result>) => void;
81
- /** Registers a PATCH route. */
82
- export declare const mountPatch: <Body, Result>(app: ExpressRouter, path: string, endpoint: PatchEndpoint<Body, Result>) => void;
83
- /** Registers a PUT route. */
84
- export declare const mountPut: <Body, Result>(app: ExpressRouter, path: string, endpoint: PutEndpoint<Body, Result>) => void;
85
- /** Registers a DELETE route. */
86
- export declare const mountDelete: (app: ExpressRouter, path: string, endpoint: DeleteEndpoint) => void;
87
85
  /** Mounts a route with the given method, endpoint, and path. */
88
86
  export declare function mount(app: ExpressRouter, { method, endpoint, path }: RouteRegistrationInfo): void;