json-rest-api 1.0.14 → 1.0.16
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/connectors_ideas/fastify.js +66 -68
- package/connectors_ideas/koa-plugin.js +50 -51
- package/eslint.config.js +11 -2
- package/examples/url-override-example.js +63 -63
- package/index.js +13 -13
- package/lib/enhanced-logger.js +51 -51
- package/lib/error-formatter.js +61 -61
- package/lib/rest-api-errors.js +28 -28
- package/package.json +1 -1
- package/plugins/core/bulk-operations-plugin.js +142 -145
- package/plugins/core/connectors/express-plugin.js +210 -217
- package/plugins/core/connectors/lib/busboy-detector.js +84 -84
- package/plugins/core/connectors/lib/formidable-detector.js +50 -50
- package/plugins/core/connectors/lib/request-helpers.js +74 -74
- package/plugins/core/file-handling-plugin.js +125 -125
- package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
- package/plugins/core/lib/anyapi/schema-utils.js +101 -101
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
- package/plugins/core/lib/dbTablesOperations.js +134 -135
- package/plugins/core/lib/fractional-positioning.js +74 -76
- package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
- package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
- package/plugins/core/lib/querying/knex-process-includes.js +50 -50
- package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
- package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
- package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
- package/plugins/core/lib/querying/knex-window-queries.js +89 -89
- package/plugins/core/lib/querying/url-helpers.js +35 -35
- package/plugins/core/lib/querying-writing/compile-schemas.js +99 -99
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
- package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
- package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
- package/plugins/core/lib/querying-writing/field-utils.js +44 -42
- package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
- package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
- package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
- package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
- package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
- package/plugins/core/lib/storage/storage-adapter.js +68 -68
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
- package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
- package/plugins/core/lib/writing/relationship-processor.js +58 -58
- package/plugins/core/rest-api-access.js +11 -15
- package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
- package/plugins/core/rest-api-cors-plugin.js +170 -171
- package/plugins/core/rest-api-knex-plugin.js +482 -493
- package/plugins/core/rest-api-multihome-plugin.js +247 -251
- package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
- package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
- package/plugins/core/rest-api-plugin-methods/common.js +295 -297
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
- package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
- package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
- package/plugins/core/rest-api-plugin-methods/get.js +86 -86
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
- package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
- package/plugins/core/rest-api-plugin-methods/post.js +61 -62
- package/plugins/core/rest-api-plugin-methods/put.js +86 -87
- package/plugins/core/rest-api-plugin-methods/query.js +88 -88
- package/plugins/core/rest-api-plugin-methods/release.js +5 -6
- package/plugins/core/rest-api-plugin.js +76 -78
- package/plugins/core/rest-api-positioning-plugin.js +251 -252
- package/plugins/core/socketio-plugin.js +240 -236
- package/plugins/storage/local-storage.js +103 -103
- package/plugins/storage/s3-storage.js +41 -42
- package/quickTest.js +37 -37
- package/scripts/debug-anyapi-review-filter.mjs +18 -18
- package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
- package/scripts/inspect-anyapi-descriptor.mjs +10 -10
- package/scripts/run-docs.js +112 -113
- package/test-debug.js +28 -28
- package/tests/TEST_TEMPLATE.test.js +51 -51
- package/tests/anyapi-basic.test.js +42 -42
- package/tests/anyapi-cursor-pagination.test.js +48 -48
- package/tests/bulk-operations.test.js +208 -208
- package/tests/computed-fields.test.js +204 -204
- package/tests/cors.test.js +412 -413
- package/tests/curl.test.js +275 -276
- package/tests/custom-idproperty-relationships.test.js +266 -266
- package/tests/field-getters.test.js +132 -132
- package/tests/field-setters.test.js +110 -110
- package/tests/fixtures/api-configs.js +699 -699
- package/tests/helpers/storage-mode.js +32 -32
- package/tests/helpers/test-utils.js +76 -76
- package/tests/include-depth-validation.test.js +76 -76
- package/tests/includes.test.js +145 -145
- package/tests/multihome.test.js +175 -175
- package/tests/nested-includes.test.js +255 -255
- package/tests/pagination-cursor-multifield.test.js +164 -164
- package/tests/pagination-enhanced.test.js +225 -225
- package/tests/polymorphic-relationships.test.js +96 -96
- package/tests/polymorphic-simple.test.js +44 -44
- package/tests/positioning-advanced.test.js +226 -226
- package/tests/positioning-extended.test.js +399 -399
- package/tests/positioning-multifilter.test.js +204 -204
- package/tests/positioning.test.js +266 -266
- package/tests/queries.test.js +184 -184
- package/tests/query-limits.test.js +154 -155
- package/tests/relationship-endpoints.test.js +127 -127
- package/tests/relationships.test.js +178 -179
- package/tests/rest-api-access.test.js +86 -86
- package/tests/rest-api.test.js +103 -103
- package/tests/searchschema-merge.test.js +93 -93
- package/tests/socketio.test.js +326 -326
- package/tests/virtual-fields.test.js +164 -164
package/lib/enhanced-logger.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Wraps any logger to provide comprehensive error logging
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { formatError, formatErrorSummary, formatErrorString } from './error-formatter.js'
|
|
6
|
+
import { formatError, formatErrorSummary, formatErrorString } from './error-formatter.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Creates an enhanced logger that automatically formats errors
|
|
@@ -13,55 +13,55 @@ import { formatError, formatErrorSummary, formatErrorString } from './error-form
|
|
|
13
13
|
* @param {boolean} options.includeStack - Whether to include stack traces (default: true)
|
|
14
14
|
* @returns {Object} Enhanced logger with automatic error formatting
|
|
15
15
|
*/
|
|
16
|
-
export function createEnhancedLogger(baseLogger, options = {}) {
|
|
17
|
-
const {
|
|
18
|
-
logFullErrors = true,
|
|
19
|
-
includeStack = true
|
|
20
|
-
} = options
|
|
21
|
-
|
|
16
|
+
export function createEnhancedLogger (baseLogger, options = {}) {
|
|
17
|
+
const {
|
|
18
|
+
logFullErrors = true,
|
|
19
|
+
includeStack = true
|
|
20
|
+
} = options
|
|
21
|
+
|
|
22
22
|
// Helper to process arguments and format errors
|
|
23
|
-
function processArgs(args) {
|
|
23
|
+
function processArgs (args) {
|
|
24
24
|
return args.map(arg => {
|
|
25
25
|
// If it's an error object, format it
|
|
26
26
|
if (arg instanceof Error) {
|
|
27
27
|
if (logFullErrors) {
|
|
28
|
-
return formatError(arg, { includeStack })
|
|
28
|
+
return formatError(arg, { includeStack })
|
|
29
29
|
} else {
|
|
30
|
-
return formatErrorSummary(arg)
|
|
30
|
+
return formatErrorSummary(arg)
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
// If it's an object with an error property, format the error
|
|
35
35
|
if (arg && typeof arg === 'object' && arg.error instanceof Error) {
|
|
36
36
|
return {
|
|
37
37
|
...arg,
|
|
38
|
-
error: logFullErrors
|
|
38
|
+
error: logFullErrors
|
|
39
39
|
? formatError(arg.error, { includeStack })
|
|
40
40
|
: formatErrorSummary(arg.error)
|
|
41
|
-
}
|
|
41
|
+
}
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
return arg
|
|
45
|
-
})
|
|
43
|
+
|
|
44
|
+
return arg
|
|
45
|
+
})
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
// Create wrapper methods for each log level
|
|
49
|
-
const enhancedLogger = {}
|
|
50
|
-
|
|
49
|
+
const enhancedLogger = {}
|
|
50
|
+
|
|
51
51
|
// Common log levels
|
|
52
|
-
const logLevels = ['debug', 'info', 'warn', 'error', 'trace', 'fatal', 'log']
|
|
53
|
-
|
|
52
|
+
const logLevels = ['debug', 'info', 'warn', 'error', 'trace', 'fatal', 'log']
|
|
53
|
+
|
|
54
54
|
for (const level of logLevels) {
|
|
55
55
|
if (typeof baseLogger[level] === 'function') {
|
|
56
|
-
enhancedLogger[level] = function(...args) {
|
|
57
|
-
const processedArgs = processArgs(args)
|
|
58
|
-
|
|
56
|
+
enhancedLogger[level] = function (...args) {
|
|
57
|
+
const processedArgs = processArgs(args)
|
|
58
|
+
|
|
59
59
|
// Special handling for error level - always log full details
|
|
60
60
|
if (level === 'error' && args.some(arg => arg instanceof Error || (arg?.error instanceof Error))) {
|
|
61
61
|
// Log a formatted version as well for better readability
|
|
62
|
-
const errors = args.filter(arg => arg instanceof Error || arg?.error instanceof Error)
|
|
62
|
+
const errors = args.filter(arg => arg instanceof Error || arg?.error instanceof Error)
|
|
63
63
|
for (const errorArg of errors) {
|
|
64
|
-
const error = errorArg instanceof Error ? errorArg : errorArg.error
|
|
64
|
+
const error = errorArg instanceof Error ? errorArg : errorArg.error
|
|
65
65
|
if (error.details?.violations && Array.isArray(error.details.violations) && error.details.violations.length > 0) {
|
|
66
66
|
// Log violations in a readable format
|
|
67
67
|
baseLogger[level]('Validation error details:', {
|
|
@@ -71,34 +71,34 @@ export function createEnhancedLogger(baseLogger, options = {}) {
|
|
|
71
71
|
rule: v.rule,
|
|
72
72
|
message: v.message
|
|
73
73
|
}))
|
|
74
|
-
})
|
|
74
|
+
})
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
return baseLogger[level](...processedArgs)
|
|
80
|
-
}
|
|
78
|
+
|
|
79
|
+
return baseLogger[level](...processedArgs)
|
|
80
|
+
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
// Preserve any other properties/methods from the base logger
|
|
85
85
|
for (const key in baseLogger) {
|
|
86
86
|
if (!(key in enhancedLogger)) {
|
|
87
|
-
enhancedLogger[key] = baseLogger[key]
|
|
87
|
+
enhancedLogger[key] = baseLogger[key]
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
// Add utility methods
|
|
92
|
-
enhancedLogger.logError = function(message, error, additionalData = {}) {
|
|
93
|
-
const errorData = formatError(error, { includeStack })
|
|
92
|
+
enhancedLogger.logError = function (message, error, additionalData = {}) {
|
|
93
|
+
const errorData = formatError(error, { includeStack })
|
|
94
94
|
this.error(message, {
|
|
95
95
|
...additionalData,
|
|
96
96
|
error: errorData,
|
|
97
97
|
errorSummary: formatErrorSummary(error)
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
enhancedLogger.logValidationError = function(message, error, additionalData = {}) {
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
enhancedLogger.logValidationError = function (message, error, additionalData = {}) {
|
|
102
102
|
if (error.details?.violations && Array.isArray(error.details.violations)) {
|
|
103
103
|
this.error(message, {
|
|
104
104
|
...additionalData,
|
|
@@ -107,28 +107,28 @@ export function createEnhancedLogger(baseLogger, options = {}) {
|
|
|
107
107
|
violations: error.details.violations,
|
|
108
108
|
fields: error.details?.fields || [],
|
|
109
109
|
fullError: formatError(error, { includeStack: false })
|
|
110
|
-
})
|
|
110
|
+
})
|
|
111
111
|
} else {
|
|
112
|
-
this.logError(message, error, additionalData)
|
|
112
|
+
this.logError(message, error, additionalData)
|
|
113
113
|
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return enhancedLogger
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return enhancedLogger
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
120
|
* Middleware to enhance an existing logger instance
|
|
121
121
|
* Can be used to patch global loggers
|
|
122
122
|
*/
|
|
123
|
-
export function enhanceLogger(logger, options = {}) {
|
|
124
|
-
const enhanced = createEnhancedLogger(logger, options)
|
|
125
|
-
|
|
123
|
+
export function enhanceLogger (logger, options = {}) {
|
|
124
|
+
const enhanced = createEnhancedLogger(logger, options)
|
|
125
|
+
|
|
126
126
|
// Replace methods on the original logger
|
|
127
127
|
for (const key in enhanced) {
|
|
128
128
|
if (typeof enhanced[key] === 'function') {
|
|
129
|
-
logger[key] = enhanced[key]
|
|
129
|
+
logger[key] = enhanced[key]
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
|
|
133
|
-
return logger
|
|
134
|
-
}
|
|
132
|
+
|
|
133
|
+
return logger
|
|
134
|
+
}
|
package/lib/error-formatter.js
CHANGED
|
@@ -11,100 +11,100 @@
|
|
|
11
11
|
* @param {number} options.maxDepth - Maximum depth for nested objects (default: 5)
|
|
12
12
|
* @returns {Object} Formatted error object safe for JSON serialization
|
|
13
13
|
*/
|
|
14
|
-
export function formatError(error, options = {}) {
|
|
15
|
-
const { includeStack = true, maxDepth = 5 } = options
|
|
16
|
-
|
|
14
|
+
export function formatError (error, options = {}) {
|
|
15
|
+
const { includeStack = true, maxDepth = 5 } = options
|
|
16
|
+
|
|
17
17
|
if (!error) {
|
|
18
|
-
return null
|
|
18
|
+
return null
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// Handle circular references
|
|
22
|
-
const seen = new WeakSet()
|
|
23
|
-
|
|
24
|
-
function serialize(obj, depth = 0) {
|
|
22
|
+
const seen = new WeakSet()
|
|
23
|
+
|
|
24
|
+
function serialize (obj, depth = 0) {
|
|
25
25
|
if (depth > maxDepth) {
|
|
26
|
-
return '[Max depth exceeded]'
|
|
26
|
+
return '[Max depth exceeded]'
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
if (obj === null || obj === undefined) {
|
|
30
|
-
return obj
|
|
30
|
+
return obj
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
if (typeof obj !== 'object') {
|
|
34
|
-
return obj
|
|
34
|
+
return obj
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
if (seen.has(obj)) {
|
|
38
|
-
return '[Circular reference]'
|
|
38
|
+
return '[Circular reference]'
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
if (obj instanceof Date) {
|
|
42
|
-
return obj.toISOString()
|
|
42
|
+
return obj.toISOString()
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
if (obj instanceof RegExp) {
|
|
46
|
-
return obj.toString()
|
|
46
|
+
return obj.toString()
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
seen.add(obj)
|
|
50
|
-
|
|
48
|
+
|
|
49
|
+
seen.add(obj)
|
|
50
|
+
|
|
51
51
|
if (Array.isArray(obj)) {
|
|
52
|
-
return obj.map(item => serialize(item, depth + 1))
|
|
52
|
+
return obj.map(item => serialize(item, depth + 1))
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
const result = {}
|
|
54
|
+
|
|
55
|
+
const result = {}
|
|
56
56
|
for (const key of Object.keys(obj)) {
|
|
57
57
|
try {
|
|
58
|
-
result[key] = serialize(obj[key], depth + 1)
|
|
58
|
+
result[key] = serialize(obj[key], depth + 1)
|
|
59
59
|
} catch (e) {
|
|
60
|
-
result[key] = `[Error serializing: ${e.message}]
|
|
60
|
+
result[key] = `[Error serializing: ${e.message}]`
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
return result
|
|
63
|
+
|
|
64
|
+
return result
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
// Start with basic error properties
|
|
68
68
|
const formatted = {
|
|
69
69
|
name: error.name || 'Error',
|
|
70
70
|
message: error.message || '',
|
|
71
71
|
...(includeStack && error.stack ? { stack: error.stack } : {})
|
|
72
|
-
}
|
|
73
|
-
|
|
72
|
+
}
|
|
73
|
+
|
|
74
74
|
// If error has a toJSON method, use it
|
|
75
75
|
if (typeof error.toJSON === 'function') {
|
|
76
76
|
try {
|
|
77
|
-
const jsonError = error.toJSON()
|
|
78
|
-
Object.assign(formatted, serialize(jsonError))
|
|
77
|
+
const jsonError = error.toJSON()
|
|
78
|
+
Object.assign(formatted, serialize(jsonError))
|
|
79
79
|
} catch (e) {
|
|
80
|
-
formatted.toJSONError = `Failed to call toJSON: ${e.message}
|
|
80
|
+
formatted.toJSONError = `Failed to call toJSON: ${e.message}`
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
// Add all enumerable properties
|
|
85
85
|
for (const key of Object.keys(error)) {
|
|
86
86
|
if (!(key in formatted)) {
|
|
87
87
|
try {
|
|
88
|
-
formatted[key] = serialize(error[key])
|
|
88
|
+
formatted[key] = serialize(error[key])
|
|
89
89
|
} catch (e) {
|
|
90
|
-
formatted[key] = `[Error serializing: ${e.message}]
|
|
90
|
+
formatted[key] = `[Error serializing: ${e.message}]`
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
// Ensure specific error properties are included
|
|
96
|
-
const importantProps = ['code', 'type', 'details', 'violations', 'subtype', 'path', 'fields']
|
|
96
|
+
const importantProps = ['code', 'type', 'details', 'violations', 'subtype', 'path', 'fields']
|
|
97
97
|
for (const prop of importantProps) {
|
|
98
98
|
if (error[prop] !== undefined && !(prop in formatted)) {
|
|
99
99
|
try {
|
|
100
|
-
formatted[prop] = serialize(error[prop])
|
|
100
|
+
formatted[prop] = serialize(error[prop])
|
|
101
101
|
} catch (e) {
|
|
102
|
-
formatted[prop] = `[Error serializing: ${e.message}]
|
|
102
|
+
formatted[prop] = `[Error serializing: ${e.message}]`
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
return formatted
|
|
106
|
+
|
|
107
|
+
return formatted
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
@@ -113,9 +113,9 @@ export function formatError(error, options = {}) {
|
|
|
113
113
|
* @param {Object} options - Formatting options
|
|
114
114
|
* @returns {string} Formatted error string
|
|
115
115
|
*/
|
|
116
|
-
export function formatErrorString(error, options = {}) {
|
|
117
|
-
const formatted = formatError(error, options)
|
|
118
|
-
return JSON.stringify(formatted, null, 2)
|
|
116
|
+
export function formatErrorString (error, options = {}) {
|
|
117
|
+
const formatted = formatError(error, options)
|
|
118
|
+
return JSON.stringify(formatted, null, 2)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|
|
@@ -123,25 +123,25 @@ export function formatErrorString(error, options = {}) {
|
|
|
123
123
|
* @param {Error} error - The error to summarize
|
|
124
124
|
* @returns {string} One-line error summary
|
|
125
125
|
*/
|
|
126
|
-
export function formatErrorSummary(error) {
|
|
127
|
-
if (!error) return 'Unknown error'
|
|
128
|
-
|
|
129
|
-
const parts = [error.message || 'No message']
|
|
130
|
-
|
|
126
|
+
export function formatErrorSummary (error) {
|
|
127
|
+
if (!error) return 'Unknown error'
|
|
128
|
+
|
|
129
|
+
const parts = [error.message || 'No message']
|
|
130
|
+
|
|
131
131
|
if (error.code) {
|
|
132
|
-
parts.push(`code: ${error.code}`)
|
|
132
|
+
parts.push(`code: ${error.code}`)
|
|
133
133
|
}
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
if (error.details?.violations && Array.isArray(error.details.violations) && error.details.violations.length > 0) {
|
|
136
136
|
const violationSummary = error.details.violations
|
|
137
137
|
.map(v => `${v.field}: ${v.message}`)
|
|
138
|
-
.join(', ')
|
|
139
|
-
parts.push(`violations: [${violationSummary}]`)
|
|
138
|
+
.join(', ')
|
|
139
|
+
parts.push(`violations: [${violationSummary}]`)
|
|
140
140
|
}
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
if (error.details?.fields && Array.isArray(error.details.fields) && error.details.fields.length > 0) {
|
|
143
|
-
parts.push(`fields: ${error.details.fields.join(', ')}`)
|
|
143
|
+
parts.push(`fields: ${error.details.fields.join(', ')}`)
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
return parts.join(' | ')
|
|
147
|
-
}
|
|
145
|
+
|
|
146
|
+
return parts.join(' | ')
|
|
147
|
+
}
|
package/lib/rest-api-errors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HookedApiError } from 'hooked-api'
|
|
1
|
+
import { HookedApiError } from 'hooked-api'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* REST API specific error classes that can be mapped to HTTP status codes
|
|
@@ -10,17 +10,17 @@ import { HookedApiError } from 'hooked-api';
|
|
|
10
10
|
* HTTP plugin should map this to 422 Unprocessable Entity
|
|
11
11
|
*/
|
|
12
12
|
export class RestApiValidationError extends HookedApiError {
|
|
13
|
-
constructor(message, { fields = [], violations = [] } = {}) {
|
|
14
|
-
super(message, 'REST_API_VALIDATION_ERROR')
|
|
15
|
-
this.code = 'REST_API_VALIDATION'
|
|
16
|
-
this.type = 'rest_api_validation'
|
|
13
|
+
constructor (message, { fields = [], violations = [] } = {}) {
|
|
14
|
+
super(message, 'REST_API_VALIDATION_ERROR')
|
|
15
|
+
this.code = 'REST_API_VALIDATION'
|
|
16
|
+
this.type = 'rest_api_validation'
|
|
17
17
|
this.details = {
|
|
18
18
|
fields,
|
|
19
19
|
violations
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
toJSON() {
|
|
22
|
+
|
|
23
|
+
toJSON () {
|
|
24
24
|
return {
|
|
25
25
|
name: this.name,
|
|
26
26
|
message: this.message,
|
|
@@ -28,7 +28,7 @@ export class RestApiValidationError extends HookedApiError {
|
|
|
28
28
|
type: this.type,
|
|
29
29
|
details: this.details,
|
|
30
30
|
stack: this.stack
|
|
31
|
-
}
|
|
31
|
+
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -37,18 +37,18 @@ export class RestApiValidationError extends HookedApiError {
|
|
|
37
37
|
* HTTP plugin should map based on subtype
|
|
38
38
|
*/
|
|
39
39
|
export class RestApiResourceError extends HookedApiError {
|
|
40
|
-
constructor(message, { subtype, resourceType, resourceId } = {}) {
|
|
41
|
-
super(message, 'REST_API_RESOURCE_ERROR')
|
|
42
|
-
this.code = 'REST_API_RESOURCE'
|
|
43
|
-
this.type = 'rest_api_resource'
|
|
44
|
-
this.subtype = subtype
|
|
40
|
+
constructor (message, { subtype, resourceType, resourceId } = {}) {
|
|
41
|
+
super(message, 'REST_API_RESOURCE_ERROR')
|
|
42
|
+
this.code = 'REST_API_RESOURCE'
|
|
43
|
+
this.type = 'rest_api_resource'
|
|
44
|
+
this.subtype = subtype // 'not_found', 'conflict', 'forbidden'
|
|
45
45
|
this.details = {
|
|
46
46
|
resourceType,
|
|
47
47
|
resourceId
|
|
48
|
-
}
|
|
48
|
+
}
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
toJSON() {
|
|
50
|
+
|
|
51
|
+
toJSON () {
|
|
52
52
|
return {
|
|
53
53
|
name: this.name,
|
|
54
54
|
message: this.message,
|
|
@@ -57,7 +57,7 @@ export class RestApiResourceError extends HookedApiError {
|
|
|
57
57
|
subtype: this.subtype,
|
|
58
58
|
details: this.details,
|
|
59
59
|
stack: this.stack
|
|
60
|
-
}
|
|
60
|
+
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -66,19 +66,19 @@ export class RestApiResourceError extends HookedApiError {
|
|
|
66
66
|
* HTTP plugin should map this to 400 Bad Request
|
|
67
67
|
*/
|
|
68
68
|
export class RestApiPayloadError extends HookedApiError {
|
|
69
|
-
constructor(message, { path, expected, received } = {}) {
|
|
70
|
-
super(message, 'REST_API_PAYLOAD_ERROR')
|
|
71
|
-
this.code = 'REST_API_PAYLOAD'
|
|
72
|
-
this.type = 'rest_api_payload'
|
|
73
|
-
this.path = path
|
|
69
|
+
constructor (message, { path, expected, received } = {}) {
|
|
70
|
+
super(message, 'REST_API_PAYLOAD_ERROR')
|
|
71
|
+
this.code = 'REST_API_PAYLOAD'
|
|
72
|
+
this.type = 'rest_api_payload'
|
|
73
|
+
this.path = path
|
|
74
74
|
this.details = {
|
|
75
75
|
path,
|
|
76
76
|
expected,
|
|
77
77
|
received
|
|
78
|
-
}
|
|
78
|
+
}
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
toJSON() {
|
|
80
|
+
|
|
81
|
+
toJSON () {
|
|
82
82
|
return {
|
|
83
83
|
name: this.name,
|
|
84
84
|
message: this.message,
|
|
@@ -87,6 +87,6 @@ export class RestApiPayloadError extends HookedApiError {
|
|
|
87
87
|
path: this.path,
|
|
88
88
|
details: this.details,
|
|
89
89
|
stack: this.stack
|
|
90
|
-
}
|
|
90
|
+
}
|
|
91
91
|
}
|
|
92
|
-
}
|
|
92
|
+
}
|