diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts index bd97f444de..1d214d0bff 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.test.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { applyCspDirectives } from './ServiceBuilderImpl'; +import { NextFunction, Request, Response } from 'express'; +import { applyCspDirectives, ServiceBuilderImpl } from './ServiceBuilderImpl'; describe('ServiceBuilderImpl', () => { describe('applyCspDirectives', () => { @@ -33,4 +34,22 @@ describe('ServiceBuilderImpl', () => { expect(result!['upgrade-insecure-requests']).toBeUndefined(); }); }); + + describe('setCustomErrorHandler', () => { + it('adds custom error handler', () => { + const serviceBuilder = new ServiceBuilderImpl(module); + const customErrorHandler = ( + error: Error, + req: Request, + res: Response, + next: NextFunction, + ) => {}; + serviceBuilder.setErrorHandler(customErrorHandler); + expect(serviceBuilder.errorHandler).toEqual(customErrorHandler); + }); + it('use default error handler', () => { + const serviceBuilder = new ServiceBuilderImpl(module); + expect(serviceBuilder.errorHandler).toBeUndefined(); + }); + }); }); diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index b085cccfd6..8d6404076f 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -17,7 +17,7 @@ import { Config } from '@backstage/config'; import compression from 'compression'; import cors from 'cors'; -import express, { Router } from 'express'; +import express, { Router, ErrorRequestHandler } from 'express'; import helmet from 'helmet'; import * as http from 'http'; import stoppable from 'stoppable'; @@ -25,7 +25,7 @@ import { Logger } from 'winston'; import { useHotCleanup } from '../../hot'; import { getRootLogger } from '../../logging'; import { - errorHandler, + errorHandler as defaultErrorHandler, notFoundHandler, requestLoggingHandler as defaultRequestLoggingHandler, } from '../../middleware'; @@ -66,6 +66,7 @@ export class ServiceBuilderImpl implements ServiceBuilder { private httpsSettings: HttpsSettings | undefined; private routers: [string, Router][]; private requestLoggingHandler: RequestLoggingHandlerFactory | undefined; + private errorHandler: ErrorRequestHandler | undefined; // Reference to the module where builder is created - needed for hot module // reloading private module: NodeModule; @@ -152,6 +153,11 @@ export class ServiceBuilderImpl implements ServiceBuilder { return this; } + setErrorHandler(errorHandler: ErrorRequestHandler) { + this.errorHandler = errorHandler; + return this; + } + async start(): Promise { const app = express(); const { port, host, logger, corsOptions, httpsSettings, helmetOptions } = @@ -169,7 +175,7 @@ export class ServiceBuilderImpl implements ServiceBuilder { app.use(root, route); } app.use(notFoundHandler()); - app.use(errorHandler()); + app.use(this.errorHandler ?? defaultErrorHandler()); const server: http.Server = httpsSettings ? await createHttpsServer(app, httpsSettings, logger) diff --git a/packages/backend-common/src/service/types.ts b/packages/backend-common/src/service/types.ts index 2ad379f31e..37bfec3c43 100644 --- a/packages/backend-common/src/service/types.ts +++ b/packages/backend-common/src/service/types.ts @@ -16,7 +16,7 @@ import { Config } from '@backstage/config'; import cors from 'cors'; -import { Router, RequestHandler } from 'express'; +import { Router, RequestHandler, ErrorRequestHandler } from 'express'; import { Server } from 'http'; import { Logger } from 'winston'; @@ -98,6 +98,15 @@ export type ServiceBuilder = { requestLoggingHandler: RequestLoggingHandlerFactory, ): ServiceBuilder; + /** + * Set the error handler + * + * If no handler is given the default one is used + * + * @param errorHandler - an error handler + */ + setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder; + /** * Starts the server using the given settings. */