Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 87d6c98

Browse files
Merge pull request #414 from devspace-K/error-handling-centralization
Implement centralized error handling middleware
2 parents 23d7032 + 97d4997 commit 87d6c98

File tree

7 files changed

+105
-7
lines changed

7 files changed

+105
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
# [3.65.1] - 20-03-2024
8+
### Changed
9+
- Route handlers have been modified to utilize centralized error middleware by forwarding exceptions using a next() call when 'useExpressErrorForwarding' flag is set. With this change, custom error middleware can be used to handle exceptions in a centralized manner.
10+
711
# [3.65.0] - 19-02-2024
812
### Changed
913
- A fragment's name included in a page's URL will not cause the URL to be modified (just like js client logic).

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@puzzle-js/core",
3-
"version": "3.65.0",
3+
"version": "3.65.1",
44
"main": "./dist/index.js",
55
"types": "./dist/index.d.ts",
66
"logo": "https://image.ibb.co/jM29on/puzzlelogo.png",

src/api.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@ export class Api {
1919
this.prepareHandlers();
2020
}
2121

22-
private controllerWrapper(handler) {
23-
return async (req, res) => {
22+
private controllerWrapper(handler, useExpressErrorForwarding = false) {
23+
return async (req, res, next) => {
2424
try {
25-
await handler(req, res);
25+
await handler(req, res, next);
2626
} catch (e) {
27+
if (useExpressErrorForwarding) {
28+
next(e);
29+
return;
30+
}
31+
2732
console.error("PUZZLE_BFF_HANDLER_UNHANDLED_ERROR");
2833
console.log(e);
2934
return res.status(500).send();
@@ -49,7 +54,7 @@ export class Api {
4954
const apiHandler = this.config.versions[version];
5055

5156
apiHandler.endpoints.forEach(endpoint => {
52-
server.handler.addRoute(`/${API_ROUTE_PREFIX}/${this.config.name}/${version}${endpoint.path}`, endpoint.method, this.controllerWrapper(this.handler[version][endpoint.controller]), endpoint.middlewares);
57+
server.handler.addRoute(`/${API_ROUTE_PREFIX}/${this.config.name}/${version}${endpoint.path}`, endpoint.method, this.controllerWrapper(this.handler[version][endpoint.controller], endpoint.useExpressErrorForwarding), endpoint.middlewares);
5358
});
5459
});
5560
}

src/configurator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const apiEndpointsStructure = struct({
2424
method: struct.enum(Object.values(HTTP_METHODS)),
2525
controller: 'string',
2626
routeCache: 'number?',
27-
cacheControl: 'string?'
27+
cacheControl: 'string?',
28+
useExpressErrorForwarding: 'boolean?'
2829
});
2930

3031
const customHeaderStructure = struct({

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export interface IApiHandler {
141141
cacheControl?: string;
142142
routeCache?: number;
143143
controller: string;
144+
useExpressErrorForwarding?: boolean;
144145
}
145146

146147
export interface IApiVersion {

tests/api.spec.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Api } from "../src/api";
22
import { expect } from "chai";
33
import { HTTP_METHODS } from "../src/enums";
44
import { Server } from "../src/network";
5+
import sinon from "sinon";
56
import supertest from "supertest";
67
import faker from "faker";
78

@@ -202,5 +203,91 @@ describe('Api', () => {
202203
.end(() => {
203204
});
204205
});
206+
207+
it('should forward to next middleware when "useExpressErrorForwarding" is set', (done) => {
208+
const consoleErrorSpy = sinon.spy(console, 'error');
209+
const server = new Server();
210+
211+
const api = new Api({
212+
liveVersion: '1.0.0',
213+
name: 'browsing',
214+
testCookie: 'browsing-version',
215+
versions: {
216+
'1.0.0': {
217+
handler: {
218+
test: (req: any, res: any) => {
219+
throw new Error("error");
220+
},
221+
},
222+
endpoints: [
223+
{
224+
method: HTTP_METHODS.GET,
225+
path: '/history',
226+
controller: 'test',
227+
middlewares: [],
228+
useExpressErrorForwarding: true,
229+
},
230+
],
231+
},
232+
},
233+
});
234+
235+
api.registerEndpoints(server);
236+
237+
supertest(server.handler.getApp())
238+
.get('/api/browsing/history')
239+
.expect(500)
240+
.end((err, res) => {
241+
expect(consoleErrorSpy.called).to.be.false;
242+
243+
consoleErrorSpy.restore();
244+
done();
245+
});
246+
});
247+
248+
it('should not forward to next middleware when "useExpressErrorForwarding" is not set', (done) => {
249+
const consoleErrorSpy = sinon.spy(console, 'error');
250+
const consoleLogSpy = sinon.spy(console, 'log');
251+
const server = new Server();
252+
253+
const api = new Api({
254+
liveVersion: '1.0.0',
255+
name: 'browsing',
256+
testCookie: 'browsing-version',
257+
versions: {
258+
'1.0.0': {
259+
handler: {
260+
test: (req: any, res: any) => {
261+
throw new Error("error");
262+
},
263+
},
264+
endpoints: [
265+
{
266+
method: HTTP_METHODS.GET,
267+
path: '/history',
268+
controller: 'test',
269+
middlewares: [],
270+
useExpressErrorForwarding: false,
271+
},
272+
],
273+
},
274+
},
275+
});
276+
277+
api.registerEndpoints(server);
278+
279+
supertest(server.handler.getApp())
280+
.get('/api/browsing/history')
281+
.expect(500)
282+
.end((err, res) => {
283+
expect(consoleErrorSpy.called).to.be.true;
284+
expect(consoleErrorSpy.firstCall.args[0]).to.include("PUZZLE_BFF_HANDLER_UNHANDLED_ERROR");
285+
expect(consoleLogSpy.firstCall.args[0]).to.be.instanceOf(Error);
286+
287+
consoleErrorSpy.restore();
288+
consoleLogSpy.restore();
289+
done();
290+
});
291+
});
205292
});
206293

0 commit comments

Comments
 (0)