Comparing version 1.2.10 to 1.3.1
import ExtendableError from 'es6-error'; | ||
import { DeserializeOpts, IBaseError, IBaseErrorConfig, SerializedError, SerializedErrorSafe } from '../interfaces'; | ||
import { ConvertedType, ConvertFn, DeserializeOpts, IBaseError, IBaseErrorConfig, SerializedError, SerializedErrorSafe } from '../interfaces'; | ||
/** | ||
@@ -19,2 +19,3 @@ * Improved error class. | ||
protected _hasSafeMetadata: boolean; | ||
protected _onConvert: ConvertFn | null; | ||
constructor(message: string, config?: IBaseErrorConfig); | ||
@@ -138,2 +139,16 @@ /** | ||
/** | ||
* Calls the user-defined `onConvert` function to convert the error into another type. | ||
* If `onConvert` is not defined, then returns the error itself. | ||
*/ | ||
convert<T = ConvertedType>(): T; | ||
/** | ||
* Returns true if the onConvert handler is defined | ||
*/ | ||
hasOnConvertDefined(): boolean; | ||
/** | ||
* Set the onConvert handler for convert() calls. | ||
* This can also be defined via the onConvert config property in the constructor. | ||
*/ | ||
setOnConvert(convertFn: ConvertFn): void; | ||
/** | ||
* Helper method for use with fromJson() | ||
@@ -140,0 +155,0 @@ * @param errInstance An error instance that extends BaseError |
@@ -20,2 +20,3 @@ "use strict"; | ||
this._config = config || {}; | ||
this._onConvert = this._config.onConvert || null; | ||
} | ||
@@ -195,3 +196,2 @@ /** | ||
toJSON(fieldsToOmit = []) { | ||
var _a; | ||
let data = { | ||
@@ -227,8 +227,12 @@ errId: this._errId, | ||
}); | ||
fieldsToOmit === null || fieldsToOmit === void 0 ? void 0 : fieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
(_a = this._config.toJSONFieldsToOmit) === null || _a === void 0 ? void 0 : _a.forEach(item => { | ||
delete data[item]; | ||
}); | ||
if (Array.isArray(fieldsToOmit)) { | ||
fieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
} | ||
if (Array.isArray(this._config.toJSONFieldsToOmit)) { | ||
this._config.toJSONFieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
} | ||
return data; | ||
@@ -242,3 +246,2 @@ } | ||
toJSONSafe(fieldsToOmit = []) { | ||
var _a; | ||
let data = { | ||
@@ -265,11 +268,38 @@ errId: this._errId, | ||
} | ||
fieldsToOmit === null || fieldsToOmit === void 0 ? void 0 : fieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
(_a = this._config.toJSONSafeFieldsToOmit) === null || _a === void 0 ? void 0 : _a.forEach(item => { | ||
delete data[item]; | ||
}); | ||
if (Array.isArray(fieldsToOmit)) { | ||
fieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
} | ||
if (Array.isArray(this._config.toJSONSafeFieldsToOmit)) { | ||
this._config.toJSONSafeFieldsToOmit.forEach(item => { | ||
delete data[item]; | ||
}); | ||
} | ||
return data; | ||
} | ||
/** | ||
* Calls the user-defined `onConvert` function to convert the error into another type. | ||
* If `onConvert` is not defined, then returns the error itself. | ||
*/ | ||
convert() { | ||
if (this._onConvert) { | ||
return this._onConvert(this); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Returns true if the onConvert handler is defined | ||
*/ | ||
hasOnConvertDefined() { | ||
return typeof this._onConvert === 'function'; | ||
} | ||
/** | ||
* Set the onConvert handler for convert() calls. | ||
* This can also be defined via the onConvert config property in the constructor. | ||
*/ | ||
setOnConvert(convertFn) { | ||
this._onConvert = convertFn; | ||
} | ||
/** | ||
* Helper method for use with fromJson() | ||
@@ -276,0 +306,0 @@ * @param errInstance An error instance that extends BaseError |
@@ -10,2 +10,8 @@ "use strict"; | ||
constructor(highLevelErrorDef, lowLevelErrorDef, config = {}) { | ||
if (typeof highLevelErrorDef.onConvert === 'function') { | ||
config.onConvert = highLevelErrorDef.onConvert; | ||
} | ||
if (typeof lowLevelErrorDef.onConvert === 'function') { | ||
config.onConvert = lowLevelErrorDef.onConvert; | ||
} | ||
super(lowLevelErrorDef.message, config); | ||
@@ -12,0 +18,0 @@ this.withErrorCode(highLevelErrorDef.code); |
import { BaseError } from './error-types/BaseError'; | ||
import { BaseRegistryError } from './error-types/BaseRegistryError'; | ||
import { ErrorRegistry } from './ErrorRegistry'; | ||
import { IBaseError, SerializedError, SerializedErrorSafe, HighLevelError, LowLevelError, DeserializeOpts, GenerateLowLevelErrorOpts, GenerateHighLevelErrorOpts } from './interfaces'; | ||
import { IBaseError, SerializedError, SerializedErrorSafe, HighLevelError, LowLevelError, DeserializeOpts, GenerateLowLevelErrorOpts, GenerateHighLevelErrorOpts, ConvertedType, ConvertFn } from './interfaces'; | ||
export * from './utils'; | ||
export { BaseError, BaseRegistryError, ErrorRegistry, IBaseError, HighLevelError, LowLevelError, SerializedError, SerializedErrorSafe, DeserializeOpts, GenerateLowLevelErrorOpts, GenerateHighLevelErrorOpts }; | ||
export { BaseError, BaseRegistryError, ErrorRegistry, IBaseError, HighLevelError, LowLevelError, SerializedError, SerializedErrorSafe, DeserializeOpts, GenerateLowLevelErrorOpts, GenerateHighLevelErrorOpts, ConvertedType, ConvertFn }; |
@@ -5,2 +5,3 @@ /** | ||
import { BaseRegistryError } from './error-types/BaseRegistryError'; | ||
import { BaseError } from './error-types/BaseError'; | ||
export interface HighLevelError { | ||
@@ -24,2 +25,11 @@ /** | ||
logLevel?: string | number; | ||
/** | ||
* Callback function to call when calling BaseError#convert(). | ||
* | ||
* (baseError) => any type | ||
* | ||
* - If not defined, will return itself when convert() is called | ||
* - If defined in HighLevelError, the HighLevelError definition takes priority | ||
*/ | ||
onConvert?: ConvertFn; | ||
} | ||
@@ -60,2 +70,11 @@ /** | ||
logLevel?: string | number; | ||
/** | ||
* Callback function to call when calling BaseError#convert(). | ||
* | ||
* (baseError) => any type | ||
* | ||
* - If not defined, will return itself when convert() is called | ||
* - This definition takes priority if HighLevelError#onConvert is defined | ||
*/ | ||
onConvert?: ConvertFn; | ||
} | ||
@@ -131,2 +150,7 @@ /** | ||
/** | ||
* Set the onConvert handler for convert() calls. | ||
* This can also be defined via the onConvert config property in the constructor. | ||
*/ | ||
setOnConvert(convertFn: ConvertFn): void; | ||
/** | ||
* Attach the original error that was thrown, if available | ||
@@ -200,2 +224,11 @@ * @param {Error} error | ||
/** | ||
* Calls the user-defined `onConvert` function to convert the error into another type. | ||
* If `onConvert` is not defined, then returns the error itself. | ||
*/ | ||
convert<T = ConvertedType>(): T; | ||
/** | ||
* Returns true if the onConvert handler is defined | ||
*/ | ||
hasOnConvertDefined(): boolean; | ||
/** | ||
* Stack trace | ||
@@ -231,2 +264,9 @@ */ | ||
onPreToJSONSafeData?: (data: Partial<SerializedErrorSafe>) => Partial<SerializedErrorSafe>; | ||
/** | ||
* A callback function to call when calling BaseError#convert(). This allows for user-defined conversion | ||
* of the BaseError into some other type (such as an Apollo GraphQL error type). | ||
* | ||
* (baseError) => any type | ||
*/ | ||
onConvert?: ConvertFn; | ||
} | ||
@@ -327,1 +367,3 @@ /** | ||
} | ||
export declare type ConvertedType = any; | ||
export declare type ConvertFn = <E extends BaseError = BaseError>(err: E) => ConvertedType; |
@@ -0,1 +1,11 @@ | ||
## 1.3.1 - Sun Mar 14 2021 03:09:54 | ||
**Contributor:** Theo Gravity | ||
- Add the ability to convert an error to another type (#11) | ||
This is useful if you need to convert the errors created by this library into another type, such as a `GraphQLError` when going outbound to the client. | ||
See the README for more details. | ||
## 1.2.10 - Fri Mar 12 2021 02:21:26 | ||
@@ -2,0 +12,0 @@ |
{ | ||
"name": "new-error", | ||
"version": "1.2.10", | ||
"version": "1.3.1", | ||
"description": "A production-grade error creation and serialization library designed for Typescript", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
143
README.md
@@ -53,5 +53,8 @@ # new-error | ||
- [Static methods](#static-methods) | ||
- [Utility methods](#utility-methods) | ||
- [Set an error id](#set-an-error-id) | ||
- [Attaching errors](#attaching-errors) | ||
- [Format messages](#format-messages) | ||
- [Converting the error into another type](#converting-the-error-into-another-type) | ||
- [Apollo GraphQL example](#apollo-graphql-example) | ||
- [Adding metadata](#adding-metadata) | ||
@@ -595,3 +598,3 @@ - [Safe metadata](#safe-metadata) | ||
Generated errors extend the `BaseError` class, which supplies the manipulation methods. | ||
Generated errors extend the `BaseError` class, which extends `Error`. | ||
@@ -630,2 +633,9 @@ ## Constructor | ||
onPreToJSONSafeData?: (data: Partial<SerializedErrorSafe>) => Partial<SerializedErrorSafe> | ||
/** | ||
* A callback function to call when calling BaseError#convert(). This allows for user-defined conversion | ||
* of the BaseError into some other type (such as a Apollo GraphQL error type). | ||
* | ||
* (baseError) => any type | ||
*/ | ||
onConvert?: <E extends BaseError = BaseError>(err: E) => any | ||
} | ||
@@ -636,2 +646,4 @@ ``` | ||
The following getters are included with the standard `Error` properties and methods: | ||
- `BaseError#getErrorId()` | ||
@@ -659,2 +671,3 @@ - `BaseError#getErrorName()` | ||
- `BaseError#setConfig(config: IBaseErrorConfig): void` | ||
- `BaseError#setOnConvert(<E extends BaseError = BaseError>(err: E) => any): void` | ||
@@ -665,2 +678,7 @@ ## Static methods | ||
## Utility methods | ||
- `BaseError#convert<E = BaseError | any>() : E` | ||
- `BaseError#hasOnConvertDefined(): boolean` | ||
## Set an error id | ||
@@ -713,2 +731,125 @@ | ||
The message can be accessed via the `.message` property. | ||
## Converting the error into another type | ||
Method: `BaseError#convert<T = any>() : T` | ||
This is useful if you need to convert the error into another type. This type can be another error or some other data type. | ||
### Apollo GraphQL example | ||
For example, Apollo GraphQL prefers that any errors thrown from a GQL endpoint is an error that extends [`ApolloError`](https://www.apollographql.com/docs/apollo-server/data/errors/). | ||
You might find yourself doing the following pattern if your resolver happens to throw a `BaseError`: | ||
```ts | ||
import { GraphQLError } from 'graphql'; | ||
import { BaseError } from 'new-error'; | ||
import { ApolloError, ForbiddenError } from 'apollo-server'; | ||
const server = new ApolloServer({ | ||
typeDefs, | ||
resolvers, | ||
formatError: (err: BaseError | ApolloError | GraphQLError | Error) => { | ||
if (err instanceof BaseError) { | ||
// re-map the BaseError into an Apollo error type | ||
switch(err.getCode()) { | ||
case 'PERMISSION_REQUIRED': | ||
return new ForbiddenError(err.message) | ||
default: | ||
return new ApolloError(err.message) | ||
} | ||
} | ||
return err; | ||
}, | ||
}); | ||
``` | ||
Trying to switch for every single code / subcode can be cumbersome. | ||
Instead of using this pattern, do the following so that your conversions can remain in one place: | ||
```ts | ||
import { GraphQLError } from 'graphql'; | ||
import { BaseError, ErrorRegistry } from 'new-error'; | ||
import { ApolloError, ForbiddenError } from 'apollo-server'; | ||
const errors = { | ||
PERMISSION_REQUIRED: { | ||
className: 'PermissionRequiredError', | ||
code: 'PERMISSION_REQUIRED', | ||
// Define a conversion function that is called when BaseError#convert() is called | ||
// error is the BaseError | ||
onConvert: (error) => { | ||
return new ForbiddenError(error.message) | ||
} | ||
}, | ||
AUTH_REQUIRED: { | ||
className: 'AuthRequiredError', | ||
code: 'AUTH_REQUIRED' | ||
// onConvert is not defined, so will return the error itself when convert() is called | ||
} | ||
} | ||
const errorCodes = { | ||
ADMIN_PANEL_RESTRICTED: { | ||
message: 'Access scope required: admin', | ||
// This will override the PERMISSION_REQUIRED / high level error handler when BaseError#convert() is called | ||
onConvert: (error) => { | ||
return new ForbiddenError('Admin required') | ||
} | ||
}, | ||
EDITOR_SECTION_RESTRICTED: { | ||
message: 'Access scope required: editor', | ||
// no onConvert function is defined, so will use the PERMISSION_REQUIRED / high level definition if defined | ||
} | ||
} | ||
const errRegistry = new ErrorRegistry(errors, errorCodes) | ||
const server = new ApolloServer({ | ||
typeDefs, | ||
resolvers, | ||
// errors thrown from the resolvers come here | ||
formatError: (err: BaseError | ApolloError | GraphQLError | Error) => { | ||
// If the error is a BaseError and the error has the onConvert handler defined | ||
if (err instanceof BaseError && err.hasOnConvertDefined()) { | ||
// Convert out to an Apollo error type | ||
return err.convert() | ||
} | ||
return err; | ||
}, | ||
}); | ||
const resolvers = { | ||
Query: { | ||
adminSettings(parent, args, context, info) { | ||
// err.convert() will call onConvert() of ADMIN_PANEL_RESTRICTED (low level defs have higher priority) | ||
throw errRegistry.newError('PERMISSION_REQUIRED', 'ADMIN_PANEL_RESTRICTED') | ||
}, | ||
editorSettings(parent, args, context, info) { | ||
// err.convert() will call onConvert() of PERMISSION_REQUIRED since EDITOR_SECTION_RESTRICTED does not | ||
// have the onConvert defined | ||
throw errRegistry.newError('PERMISSION_REQUIRED', 'EDITOR_SECTION_RESTRICTED') | ||
}, | ||
checkAuth(parent, args, context, info) { | ||
// err.convert() will return itself since onConvert() is not defined for either AUTH_REQUIRED or EDITOR_SECTION_RESTRICTED | ||
throw errRegistry.newError('AUTH_REQUIRED', 'EDITOR_SECTION_RESTRICTED') | ||
}, | ||
checkAuth2(parent, args, context, info) { | ||
// err.convert() will return itself since onConvert() is not defined for either AUTH_REQUIRED | ||
throw errRegistry.newBareError('AUTH_REQUIRED', 'Some error message') | ||
}, | ||
permRequired(parent, args, context, info) { | ||
// err.convert() will call onConvert() of PERMISSION_REQUIRED | ||
throw errRegistry.newBareError('PERMISSION_REQUIRED', 'Some error message') | ||
} | ||
} | ||
} | ||
``` | ||
## Adding metadata | ||
@@ -715,0 +856,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
101442
1263
1169