@naturalcycles/backend-lib 4.7.2 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -84,7 +84,7 @@ function createDefaultApp(cfg) {
84
84
  // Generic error handler
85
85
  // It handles errors, returns proper status, does sentry.captureException(),
86
86
  // assigns err.data.errorId from sentry
87
- app.use((0, genericErrorMiddleware_1.genericErrorMiddleware)({ sentryService }));
87
+ app.use((0, genericErrorMiddleware_1.genericErrorMiddleware)({ sentryService, ...cfg.genericErrorMwCfg }));
88
88
  return app;
89
89
  }
90
90
  exports.createDefaultApp = createDefaultApp;
@@ -2,6 +2,7 @@ import { Options, OptionsJson, OptionsUrlencoded } from 'body-parser';
2
2
  import { CorsOptions } from 'cors';
3
3
  import { SentrySharedService } from '../sentry/sentry.shared.service';
4
4
  import { BackendRequestHandler } from './server.model';
5
+ import { GenericErrorMiddlewareCfg } from './genericErrorMiddleware';
5
6
  /**
6
7
  * Plain RequestHandler can be provided - then it's mounted to /
7
8
  * Otherwise `path` can be provided to specify mounting point.
@@ -29,4 +30,5 @@ export interface DefaultAppCfg {
29
30
  bodyParserUrlEncodedOptions?: OptionsUrlencoded;
30
31
  bodyParserRawOptions?: Options;
31
32
  corsOptions?: CorsOptions;
33
+ genericErrorMwCfg?: GenericErrorMiddlewareCfg;
32
34
  }
@@ -1,3 +1,4 @@
1
+ import { ErrorObject, HttpErrorData } from '@naturalcycles/js-lib';
1
2
  import { SentrySharedService } from '../sentry/sentry.shared.service';
2
3
  import { BackendErrorRequestHandler, BackendRequest, BackendResponse } from './server.model';
3
4
  export interface GenericErrorMiddlewareCfg {
@@ -7,6 +8,11 @@ export interface GenericErrorMiddlewareCfg {
7
8
  * So, by default, it will report ALL errors, not only 5xx.
8
9
  */
9
10
  reportOnly5xx?: boolean;
11
+ /**
12
+ * Generic hook that can be used to **mutate** errors before they are returned to client.
13
+ * This function does not affect data sent to sentry.
14
+ */
15
+ formatError?: (err: ErrorObject<HttpErrorData>) => void;
10
16
  }
11
17
  /**
12
18
  * Generic error handler.
@@ -8,6 +8,7 @@ const includeErrorStack = APP_ENV !== 'prod' && APP_ENV !== 'test';
8
8
  // Hacky way to store the sentryService, so it's available to `respondWithError` function
9
9
  let sentryService;
10
10
  let reportOnly5xx = false;
11
+ let formatError;
11
12
  /**
12
13
  * Generic error handler.
13
14
  * Returns HTTP code based on err.data.httpStatusCode (default to 500).
@@ -16,6 +17,7 @@ let reportOnly5xx = false;
16
17
  function genericErrorMiddleware(cfg = {}) {
17
18
  sentryService || (sentryService = cfg.sentryService);
18
19
  reportOnly5xx = cfg.reportOnly5xx || false;
20
+ formatError = cfg.formatError;
19
21
  return (err, req, res, _next) => {
20
22
  // if (res.headersSent) {
21
23
  // Here we don't even log this error
@@ -56,6 +58,7 @@ function respondWithError(req, res, err) {
56
58
  httpError.data.headersSent = headersSent || undefined;
57
59
  (_b = httpError.data).report || (_b.report = undefined); // set to undefined if false
58
60
  (0, js_lib_1._filterUndefinedValues)(httpError.data, true);
61
+ formatError?.(httpError); // Mutates
59
62
  res.status(httpError.data.httpStatusCode).json({
60
63
  error: httpError,
61
64
  });
@@ -1,11 +1,11 @@
1
1
  import { GetGotOptions, Got } from '@naturalcycles/nodejs-lib';
2
- import { BackendApplication } from '../index';
2
+ import { BackendApplication, DefaultAppCfg } from '../index';
3
3
  import { BackendRequestHandlerCfg } from '../server/createDefaultApp.model';
4
4
  export interface ExpressApp extends Got {
5
5
  close(): Promise<void>;
6
6
  }
7
7
  declare class ExpressTestService {
8
- createAppFromResource(resource: BackendRequestHandlerCfg, opt?: GetGotOptions): ExpressApp;
8
+ createAppFromResource(resource: BackendRequestHandlerCfg, opt?: GetGotOptions, defaultAppCfg?: DefaultAppCfg): ExpressApp;
9
9
  createAppFromResources(resources: BackendRequestHandlerCfg[], opt?: GetGotOptions): ExpressApp;
10
10
  createApp(app: BackendApplication, opt?: GetGotOptions): ExpressApp;
11
11
  /**
@@ -9,8 +9,9 @@ const index_1 = require("../index");
9
9
  // await app.close()
10
10
  // })
11
11
  class ExpressTestService {
12
- createAppFromResource(resource, opt) {
12
+ createAppFromResource(resource, opt, defaultAppCfg) {
13
13
  return this.createApp((0, index_1.createDefaultApp)({
14
+ ...defaultAppCfg,
14
15
  resources: [resource],
15
16
  }), opt);
16
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
- "version": "4.7.2",
3
+ "version": "4.8.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install && patch-package",
6
6
  "serve": "APP_ENV=dev nodemon",
@@ -2,6 +2,7 @@ import { Options, OptionsJson, OptionsUrlencoded } from 'body-parser'
2
2
  import { CorsOptions } from 'cors'
3
3
  import { SentrySharedService } from '../sentry/sentry.shared.service'
4
4
  import { BackendRequestHandler } from './server.model'
5
+ import { GenericErrorMiddlewareCfg } from './genericErrorMiddleware'
5
6
 
6
7
  /**
7
8
  * Plain RequestHandler can be provided - then it's mounted to /
@@ -35,4 +36,6 @@ export interface DefaultAppCfg {
35
36
  bodyParserRawOptions?: Options
36
37
 
37
38
  corsOptions?: CorsOptions
39
+
40
+ genericErrorMwCfg?: GenericErrorMiddlewareCfg
38
41
  }
@@ -120,7 +120,7 @@ export function createDefaultApp(cfg: DefaultAppCfg): BackendApplication {
120
120
  // Generic error handler
121
121
  // It handles errors, returns proper status, does sentry.captureException(),
122
122
  // assigns err.data.errorId from sentry
123
- app.use(genericErrorMiddleware({ sentryService }))
123
+ app.use(genericErrorMiddleware({ sentryService, ...cfg.genericErrorMwCfg }))
124
124
 
125
125
  return app
126
126
  }
@@ -2,6 +2,7 @@ import {
2
2
  _anyToError,
3
3
  _errorToErrorObject,
4
4
  _filterUndefinedValues,
5
+ ErrorObject,
5
6
  HttpError,
6
7
  HttpErrorData,
7
8
  HttpErrorResponse,
@@ -18,6 +19,12 @@ export interface GenericErrorMiddlewareCfg {
18
19
  * So, by default, it will report ALL errors, not only 5xx.
19
20
  */
