exframe-middleware 1.0.1 → 1.3.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.
package/README.md CHANGED
@@ -40,7 +40,7 @@ errors and reports their status and message
40
40
  client.use(handleErrors().mq);
41
41
  ```
42
42
 
43
- happyRouteResponseBuilder
43
+ standardRouteResponseBuilder
44
44
  ---
45
45
 
46
46
  builds the response object based on input and if single or multi response
@@ -50,6 +50,6 @@ example from in production
50
50
  subscribe(
51
51
  'startBoBTransfers',
52
52
  validateRequestRPC(schemas.startBoBTransfer),
53
- (context, message) => startBoBTransfer.start(context, message).then(happyRouteResponseBuilder.singleItem)
53
+ (context, message) => startBoBTransfer.start(context, message).then(standardRouteResponseBuilder.singleItem)
54
54
  )
55
55
  ```
package/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  'use strict';
2
2
 
3
-
4
3
  const handleErrors = require('./lib/handleErrors');
5
4
  const standardRouteResponseBuilder = require('./lib/standardRouteResponse');
6
5
  const buildExpressRequestContext = require('./lib/buildExpressRequestContext');
7
6
  const authorizeUser = require('./lib/authorizeUser');
8
7
  const buildCspFromHeader = require('./lib/buildCspFromHeaders');
9
8
 
