Merge pull request #8383 from radoslaw-wielonski-nc/feat/add-custom-error-handler

Feat/add custom error handler
This commit is contained in:
Johan Haals
2021-12-08 16:48:22 +01:00
committed by GitHub
5 changed files with 71 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Add possibility to use custom error handler
+2
View File
@@ -521,6 +521,8 @@ export type ServiceBuilder = {
setRequestLoggingHandler(
requestLoggingHandler: RequestLoggingHandlerFactory,
): ServiceBuilder;
setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder;
disableDefaultErrorHandler(): ServiceBuilder;
start(): Promise<Server>;
};
@@ -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,27 @@ describe('ServiceBuilderImpl', () => {
expect(result!['upgrade-insecure-requests']).toBeUndefined();
});
});
describe('setCustomErrorHandler', () => {
it('check if custom error handler is undefined', () => {
const serviceBuilder = new ServiceBuilderImpl(module);
const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder);
expect(serviceBuilderProto.errorHandler).toBeUndefined();
});
it('adds custom error handler', () => {
const serviceBuilder = new ServiceBuilderImpl(module);
const serviceBuilderProto = Object.getPrototypeOf(serviceBuilder);
const customErrorHandler = (
error: Error,
_req: Request,
_res: Response,
next: NextFunction,
) => {
next(error);
};
serviceBuilderProto.setErrorHandler(customErrorHandler);
expect(serviceBuilderProto.errorHandler).toEqual(customErrorHandler);
});
});
});
@@ -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,8 @@ export class ServiceBuilderImpl implements ServiceBuilder {
private httpsSettings: HttpsSettings | undefined;
private routers: [string, Router][];
private requestLoggingHandler: RequestLoggingHandlerFactory | undefined;
private errorHandler: ErrorRequestHandler | undefined;
private useDefaultErrorHandler: boolean;
// Reference to the module where builder is created - needed for hot module
// reloading
private module: NodeModule;
@@ -73,6 +75,7 @@ export class ServiceBuilderImpl implements ServiceBuilder {
constructor(moduleRef: NodeModule) {
this.routers = [];
this.module = moduleRef;
this.useDefaultErrorHandler = true;
}
loadConfig(config: Config): ServiceBuilder {
@@ -152,6 +155,16 @@ export class ServiceBuilderImpl implements ServiceBuilder {
return this;
}
setErrorHandler(errorHandler: ErrorRequestHandler) {
this.errorHandler = errorHandler;
return this;
}
disableDefaultErrorHandler() {
this.useDefaultErrorHandler = false;
return this;
}
async start(): Promise<http.Server> {
const app = express();
const { port, host, logger, corsOptions, httpsSettings, helmetOptions } =
@@ -169,7 +182,14 @@ export class ServiceBuilderImpl implements ServiceBuilder {
app.use(root, route);
}
app.use(notFoundHandler());
app.use(errorHandler());
if (this.errorHandler) {
app.use(this.errorHandler);
}
if (this.useDefaultErrorHandler) {
app.use(defaultErrorHandler());
}
const server: http.Server = httpsSettings
? await createHttpsServer(app, httpsSettings, logger)
+16 -1
View File
@@ -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,21 @@ export type ServiceBuilder = {
requestLoggingHandler: RequestLoggingHandlerFactory,
): ServiceBuilder;
/**
* Sets an additional errorHandler to run before the defaultErrorHandler.
*
* For execution of only the custom error handler make sure to also invoke disableDefaultErrorHandler()
* otherwise the defaultErrorHandler is executed at the end of the error middleware chain.
*
* @param errorHandler - an error handler
*/
setErrorHandler(errorHandler: ErrorRequestHandler): ServiceBuilder;
/**
* Disables the default error handler
*/
disableDefaultErrorHandler(): ServiceBuilder;
/**
* Starts the server using the given settings.
*/