Merge pull request #8383 from radoslaw-wielonski-nc/feat/add-custom-error-handler
Feat/add custom error handler
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Add possibility to use custom error handler
|
||||
@@ -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,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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user