piper-utils 1.1.30 → 1.1.33
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/bin/main.js +1009 -300
- package/bin/main.js.map +1 -1
- package/package.json +1 -1
- package/src/requestResponse/requestResponse.js +292 -286
- package/src/requestResponse/requestResponse.test.js +386 -416
|
@@ -1,287 +1,293 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
|
-
import { errorList } from './errorCodes.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {Object} body
|
|
6
|
-
* @param {{dbClose?:function}} [options]
|
|
7
|
-
*/
|
|
8
|
-
export function success(body, options) {
|
|
9
|
-
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
10
|
-
dbClose();
|
|
11
|
-
|
|
12
|
-
return buildResponse(200, body);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {string} html
|
|
17
|
-
* @param {{dbClose:function|undefined}} options
|
|
18
|
-
*/
|
|
19
|
-
export function successHtml(html, options) {
|
|
20
|
-
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
21
|
-
|
|
22
|
-
dbClose();
|
|
23
|
-
return {
|
|
24
|
-
statusCode: 200,
|
|
25
|
-
headers: {
|
|
26
|
-
'Content-Type': 'text/html',
|
|
27
|
-
'Access-Control-Allow-Origin': '*',
|
|
28
|
-
'Access-Control-Allow-Credentials': true
|
|
29
|
-
},
|
|
30
|
-
body: html
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @param {string} event
|
|
36
|
-
* @returns string
|
|
37
|
-
*/
|
|
38
|
-
export function getCurrentUserNameFromCognitoEvent(event) {
|
|
39
|
-
const attributes = _.get(event, 'request.userAttributes');
|
|
40
|
-
|
|
41
|
-
return attributes['cognito:email_alias'] || attributes['email'] || 'UNKNOWN USER';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get the user information from the event object
|
|
46
|
-
*
|
|
47
|
-
* @param event {Object} an event object
|
|
48
|
-
* @returns {{username: string, id: number}}
|
|
49
|
-
*/
|
|
50
|
-
export function getCurrentUser(event) {
|
|
51
|
-
let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:UID') ||
|
|
52
|
-
_.get(event, 'requestContext.authorizer.custom:UID') ||
|
|
53
|
-
'0';
|
|
54
|
-
|
|
55
|
-
const id = JSON.parse(jsonToParse);
|
|
56
|
-
|
|
57
|
-
const username = _.get(event, 'requestContext.authorizer.claims.email') || _.get(event, 'requestContext.authorizer.email') || 'localtestuser@gexample.com';
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
username,
|
|
61
|
-
id
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Create a failure response
|
|
67
|
-
*
|
|
68
|
-
* @param body {Object} an event object
|
|
69
|
-
* @param options {Object} an options object
|
|
70
|
-
* @returns {{statusCode:number, headers:object, body:string}} a response object
|
|
71
|
-
*/
|
|
72
|
-
export function failure(body = {}, options) {
|
|
73
|
-
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
74
|
-
dbClose();
|
|
75
|
-
let cleanedErrorBody;
|
|
76
|
-
|
|
77
|
-
if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {
|
|
78
|
-
if (_.isObject(body)) {
|
|
79
|
-
console.error('------->ALL UTIL ERROR:', JSON.stringify(body, null, 2));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const NORMAL_ERROR = { statusCode: 500, errorCode: '5XX', message: 'INTERNAL UTIL ERROR' };
|
|
84
|
-
cleanedErrorBody = body;
|
|
85
|
-
if (!_.isUndefined(body.details)) {
|
|
86
|
-
cleanedErrorBody = detectJoyError(body);
|
|
87
|
-
} else if (_.isUndefined(body.errorCode) || _.isUndefined(body.statusCode)) {
|
|
88
|
-
cleanedErrorBody = detectSequelizeError(body);
|
|
89
|
-
}
|
|
90
|
-
if (_.get(body, 'response.data.message')) {
|
|
91
|
-
const err = _.get(body, 'response.data.message');
|
|
92
|
-
if (_.isObject(body)) {
|
|
93
|
-
console.error('------->MSG UTIL ERROR:', JSON.stringify(err, null, 2));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const newBody = _.merge(NORMAL_ERROR, cleanedErrorBody);
|
|
97
|
-
|
|
98
|
-
return buildResponse(newBody.statusCode, newBody);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Create a failure response object
|
|
103
|
-
*
|
|
104
|
-
* @param statusCode {Number} a status code
|
|
105
|
-
* @param body {Object} an event object
|
|
106
|
-
* @returns {{statusCode:number, headers:object, body:string}} a response object
|
|
107
|
-
*/
|
|
108
|
-
function buildResponse(statusCode, body) {
|
|
109
|
-
return {
|
|
110
|
-
statusCode: statusCode,
|
|
111
|
-
headers: {
|
|
112
|
-
'Access-Control-Allow-Origin': '*',
|
|
113
|
-
'Access-Control-Allow-Credentials': true
|
|
114
|
-
},
|
|
115
|
-
body: JSON.stringify(body)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* parse the body of the event object
|
|
121
|
-
*
|
|
122
|
-
* @param requestEvent {{body:string}} an event object
|
|
123
|
-
* @returns event {*} the json object of the body
|
|
124
|
-
*/
|
|
125
|
-
export function parseBody(requestEvent) {
|
|
126
|
-
|
|
127
|
-
let eventBody = {};
|
|
128
|
-
if (_.isString(requestEvent.body)) {
|
|
129
|
-
try {
|
|
130
|
-
eventBody = JSON.parse(requestEvent.body);
|
|
131
|
-
} catch (e) {
|
|
132
|
-
// Invalid JSON
|
|
133
|
-
eventBody = null;
|
|
134
|
-
|
|
135
|
-
throw errorList.invalidJson;
|
|
136
|
-
}
|
|
137
|
-
} else if (_.isObject(requestEvent.body)) {
|
|
138
|
-
eventBody = requestEvent.body;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return eventBody;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* parse the body of the event object
|
|
146
|
-
*
|
|
147
|
-
* @param requestEvent {string|object} an event object
|
|
148
|
-
* @param [callback] {function} undefined a call back function
|
|
149
|
-
* @returns event {*} the json object of the body
|
|
150
|
-
*/
|
|
151
|
-
export function parseEvent(requestEvent, callback) {
|
|
152
|
-
let event = {};
|
|
153
|
-
if (_.isString(requestEvent)) {
|
|
154
|
-
try {
|
|
155
|
-
event = JSON.parse(requestEvent);
|
|
156
|
-
} catch (e) {
|
|
157
|
-
// Invalid JSON
|
|
158
|
-
event = null;
|
|
159
|
-
|
|
160
|
-
if (callback) {
|
|
161
|
-
callback(Error(e));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
} else if (_.isObject(requestEvent)) {
|
|
165
|
-
event = requestEvent;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return event;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* parse the body of the event object
|
|
173
|
-
* look for sequelize errors and return a message
|
|
174
|
-
* ERRORS should not be caught here this is a fallback for unknown database errors
|
|
175
|
-
*
|
|
176
|
-
* @param body {object} part of a body response
|
|
177
|
-
* @returns error message object {message:string}
|
|
178
|
-
*/
|
|
179
|
-
export function detectSequelizeError(body) {
|
|
180
|
-
const errorBody = {};
|
|
181
|
-
const errorName = _.get(body, 'name', '');
|
|
182
|
-
|
|
183
|
-
if (errorName === 'SequelizeForeignKeyConstraintError') {
|
|
184
|
-
errorBody.message = 'You cannot delete this item as it is in use';
|
|
185
|
-
errorBody.statusCode = 409;
|
|
186
|
-
errorBody.errorCode = '4090';
|
|
187
|
-
return errorBody;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (errorName === 'SequelizeUniqueConstraintError') {
|
|
191
|
-
const fields = _.get(body, 'errors', []).map(err => _.get(err, 'path')).filter(Boolean);
|
|
192
|
-
errorBody.message = fields.length
|
|
193
|
-
? 'A record with this ' + fields.join(', ') + ' already exists'
|
|
194
|
-
: 'A record with this value already exists';
|
|
195
|
-
errorBody.statusCode = 409;
|
|
196
|
-
errorBody.errorCode = '4091';
|
|
197
|
-
return errorBody;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (errorName === 'SequelizeValidationError') {
|
|
201
|
-
const messages = _.get(body, 'errors', []).map(err => _.get(err, 'message')).filter(Boolean);
|
|
202
|
-
errorBody.message = messages.length ? messages.join(', ') : 'Validation error';
|
|
203
|
-
errorBody.statusCode = 400;
|
|
204
|
-
errorBody.errorCode = '4001';
|
|
205
|
-
return errorBody;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
let sequelizeError = _.get(body, 'errors', []).reduce((acc, err) => {
|
|
209
|
-
acc = acc + ' ' + _.get(err, 'message');
|
|
210
|
-
return acc;
|
|
211
|
-
}, '');
|
|
212
|
-
const parentError = _.get(body, 'parent', '');
|
|
213
|
-
|
|
214
|
-
sequelizeError = sequelizeError + _.get(body, 'original.detail', '') + _.get(body, 'TypeError', '') + parentError;
|
|
215
|
-
errorBody.message = sequelizeError.trim();
|
|
216
|
-
return errorBody;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export function detectJoyError(body) {
|
|
220
|
-
const errorBody = {};
|
|
221
|
-
const details = _.get(body, 'details') || [];
|
|
222
|
-
|
|
223
|
-
console.error('USER VALIDATION ERROR:', body);
|
|
224
|
-
const messages = extractJoyMessages(details);
|
|
225
|
-
const msg = messages.join(', ');
|
|
226
|
-
|
|
227
|
-
if (msg) {
|
|
228
|
-
errorBody.message = msg;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
errorBody.statusCode = 400;
|
|
232
|
-
errorBody.errorCode = '4000';
|
|
233
|
-
return errorBody;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function extractJoyMessages(details) {
|
|
237
|
-
const messages = [];
|
|
238
|
-
for (const detail of details) {
|
|
239
|
-
const contextDetails = _.get(detail, 'context.details') || [];
|
|
240
|
-
const directDetails = detail.details || [];
|
|
241
|
-
const nestedDetails = contextDetails.length > 0 ? contextDetails : directDetails;
|
|
242
|
-
|
|
243
|
-
if (nestedDetails.length > 0) {
|
|
244
|
-
messages.push(...extractJoyMessages(nestedDetails));
|
|
245
|
-
} else if (detail.message) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { errorList } from './errorCodes.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {Object} body
|
|
6
|
+
* @param {{dbClose?:function}} [options]
|
|
7
|
+
*/
|
|
8
|
+
export function success(body, options) {
|
|
9
|
+
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
10
|
+
dbClose();
|
|
11
|
+
|
|
12
|
+
return buildResponse(200, body);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} html
|
|
17
|
+
* @param {{dbClose:function|undefined}} options
|
|
18
|
+
*/
|
|
19
|
+
export function successHtml(html, options) {
|
|
20
|
+
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
21
|
+
|
|
22
|
+
dbClose();
|
|
23
|
+
return {
|
|
24
|
+
statusCode: 200,
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type': 'text/html',
|
|
27
|
+
'Access-Control-Allow-Origin': '*',
|
|
28
|
+
'Access-Control-Allow-Credentials': true
|
|
29
|
+
},
|
|
30
|
+
body: html
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} event
|
|
36
|
+
* @returns string
|
|
37
|
+
*/
|
|
38
|
+
export function getCurrentUserNameFromCognitoEvent(event) {
|
|
39
|
+
const attributes = _.get(event, 'request.userAttributes');
|
|
40
|
+
|
|
41
|
+
return attributes['cognito:email_alias'] || attributes['email'] || 'UNKNOWN USER';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the user information from the event object
|
|
46
|
+
*
|
|
47
|
+
* @param event {Object} an event object
|
|
48
|
+
* @returns {{username: string, id: number}}
|
|
49
|
+
*/
|
|
50
|
+
export function getCurrentUser(event) {
|
|
51
|
+
let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:UID') ||
|
|
52
|
+
_.get(event, 'requestContext.authorizer.custom:UID') ||
|
|
53
|
+
'0';
|
|
54
|
+
|
|
55
|
+
const id = JSON.parse(jsonToParse);
|
|
56
|
+
|
|
57
|
+
const username = _.get(event, 'requestContext.authorizer.claims.email') || _.get(event, 'requestContext.authorizer.email') || 'localtestuser@gexample.com';
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
username,
|
|
61
|
+
id
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create a failure response
|
|
67
|
+
*
|
|
68
|
+
* @param body {Object} an event object
|
|
69
|
+
* @param options {Object} an options object
|
|
70
|
+
* @returns {{statusCode:number, headers:object, body:string}} a response object
|
|
71
|
+
*/
|
|
72
|
+
export function failure(body = {}, options) {
|
|
73
|
+
const dbClose = _.get(options, 'dbClose', _.noop);
|
|
74
|
+
dbClose();
|
|
75
|
+
let cleanedErrorBody;
|
|
76
|
+
|
|
77
|
+
if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {
|
|
78
|
+
if (_.isObject(body)) {
|
|
79
|
+
console.error('------->ALL UTIL ERROR:', JSON.stringify(body, null, 2));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const NORMAL_ERROR = { statusCode: 500, errorCode: '5XX', message: 'INTERNAL UTIL ERROR' };
|
|
84
|
+
cleanedErrorBody = body;
|
|
85
|
+
if (!_.isUndefined(body.details)) {
|
|
86
|
+
cleanedErrorBody = detectJoyError(body);
|
|
87
|
+
} else if (_.isUndefined(body.errorCode) || _.isUndefined(body.statusCode)) {
|
|
88
|
+
cleanedErrorBody = detectSequelizeError(body);
|
|
89
|
+
}
|
|
90
|
+
if (_.get(body, 'response.data.message')) {
|
|
91
|
+
const err = _.get(body, 'response.data.message');
|
|
92
|
+
if (_.isObject(body)) {
|
|
93
|
+
console.error('------->MSG UTIL ERROR:', JSON.stringify(err, null, 2));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const newBody = _.merge(NORMAL_ERROR, cleanedErrorBody);
|
|
97
|
+
|
|
98
|
+
return buildResponse(newBody.statusCode, newBody);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Create a failure response object
|
|
103
|
+
*
|
|
104
|
+
* @param statusCode {Number} a status code
|
|
105
|
+
* @param body {Object} an event object
|
|
106
|
+
* @returns {{statusCode:number, headers:object, body:string}} a response object
|
|
107
|
+
*/
|
|
108
|
+
function buildResponse(statusCode, body) {
|
|
109
|
+
return {
|
|
110
|
+
statusCode: statusCode,
|
|
111
|
+
headers: {
|
|
112
|
+
'Access-Control-Allow-Origin': '*',
|
|
113
|
+
'Access-Control-Allow-Credentials': true
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify(body)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* parse the body of the event object
|
|
121
|
+
*
|
|
122
|
+
* @param requestEvent {{body:string}} an event object
|
|
123
|
+
* @returns event {*} the json object of the body
|
|
124
|
+
*/
|
|
125
|
+
export function parseBody(requestEvent) {
|
|
126
|
+
|
|
127
|
+
let eventBody = {};
|
|
128
|
+
if (_.isString(requestEvent.body)) {
|
|
129
|
+
try {
|
|
130
|
+
eventBody = JSON.parse(requestEvent.body);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
// Invalid JSON
|
|
133
|
+
eventBody = null;
|
|
134
|
+
|
|
135
|
+
throw errorList.invalidJson;
|
|
136
|
+
}
|
|
137
|
+
} else if (_.isObject(requestEvent.body)) {
|
|
138
|
+
eventBody = requestEvent.body;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return eventBody;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* parse the body of the event object
|
|
146
|
+
*
|
|
147
|
+
* @param requestEvent {string|object} an event object
|
|
148
|
+
* @param [callback] {function} undefined a call back function
|
|
149
|
+
* @returns event {*} the json object of the body
|
|
150
|
+
*/
|
|
151
|
+
export function parseEvent(requestEvent, callback) {
|
|
152
|
+
let event = {};
|
|
153
|
+
if (_.isString(requestEvent)) {
|
|
154
|
+
try {
|
|
155
|
+
event = JSON.parse(requestEvent);
|
|
156
|
+
} catch (e) {
|
|
157
|
+
// Invalid JSON
|
|
158
|
+
event = null;
|
|
159
|
+
|
|
160
|
+
if (callback) {
|
|
161
|
+
callback(Error(e));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} else if (_.isObject(requestEvent)) {
|
|
165
|
+
event = requestEvent;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return event;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* parse the body of the event object
|
|
173
|
+
* look for sequelize errors and return a message
|
|
174
|
+
* ERRORS should not be caught here this is a fallback for unknown database errors
|
|
175
|
+
*
|
|
176
|
+
* @param body {object} part of a body response
|
|
177
|
+
* @returns error message object {message:string}
|
|
178
|
+
*/
|
|
179
|
+
export function detectSequelizeError(body) {
|
|
180
|
+
const errorBody = {};
|
|
181
|
+
const errorName = _.get(body, 'name', '');
|
|
182
|
+
|
|
183
|
+
if (errorName === 'SequelizeForeignKeyConstraintError') {
|
|
184
|
+
errorBody.message = 'You cannot delete this item as it is in use';
|
|
185
|
+
errorBody.statusCode = 409;
|
|
186
|
+
errorBody.errorCode = '4090';
|
|
187
|
+
return errorBody;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (errorName === 'SequelizeUniqueConstraintError') {
|
|
191
|
+
const fields = _.get(body, 'errors', []).map(err => _.get(err, 'path')).filter(Boolean);
|
|
192
|
+
errorBody.message = fields.length
|
|
193
|
+
? 'A record with this ' + fields.join(', ') + ' already exists'
|
|
194
|
+
: 'A record with this value already exists';
|
|
195
|
+
errorBody.statusCode = 409;
|
|
196
|
+
errorBody.errorCode = '4091';
|
|
197
|
+
return errorBody;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (errorName === 'SequelizeValidationError') {
|
|
201
|
+
const messages = _.get(body, 'errors', []).map(err => _.get(err, 'message')).filter(Boolean);
|
|
202
|
+
errorBody.message = messages.length ? messages.join(', ') : 'Validation error';
|
|
203
|
+
errorBody.statusCode = 400;
|
|
204
|
+
errorBody.errorCode = '4001';
|
|
205
|
+
return errorBody;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let sequelizeError = _.get(body, 'errors', []).reduce((acc, err) => {
|
|
209
|
+
acc = acc + ' ' + _.get(err, 'message');
|
|
210
|
+
return acc;
|
|
211
|
+
}, '');
|
|
212
|
+
const parentError = _.get(body, 'parent', '');
|
|
213
|
+
|
|
214
|
+
sequelizeError = sequelizeError + _.get(body, 'original.detail', '') + _.get(body, 'TypeError', '') + parentError;
|
|
215
|
+
errorBody.message = sequelizeError.trim();
|
|
216
|
+
return errorBody;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function detectJoyError(body) {
|
|
220
|
+
const errorBody = {};
|
|
221
|
+
const details = _.get(body, 'details') || [];
|
|
222
|
+
|
|
223
|
+
console.error('USER VALIDATION ERROR:', JSON.stringify(body, null, 2));
|
|
224
|
+
const messages = extractJoyMessages(details);
|
|
225
|
+
const msg = messages.join(', ');
|
|
226
|
+
|
|
227
|
+
if (msg) {
|
|
228
|
+
errorBody.message = msg;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
errorBody.statusCode = 400;
|
|
232
|
+
errorBody.errorCode = '4000';
|
|
233
|
+
return errorBody;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function extractJoyMessages(details) {
|
|
237
|
+
const messages = [];
|
|
238
|
+
for (const detail of details) {
|
|
239
|
+
const contextDetails = _.get(detail, 'context.details') || [];
|
|
240
|
+
const directDetails = detail.details || [];
|
|
241
|
+
const nestedDetails = contextDetails.length > 0 ? contextDetails : directDetails;
|
|
242
|
+
|
|
243
|
+
if (nestedDetails.length > 0) {
|
|
244
|
+
messages.push(...extractJoyMessages(nestedDetails));
|
|
245
|
+
} else if (detail.message) {
|
|
246
|
+
let msg = detail.message;
|
|
247
|
+
if (detail.context?.value && /does not match/.test(msg)) {
|
|
248
|
+
const valueStr = JSON.stringify(detail.context.value);
|
|
249
|
+
const truncated = valueStr.length > 200 ? valueStr.substring(0, 200) + '...' : valueStr;
|
|
250
|
+
msg += ', received: ' + truncated;
|
|
251
|
+
}
|
|
252
|
+
messages.push(msg);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return messages;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Parse the body of a Dynamoose error response.
|
|
260
|
+
* Attempts to extract a human-readable error message from Dynamoose errors.
|
|
261
|
+
* This is a fallback for unknown database errors.
|
|
262
|
+
*
|
|
263
|
+
* @param {object} body - Part of a body response containing error details.
|
|
264
|
+
* @returns {object} - Error message object { message: string }
|
|
265
|
+
*/
|
|
266
|
+
export function detectDynamooseError(body) {
|
|
267
|
+
const errorBody = {};
|
|
268
|
+
|
|
269
|
+
// Start with an empty message string.
|
|
270
|
+
let dynamooseError = '';
|
|
271
|
+
|
|
272
|
+
// If the error body contains an array of errors, concatenate their messages.
|
|
273
|
+
if (Array.isArray(body.errors)) {
|
|
274
|
+
dynamooseError += body.errors.reduce((acc, err) => {
|
|
275
|
+
return acc + ' ' + (err.message || '');
|
|
276
|
+
}, '');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// If there's a top-level message, add it.
|
|
280
|
+
if (body.message) {
|
|
281
|
+
dynamooseError += ' ' + body.message;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// If there is any additional detail provided, append it.
|
|
285
|
+
if (body.detail) {
|
|
286
|
+
dynamooseError += ' ' + body.detail;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Trim the message to remove extra spaces.
|
|
290
|
+
errorBody.message = dynamooseError.trim();
|
|
291
|
+
|
|
292
|
+
return errorBody;
|
|
287
293
|
}
|