aio-lib-core-errors
This contains the base class for all Adobe I/O Core Errors. Use this as an Error class subclass for all your SDK Errors.
This module was inspired by how Node.js creates its own Error classes.
AioCoreSDKError
This is the base class for all the Error classes, and it should not be instantiated directly. Create your own subclass (dynamic usage) or use the ErrorWrapper below (static usage).
The message
property of AioCoreSDKError
outputs the Error in this format:
[SDK:ERROR_CODE] ERROR_MESSAGE
SDK
is the SDK nameERROR_CODE
is the error codeERROR_MESSAGE
is the error message
Note that the sdk details
is not displayed in the message. To see any sdk details
, you will need to convert the Error object itself to JSON via .toJSON()
(JSON.stringify
will convert the Error object as well, via invoking .toJSON()
on the Error object)
Dynamic Errors Usage
const { AioCoreSDKError } = require('@adobe/aio-lib-errors')
const gSDKDetails = {
tenantId,
endpoint
}
const gSDKName = "AdobeIOCampaignStandard"
export default class CampaignStandardCoreAPIError extends AioCoreSDKError {
constructor(message, code) {
super(message, code, gSDKName, gSDKDetails)
}
}
So if we have this wrapper function, we change from:
function getAllProfiles (parameters) {
return new Promise((resolve, reject) => {
const apiFunc = 'getAllProfiles'
this.sdk.apis.profile[apiFunc]()
.then(response => {
resolve(response)
})
.catch(err => {
debug(err)
reject(new Error(`${apiFunc} ${err}`))
})
})
}
to this:
function getAllProfiles (parameters) {
return new Promise((resolve, reject) => {
const apiFunc = 'getAllProfiles'
this.sdk.apis.profile[apiFunc]()
.then(response => {
resolve(response)
})
.catch(err => {
debug(err)
reject(new CampaignStandardCoreAPIError(err.message , apiFunc ))
})
})
}
As you can see, this is not very intuitive, and may be error-prone. We can do better with static errors (see below).
Static Errors
The example Usage above is for dynamic errors, for example API errors that we are wrapping. Static errors are much better: they are more intuitive to use, and much better for code readability.
1. Create your Error Class via the ErrorWrapper
We define our specialized Error class, and error codes in its own module like so:
const { ErrorWrapper, createUpdater } = require('@adobe/aio-lib-core-errors').AioCoreSDKErrorWrapper
const codes = {}
const messages = new Map()
const Updater = createUpdater(
codes,
messages
)
const E = ErrorWrapper(
'MySDKError',
'MySDK',
Updater
)
module.exports = {
codes,
messages
}
E('UNKNOWN_THING_ID', 'There was a problem with that thing')
E('UNKNOWN_ORDER_ID', 'There was a problem with that order id: %s.')
Error Class Wrapper
Let's parse what this line means:
E('UNKNOWN_ORDER_ID', 'There was a problem with that order id: %s.')
This will dynamically create a MySDKError
class with the appropriate closures for values:
- sdk name (
MySDK
, passed in to the ErrorWrapper constructor above) - sdk error class name (
MySDKError
, passed in to the ErrorWrapper constructor above) - error code (
UNKNOWN_ORDER_ID
, the first parameter passed in to E
) - error message (
There was a problem with that order id: %s.
, the second parameter passed in to E
. If this is a string with format specifiers
, you can pass in arguments for the format specifiers, when the Error is constructed. See example below).
class MySDKError extends AioCoreSDKError { ... }
The line will add the dynamically created MySDKError
class to the exported codes
object, with the first parameter to the wrapper (the error code) as the key.
The constructor
for the class created takes one parameter, an object:
constructor(parameters)
parameters
(optional) is an object
parameters.sdkDetails
(optional) is an object
that you want to pass in as additional data for the Error object. e.g. function parameters for an API call.parameters.messageValues
(optional) is a string
, number
, object
or an array
of the items that you want to apply to the error message, if the message has a format specifier.
In the error specification line below, you can see it has one format specifier %s
:
E('UNKNOWN_ORDER_ID', 'There was a problem with that order id: %s.')
2. Use Your Error Classes
Import the static error code Error classes, and use directly.
const { UNKNOWN_THING_ID, UNKNOWN_ORDER_ID } = require('./SDKErrors').codes
const gSdkDetails = {
tenantId: 'mytenant'
}
const unknownThing = true
if (unknownThing) {
throw new UNKNOWN_THING_ID({ sdkDetails: gSDKDetails })
}
const unknownOrderId = true
if (unknownOrderId) {
throw new UNKNOWN_ORDER_ID({
sdkDetails: gSDKDetails,
messageValues: ['ORDER-2125SFG']
}) )
}
function getOrder(orderId) {
const sdkDetails = { orderId }
const somethingWentWrong = true
if (somethingWentWrong) {
throw new UNKNOWN_ORDER_ID({
sdkDetails: sDKDetails,
messageValues: 'ORDER-2125SFGF'
}) )
}
}
getOrder('abc123')
Example Console Output
Print out a thrown UNKNOWN_ORDER_ID
Error object to the console. console
calls the .toString()
method for the Error object, and the resulting data is not structured well, and will not expand nested objects:
try {
throw new UNKNOWN_ORDER_ID()
} catch (e) {
console.error(e)
}
Output:
{ MySDKError: [MySDK:UNKNOWN_ORDER_ID] There was a problem with that order id: ORDER-21241-FSFS.
at new <anonymous> (/Users/obfuscated/aio-lib-core-errors/src/AioCoreSDKErrorWrapper.js:22:9)
at Object.<anonymous>.test (/Users/obfuscated/aio-lib-core-errors/test/MySDKError.test.js:50:15)
at Object.asyncJestTest (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
at resolve (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
at new Promise (<anonymous>)
at mapper (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
at promise.then (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
at process._tickCallback (internal/process/next_tick.js:68:7)
code: 'UNKNOWN_ORDER_ID',
sdk: 'MySDK',
sdkDetails: { tenantId: 'MYTENANT2' },
name: 'MySDKError' }
Simply print out a thrown UNKNOWN_ORDER_ID
Error object's message
property to the console:
try {
throw new UNKNOWN_ORDER_ID()
} catch (e) {
console.error(e.message)
}
Output:
[MySDK:UNKNOWN_ORDER_ID] There was a problem with that order id: ORDER-21241-FSFS.
Convert a thrown UNKNOWN_ORDER_ID
Error object to JSON and print to the console. console
calls the .toJSON()
method of the Error object, and will expand nested objects:
try {
throw new UNKNOWN_ORDER_ID()
} catch (e) {
console.error(JSON.stringify(e, null, 2))
}
Output:
{
"sdk": {
"name": "MySDK",
"details": {
"tenantId": "MYTENANT2"
}
},
"code": "UNKNOWN_ORDER_ID",
"message": "[MySDK:UNKNOWN_ORDER_ID] There was a problem with that order id: ORDER-21241-FSFS.",
"stacktrace": "MySDKError: [MySDK:UNKNOWN_ORDER_ID] There was a problem with that order id: ORDER-21241-FSFS.\n at new <anonymous> (/Users/obfuscated/aio-lib-core-errors/src/AioCoreSDKErrorWrapper.js:22:9)\n at Object.<anonymous>.test (/Users/obfuscated/aio-lib-core-errors/test/MySDKError.test.js:50:15)\n at Object.asyncJestTest (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)\n at resolve (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:43:12)\n at new Promise (<anonymous>)\n at mapper (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:26:19)\n at promise.then (/Users/obfuscated/aio-lib-core-errors/node_modules/jest-jasmine2/build/queueRunner.js:73:41)\n at process._tickCallback (internal/process/next_tick.js:68:7)"
}