https://github.com/jeffijoe/fejl
Error-making utility for Node apps.
https://github.com/jeffijoe/fejl
error-handling nodejs typescript typescript-library
Last synced: over 1 year ago
JSON representation
Error-making utility for Node apps.
- Host: GitHub
- URL: https://github.com/jeffijoe/fejl
- Owner: jeffijoe
- License: mit
- Created: 2017-09-26T06:01:02.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2025-01-16T19:33:14.000Z (over 1 year ago)
- Last Synced: 2025-03-31T16:14:59.995Z (over 1 year ago)
- Topics: error-handling, nodejs, typescript, typescript-library
- Language: TypeScript
- Homepage:
- Size: 1.12 MB
- Stars: 34
- Watchers: 2
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Fejl
Error utility for Node apps, written in [TypeScript](https://www.typescriptlang.org).
[](https://www.npmjs.com/package/fejl)
[](https://david-dm.org/jeffijoe/fejl)
[](https://david-dm.org/jeffijoe/fejl)
[](https://travis-ci.org/jeffijoe/fejl)
[](https://coveralls.io/github/jeffijoe/fejl)
[](https://www.npmjs.com/package/fejl)
[](https://github.com/jeffijoe/fejl/blob/master/LICENSE.md)
[](http://typescriptlang.org)
# Install
With `npm`:
```
npm install fejl
```
Or with `yarn`
```
yarn add fejl
```
# Usage
Fejl exports a general-purpose `MakeErrorClass` function which lets you build an error class with a default message and attributes.
```js
import { MakeErrorClass } from 'fejl'
class InvalidConfigError extends MakeErrorClass(
// Default message
'The configuration file is invalid',
// Default props
{ infoUrl: 'https://example.com/error-info' }
) {}
// Using defaults
try {
throw new InvalidConfigError()
} catch (err) {
console.log(err.name) // 'InvalidConfigError'
console.log(err.message) // 'The configuration file is invalid'
console.log(err.infoUrl) // 'https://example.com/error-info'
console.log(err.stack) //
console.log(err instanceof InvalidConfigErrror) // true
}
// Overriding defaults
try {
throw new InvalidConfigError('The config file was not found', {
infoUrl: 'https://example.com/other-err',
code: 123
})
} catch (err) {
console.log(err.message) // 'The configuration file is invalid'
console.log(err.infoUrl) // 'https://example.com/other-err'
console.log(err.code) // 123
}
```
Additionally, for your convenience, a few common HTTP errors have been defined which set a `statusCode`, see [`http.ts`](/src/http.ts) for which ones. If you think I missed some important ones, feel free to open an issue/PR.
# Additional awesomeness
Fejl wants to get rid of excessive boilerplate in conditionally throwing errors. Therefore, each error class created with `MakeErrorClass` comes with the following **static functions**:
## `assert(data: T, message: string): void`
Let's create ourselves an error class to play with.
```js
import { MakeErrorClass } from 'fejl'
// Defaults are optional
class InvalidInput extends MakeErrorClass() {}
```
Let's see how `InvalidInput.assert` can make our lives easier.
**Ugly:**
```js
function someFunc(value) {
if (!value) {
throw new InvalidInput('Value is required.')
}
}
```
**Sexy:**
```js
function someFunc(value) {
InvalidInput.assert(value, 'Value is required')
}
```
## `makeAssert(message: string): Asserter`
Sometimes an error can be thrown in multiple places, but the message would be the same. `makeAssert` will generate an asserter function that can be reused, and which is also really useful when working with `Promise`s.
`MyError.makeAssert('Nope')` is essentially sugar for `(data) => MyError.assert(data, 'Nope')`.
For this example, we want to use one of the built-in HTTP errors.
```js
import { NotFound } from 'fejl'
```
**Ugly:**
```js
async function getTaskForUser(userId, taskId) {
const user = await getUserAsync(userId)
if (!user) {
throw new NotFound('User not found')
}
const task = await getTaskAsync(userId, taskId)
if (!task) {
throw new NotFound('Task not found')
}
return task
}
```
**Sexy:**
```js
async function getTaskForUser(userId, taskId) {
const user = await getUserAsync(userId)
NotFound.assert(user, 'User not found')
const task = await getTaskAsync(userId, taskId)
NotFound.assert(task, 'Task not found')
return task
}
```
**Sexier:**
```js
async function getTaskForUser(userId, taskId) {
const user = await getUserAsync(userId).then(
NotFound.makeAssert('User not found')
)
const task = await getTaskAsync(userId, taskId).then(
NotFound.makeAssert('Task not found')
)
return task
}
```
## `retry(fn: () => Promise, opts?: RetryOpts): Promise`
Keeps running the inner `fn` until it _does not_ throw errors of the type that `.retry` was called on.
```ts
const eventuallyExists = await NotFound.retry(
async () => {
const report = await getSomeReportThatMayOrMayNotExistAtSomePointInTime().then(
NotFound.makeAssert('The report was not found')
)
return report
},
{
// These are available options with their defaults.
tries: 10, // How many times to try
factor: 2, // The exponential backoff factor to use.
minTimeout: 1000, // The minimum amount of time to wait between retries in ms
maxTimeout: Infinity // The nax amount of time to wait between retries in ms
}
)
```
You can import the `retry` top-level utilty that is not bound to any particular error.
The API is similar to `promise-retry`.
```ts
import { retry } from 'fejl'
const result = await retry(
async (again, attempt) => {
return getSomeReportThatMayOrMayNotExistAtSomePointInTime()
.then(NotFound.makeAssert('The report was not found'))
.catch(err => {
if (err instanceof NotFound) {
// Only retry on NotFound errors.
throw again(err)
}
throw err
})
},
{
// options...
tries: 10
}
)
```
## `ignore(valueToReturnOnCatch: T): IgnoreFunc`
Makes an ignore function for this error class that will return the specified value if caught.
Otherwise throws the original error.
```ts
// If a `NotFound` is thrown, returns 99.95
const price = await getSomeRemotePriceThatMayOrMayNotExist().catch(
NotFound.ignore(99.95)
)
// Using try-catch
try {
return getSomeRemotePriceThatMayOrMayNotExist()
} catch (err) {
return NotFound.ignore(99.95)(err)
}
```
You can check multiple errors at once by using the top-level higher-order ignore utility.
```ts
import { ignore } from 'fejl'
// If a `NotFound` or `Forbidden` is thrown, returns 99.95
const price = await getSomeRemotePriceThatMayOrMayNotExist().catch(
// Note the double-invocation
ignore(NotFound, Forbidden)(99.95)
)
```
## `getHttpErrorConstructorForStatusCode(statusCode: number): HttpErrorConstructor`
Given a status code, returns the proper error to throw.
```ts
import { getHttpErrorConstructorForStatusCode, BadRequest } from 'fejl'
const ErrorCtor = getHttpErrorConstructorForStatusCode(400)
ErrorCtor === BadRequest // true
```
# What's in a name?
"fejl" _[fɑjl]_ is danish for _"error"_, and when pronounced in English also sounds like the word "fail".
# Author
Jeff Hansen — [@Jeffijoe](https://twitter.com/Jeffijoe)