-
Notifications
You must be signed in to change notification settings - Fork 0
dos and donts
If you find yourself writing increasingly complex (and possibly convoluted) error handlers, consider refactoring the code instead. A function throwing all sorts of different errors is a pretty strong indication that it does too much.
Most of the error handlers of this library don't change the semantics of the wrapped method. The
notable exceptions to this are SIDE_EFFECT
and RECOVER
. It is recommended to use those sparingly in order to avoid surprises and unexpected behavior.
Using exceptions for control flow is considered an anti-pattern. An exception should, by definition, not be something you encounter during normal operation of your app.
As a slightly contrived (and convoluted) example - loosely based on pg-promise - you should avoid doing this:
class Repository {
// ...
@HandleError({
action: HandlerAction.MAP,
scope: QueryResultError,
callback: (_, id) => new UserNotFoundError(id)
})
public async getUser(id: number): Promise<User> {
// 'one' throws if the query returns a result set with not exactly one row.
return this.db.one('user', { id })
}
@HandleError({
action: HandlerAction.RECOVER,
scope: UserNotFoundError,
callback: () => null
})
public async findUser(id: number): Promise<User | null> {
return this.getUser(id)
}
}
Instead, do this:
class Repository {
// ...
public async findUser(id: number): Promise<User | null> {
// 'oneOrNone' throws if the query returns a result set with more than one row.
return this.db.oneOrNone('user', { id })
}
public async getUser(id: number): Promise<User> {
const maybeUser = await this.findUser(id)
if (maybeUser === null) {
throw new UserNotFound(id)
}
return maybeUser
}
}