@technomoron/api-server-base 1.1.1 → 1.1.3
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.
|
@@ -133,6 +133,13 @@ class ApiError extends Error {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
exports.ApiError = ApiError;
|
|
136
|
+
function isApiErrorLike(candidate) {
|
|
137
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
const maybeError = candidate;
|
|
141
|
+
return typeof maybeError.code === 'number' && typeof maybeError.message === 'string';
|
|
142
|
+
}
|
|
136
143
|
function fillConfig(config) {
|
|
137
144
|
return {
|
|
138
145
|
apiPort: config.apiPort ?? 3101,
|
|
@@ -428,16 +435,31 @@ class ApiServer {
|
|
|
428
435
|
}
|
|
429
436
|
apiReq.tokenData = await this.authenticate(apiReq, auth.type);
|
|
430
437
|
await this.authorize(apiReq, auth.req);
|
|
431
|
-
const
|
|
438
|
+
const handlerResult = await handler(apiReq);
|
|
439
|
+
if (!Array.isArray(handlerResult)) {
|
|
440
|
+
throw new ApiError({
|
|
441
|
+
code: 500,
|
|
442
|
+
message: 'Handler result must be an array: [status, data?, message?]'
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
const [code, data = null, rawMessage = 'Success'] = handlerResult;
|
|
446
|
+
if (typeof code !== 'number' || Number.isNaN(code)) {
|
|
447
|
+
throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
|
|
448
|
+
}
|
|
449
|
+
const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
|
|
432
450
|
res.status(code).json({ code, message, data });
|
|
433
451
|
}
|
|
434
452
|
catch (error) {
|
|
435
|
-
if (error instanceof ApiError) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
453
|
+
if (error instanceof ApiError || isApiErrorLike(error)) {
|
|
454
|
+
const apiError = error;
|
|
455
|
+
const normalizedErrors = apiError.errors && typeof apiError.errors === 'object' && !Array.isArray(apiError.errors)
|
|
456
|
+
? apiError.errors
|
|
457
|
+
: {};
|
|
458
|
+
res.status(apiError.code).json({
|
|
459
|
+
code: apiError.code,
|
|
460
|
+
message: apiError.message,
|
|
461
|
+
data: apiError.data ?? null,
|
|
462
|
+
errors: normalizedErrors
|
|
441
463
|
});
|
|
442
464
|
}
|
|
443
465
|
else {
|
|
@@ -445,7 +467,7 @@ class ApiServer {
|
|
|
445
467
|
code: 500,
|
|
446
468
|
message: this.guessExceptionText(error),
|
|
447
469
|
data: null,
|
|
448
|
-
errors:
|
|
470
|
+
errors: {}
|
|
449
471
|
});
|
|
450
472
|
}
|
|
451
473
|
}
|
|
@@ -125,6 +125,13 @@ export class ApiError extends Error {
|
|
|
125
125
|
this.errors = errors !== undefined ? errors : {};
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
function isApiErrorLike(candidate) {
|
|
129
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const maybeError = candidate;
|
|
133
|
+
return typeof maybeError.code === 'number' && typeof maybeError.message === 'string';
|
|
134
|
+
}
|
|
128
135
|
function fillConfig(config) {
|
|
129
136
|
return {
|
|
130
137
|
apiPort: config.apiPort ?? 3101,
|
|
@@ -420,16 +427,31 @@ export class ApiServer {
|
|
|
420
427
|
}
|
|
421
428
|
apiReq.tokenData = await this.authenticate(apiReq, auth.type);
|
|
422
429
|
await this.authorize(apiReq, auth.req);
|
|
423
|
-
const
|
|
430
|
+
const handlerResult = await handler(apiReq);
|
|
431
|
+
if (!Array.isArray(handlerResult)) {
|
|
432
|
+
throw new ApiError({
|
|
433
|
+
code: 500,
|
|
434
|
+
message: 'Handler result must be an array: [status, data?, message?]'
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
const [code, data = null, rawMessage = 'Success'] = handlerResult;
|
|
438
|
+
if (typeof code !== 'number' || Number.isNaN(code)) {
|
|
439
|
+
throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
|
|
440
|
+
}
|
|
441
|
+
const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
|
|
424
442
|
res.status(code).json({ code, message, data });
|
|
425
443
|
}
|
|
426
444
|
catch (error) {
|
|
427
|
-
if (error instanceof ApiError) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
445
|
+
if (error instanceof ApiError || isApiErrorLike(error)) {
|
|
446
|
+
const apiError = error;
|
|
447
|
+
const normalizedErrors = apiError.errors && typeof apiError.errors === 'object' && !Array.isArray(apiError.errors)
|
|
448
|
+
? apiError.errors
|
|
449
|
+
: {};
|
|
450
|
+
res.status(apiError.code).json({
|
|
451
|
+
code: apiError.code,
|
|
452
|
+
message: apiError.message,
|
|
453
|
+
data: apiError.data ?? null,
|
|
454
|
+
errors: normalizedErrors
|
|
433
455
|
});
|
|
434
456
|
}
|
|
435
457
|
else {
|
|
@@ -437,7 +459,7 @@ export class ApiServer {
|
|
|
437
459
|
code: 500,
|
|
438
460
|
message: this.guessExceptionText(error),
|
|
439
461
|
data: null,
|
|
440
|
-
errors:
|
|
462
|
+
errors: {}
|
|
441
463
|
});
|
|
442
464
|
}
|
|
443
465
|
}
|