10
-
11
9
  module.exports = {
12
10
  /**
13
11
  * @param {Object} config the configuration object
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
-
4
3
  const errors = require('exframe-errors');
5
4
 
6
5
  module.exports = context => {
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
-
4
3
  /**
5
4
  * @description middleware for express to build the request context, app.use(buildExpressRequestContext)
6
5
  * @param {Object} request express request
@@ -3,7 +3,21 @@
3
3
  /**
4
4
  * error
5
5
  */
6
- module.exports = (context, error, optionalIncomingMessage) => {
6
+ module.exports = (context, rawError, optionalIncomingMessage) => {
7
+ let error = rawError;
8
+
9
+ // exframe-workflow v4 creates a parent error object with an errors array that can contain multiple child errors
10
+ // originating from forked workflows. This check moves that errors array to the top level so that the workflow
11
+ // error can be processed in the same way as pre-v4 exframe-workflow errors below.
12
+ // NOTE: schema validation errors can also have an errors array, but in that case the objects in the array are
13
+ // not complete errors and represent each schema validation error from a single request. These objects will not
14
+ // have a "statusCode" property and is the reason for the check here to keep them out of the workflow error logic.
15
+ if (Array.isArray(rawError.errors) && rawError.errors.length > 0 && rawError.errors[0].statusCode !== undefined) {
16
+ if (rawError.errors.length > 1) error = rawError.errors;
17
+ else error = rawError.errors[0] || rawError;
18
+ }
19
+
20
+ const { errorCode } = error;
7
21
  let { message } = error;
8
22
  let status;
9
23
 
@@ -45,5 +59,5 @@ module.exports = (context, error, optionalIncomingMessage) => {
45
59
  }
46
60
  else context.log.warn('There was an issue with the client request', { message: optionalIncomingMessage || error.message, errorDetails: error });
47
61
 
48
- return { status, message };
62
+ return { status, message, errorCode };
49
63
  };
package/package.json CHANGED
@@ -1,31 +1,37 @@
1
1
  {
2
2
  "name": "exframe-middleware",
3
- "version": "1.0.1",
3
+ "version": "1.3.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
+ "config": {
7
+ "reporter": "mocha-exzeo-reporter"
8
+ },
6
9
  "scripts": {
7
- "test": "nyc mocha",
10
+ "test": "nyc mocha --reporter $npm_package_config_reporter",
8
11
  "pretest": "npm run lint",
9
12
  "dev-test": "nyc mocha",
10
13
  "lint": "eslint --ignore-pattern test* ."
11
14
  },
12
15
  "repository": {
13
16
  "type": "git",
14
- "url": "git+ssh://git@bitbucket.org/exzeo-usa/exframe-middleware.git"
17
+ "url": "https://bitbucket.org/exzeo-usa/exframe",
18
+ "directory": "packages/exframe-middleware"
15
19
  },
16
- "author": "",
20
+ "author": "Exzeo",
17
21
  "license": "ISC",
18
22
  "homepage": "https://bitbucket.org/exzeo-usa/exframe-middleware#readme",
19
23
  "devDependencies": {
20
- "chai": "^4.2.0",
21
- "eslint": "^5.15.3",
22
- "eslint-config-airbnb-base": "^13.1.0",
23
- "eslint-plugin-import": "^2.16.0",
24
- "mocha": "^6.0.2",
25
- "nyc": "^13.3.0",
26
- "sinon": "^7.3.0"
24
+ "chai": "*",
25
+ "eslint": "*",
26
+ "eslint-config-airbnb-base": "*",
27
+ "eslint-plugin-import": "^2.22.0",
28
+ "mocha": "*",
29
+ "mocha-exzeo-reporter": "*",
30
+ "nyc": "*",
31
+ "sinon": "*"
27
32
  },
28
33
  "dependencies": {
29
- "exframe-errors": "^1.0.0"
30
- }
34
+ "exframe-errors": "^1.2.0"
35
+ },
36
+ "gitHead": "1959247957f1a308c44d4c5210712125ab6e5573"
31
37
  }
@@ -0,0 +1,21 @@
1
+ # The language the application is written in.
2
+ ; sonar.language=js
3
+ sonar.language=JavaScript
4
+
5
+ # Path is relative to the sonar-project.properties file. Defaults to .
6
+ sonar.sources=.
7
+
8
+ # # Encoding of the source code. Default is default system encoding
9
+ sonar.sourceEncoding=UTF-8
10
+
11
+ # # Patterns used to exclude some source files from analysis.
12
+ sonar.exclusions=test*/**/*.js
13
+
14
+ # # Patterns used to include some test files and only these ones in analysis.
15
+ sonar.test.inclusions=test*/**/*.js
16
+
17
+ # Patterns used to exclude some files from coverage report.
18
+ sonar.coverage.exclusions=test*/**/*.js,node_modules/*,documentation/combined/lcov-report/*,junit/*
19
+
20
+ # Paths (absolute or relative) to the files with LCOV data.
21
+ sonar.javascript.lcov.reportPaths=documentation/combined/lcov.info
@@ -1,17 +1,16 @@
1
1
  'use strict';
2
2
 
3
-
4
3
  const errors = require('exframe-errors');
5
4
  const { expect } = require('chai');
6
5
  const sinon = require('sinon');
7
6
 
8
7
  const { fakeLogger } = require('./support/utils');
9
- const handleErorrs = require('../index').handleErrors();
8
+ const handleErrors = require('../index').handleErrors();
10
9
 
11
10
  context('handleErrors', () => {
12
11
  describe('status buckets', () => {
13
12
  it('403 beats everything else', async () => {
14
- const { status, message } = await handleErorrs.mq(
13
+ const { status, message } = await handleErrors.mq(
15
14
  [
16
15
  new errors.Unauthorized('nah brah'),
17
16
  new errors.InvalidInput(),
@@ -26,7 +25,7 @@ context('handleErrors', () => {
26
25
  });
27
26
 
28
27
  it('then 401', async () => {
29
- const { status, message } = await handleErorrs.mq(
28
+ const { status, message } = await handleErrors.mq(
30
29
  [
31
30
  new errors.InvalidInput(),
32
31
  new errors.ResourceNotFound(),
@@ -40,7 +39,7 @@ context('handleErrors', () => {
40
39
  });
41
40
 
42
41
  it('then 500', async () => {
43
- const { status, message } = await handleErorrs.mq(
42
+ const { status, message } = await handleErrors.mq(
44
43
  [
45
44
  new errors.InvalidInput(),
46
45
  new errors.ExframeBase('some message')
@@ -53,7 +52,7 @@ context('handleErrors', () => {
53
52
  });
54
53
 
55
54
  it('then groups 400 type errors', async () => {
56
- const { status, message } = await handleErorrs.mq(
55
+ const { status, message } = await handleErrors.mq(
57
56
  [
58
57
  new errors.InvalidInput(), // 400
59
58
  new errors.ResourceNotFound() // 404
@@ -66,7 +65,7 @@ context('handleErrors', () => {
66
65
  });
67
66
 
68
67
  it('but gives a specific error status when all errors are the same', async () => {
69
- const { status, message } = await handleErorrs.mq(
68
+ const { status, message } = await handleErrors.mq(
70
69
  [
71
70
  new errors.ResourceNotFound(),
72
71
  new errors.ResourceNotFound(),
@@ -82,21 +81,28 @@ context('handleErrors', () => {
82
81
 
83
82
  describe('single errors', () => {
84
83
  it('handles single errors', async () => {
85
- const { status, message } = await handleErorrs.mq(new errors.InvalidInput('some message, ya'), { log: fakeLogger });
84
+ const { status, message } = await handleErrors.mq(new errors.InvalidInput('some message, ya'), { log: fakeLogger });
86
85
  expect(status).to.equal(400);
87
86
  expect(message).to.equal('some message, ya');
88
87
  });
89
88
 
90
89
  it('defaults errors to 500 errors', async () => {
91
- const { status, message } = await handleErorrs.mq('not an error object', { log: fakeLogger });
90
+ const { status, message } = await handleErrors.mq('not an error object', { log: fakeLogger });
92
91
  expect(status).to.equal(500);
93
92
  expect(message).to.equal('Internal Server Error');
94
93
  });
95
94
 
96
95
  it('handles baseExzeoError', async () => {
97
- const { status, message } = await handleErorrs.mq(new errors.ExframeBase('this is my message'), { log: fakeLogger });
96
+ const { status, message } = await handleErrors.mq(new errors.ExframeBase('this is my message'), { log: fakeLogger });
97
+ expect(status).to.equal(500);
98
+ expect(message).to.equal('this is my message');
99
+ });
100
+
101
+ it('returns errorCode when provided', async () => {
102
+ const { status, message, errorCode } = await handleErrors.mq(new errors.ExframeBase('this is my message', 'ERROR_CODE'), { log: fakeLogger });
98
103
  expect(status).to.equal(500);
99
104
  expect(message).to.equal('this is my message');
105
+ expect(errorCode).to.equal('ERROR_CODE');
100
106
  });
101
107
  });
102
108
 
@@ -110,16 +116,17 @@ context('handleErrors', () => {
110
116
  const sendSpy = sinon.spy(expressResponseObject, 'send');
111
117
  const doneSpy = sinon.spy();
112
118
 
113
- const response = handleErorrs.express(new errors.ResourceNotFound('Resource not found'), { log: fakeLogger }, expressResponseObject, doneSpy);
119
+ const response = handleErrors.express(new errors.ResourceNotFound('Resource not found'), { log: fakeLogger }, expressResponseObject, doneSpy);
114
120
 
115
121
  expect(doneSpy.callCount).to.equal(0);
116
122
  expect(statusSpy.callCount).to.equal(1);
117
123
  expect(statusSpy.args).to.deep.equal([[404]]);
118
124
  expect(sendSpy.callCount).to.equal(1);
119
- expect(sendSpy.args).to.deep.equal([[{ status: 404, message: 'Resource not found' }]]);
125
+ expect(sendSpy.args).to.deep.equal([[{ status: 404, message: 'Resource not found', errorCode: 'NOT_FOUND' }]]);
120
126
  expect(response).to.deep.equal({
121
127
  status: 404,
122
- message: 'Resource not found'
128
+ message: 'Resource not found',
129
+ errorCode: 'NOT_FOUND'
123
130
  });
124
131
 
125
132
  sinon.reset();
@@ -134,7 +141,7 @@ context('handleErrors', () => {
134
141
  const sendSpy = sinon.spy(expressResponseObject, 'send');
135
142
  const doneSpy = sinon.spy();
136
143
 
137
- handleErorrs.express(null, { log: fakeLogger }, expressResponseObject, doneSpy);
144
+ handleErrors.express(null, { log: fakeLogger }, expressResponseObject, doneSpy);
138
145
 
139
146
  expect(doneSpy.callCount).to.equal(1);
140
147
  expect(statusSpy.callCount).to.equal(0);
@@ -143,4 +150,93 @@ context('handleErrors', () => {
143
150
  sinon.reset();
144
151
  });
145
152
  });
153
+ describe('exframe-workflow style errors', () => {
154
+ it('handles multiple errors', async () => {
155
+ const testError = new Error('A thing happened');
156
+ testError.errors = [
157
+ new errors.InvalidInput('You messed up'),
158
+ new errors.ResourceNotFound('Something is not there')
159
+ ];
160
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
161
+ expect(status).to.equal(400);
162
+ expect(message).to.equal('multiple errors occured: [You messed up, Something is not there]');
163
+ });
164
+ it('handles a single error', async () => {
165
+ const testError = new Error('A thing happened');
166
+ testError.errors = [
167
+ new errors.InvalidInput('You messed up')
168
+ ];
169
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
170
+ expect(status).to.equal(400);
171
+ expect(message).to.equal('You messed up');
172
+ });
173
+ it('handles an empty errors array', async () => {
174
+ const testError = new Error('A thing happened');
175
+ testError.errors = [];
176
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
177
+ expect(status).to.equal(500);
178
+ expect(message).to.equal('A thing happened');
179
+ });
180
+ it('handles an errors field that is not an array', async () => {
181
+ const testError = new Error('A thing happened');
182
+ testError.errors = 123;
183
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
184
+ expect(status).to.equal(500);
185
+ expect(message).to.equal('A thing happened');
186
+ });
187
+ });
188
+
189
+ describe('schema validation errors', () => {
190
+ it('handles a single validation error', async () => {
191
+ const testError = new errors.InvalidInput('You messed up');
192
+ testError.errors = [
193
+ {
194
+ keyword: 'required',
195
+ dataPath: '',
196
+ schemaPath: '#/required',
197
+ params: {
198
+ missingProperty: 'banana'
199
+ },
200
+ message: 'should have required property \'banana\''
201
+ }
202
+ ];
203
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
204
+ expect(status).to.equal(400);
205
+ expect(message).to.equal('You messed up');
206
+ });
207
+
208
+ it('handles multiple validation error', async () => {
209
+ const testError = new errors.InvalidInput('You messed up');
210
+ testError.errors = [
211
+ {
212
+ keyword: 'required',
213
+ dataPath: '',
214
+ schemaPath: '#/required',
215
+ params: {
216
+ missingProperty: 'banana'
217
+ },
218
+ message: 'should have required property \'banana\''
219
+ }, {
220
+ keyword: 'required',
221
+ dataPath: '',
222
+ schemaPath: '#/required',
223
+ params: {
224
+ missingProperty: 'pineapple'
225
+ },
226
+ message: 'should have required property \'pineapple\''
227
+ }, {
228
+ keyword: 'required',
229
+ dataPath: '',
230
+ schemaPath: '#/required',
231
+ params: {
232
+ missingProperty: 'kiwi'
233
+ },
234
+ message: 'should have required property \'kiwi\''
235
+ }
236
+ ];
237
+ const { status, message } = await handleErrors.mq(testError, { log: fakeLogger });
238
+ expect(status).to.equal(400);
239
+ expect(message).to.equal('You messed up');
240
+ });
241
+ });
146
242
  });