20
21
  reportOnly5xx?: boolean
22
+
23
+ /**
24
+ * Generic hook that can be used to **mutate** errors before they are returned to client.
25
+ * This function does not affect data sent to sentry.
26
+ */
27
+ formatError?: (err: ErrorObject<HttpErrorData>) => void
21
28
  }
22
29
 
23
30
  const { APP_ENV } = process.env
@@ -26,6 +33,7 @@ const includeErrorStack = APP_ENV !== 'prod' && APP_ENV !== 'test'
26
33
  // Hacky way to store the sentryService, so it's available to `respondWithError` function
27
34
  let sentryService: SentrySharedService | undefined
28
35
  let reportOnly5xx = false
36
+ let formatError: GenericErrorMiddlewareCfg['formatError']
29
37
 
30
38
  /**
31
39
  * Generic error handler.
@@ -37,6 +45,7 @@ export function genericErrorMiddleware(
37
45
  ): BackendErrorRequestHandler {
38
46
  sentryService ||= cfg.sentryService
39
47
  reportOnly5xx = cfg.reportOnly5xx || false
48
+ formatError = cfg.formatError
40
49
 
41
50
  return (err, req, res, _next) => {
42
51
  // if (res.headersSent) {
@@ -84,6 +93,8 @@ export function respondWithError(req: BackendRequest, res: BackendResponse, err:
84
93
  httpError.data.report ||= undefined // set to undefined if false
85
94
  _filterUndefinedValues(httpError.data, true)
86
95
 
96
+ formatError?.(httpError) // Mutates
97
+
87
98
  res.status(httpError.data.httpStatusCode).json({
88
99
  error: httpError,
89
100
  } as HttpErrorResponse)
@@ -1,7 +1,7 @@
1
1
  import { Server } from 'http'
2
2
  import { AddressInfo } from 'net'
3
3
  import { getGot, GetGotOptions, Got } from '@naturalcycles/nodejs-lib'
4
- import { BackendApplication, createDefaultApp } from '../index'
4
+ import { BackendApplication, createDefaultApp, DefaultAppCfg } from '../index'
5
5
  import { BackendRequestHandlerCfg } from '../server/createDefaultApp.model'
6
6
 
7
7
  export interface ExpressApp extends Got {
@@ -15,9 +15,14 @@ export interface ExpressApp extends Got {
15
15
  // })
16
16
 
17
17
  class ExpressTestService {
18
- createAppFromResource(resource: BackendRequestHandlerCfg, opt?: GetGotOptions): ExpressApp {
18
+ createAppFromResource(
19
+ resource: BackendRequestHandlerCfg,
20
+ opt?: GetGotOptions,
21
+ defaultAppCfg?: DefaultAppCfg,
22
+ ): ExpressApp {
19
23
  return this.createApp(
20
24
  createDefaultApp({
25
+ ...defaultAppCfg,
21
26
  resources: [resource],
22
27
  }),
23
28
  opt,