@restify-ts/errors v1.0.0-beta.1
@restify-ts/errors
A collection of HTTP and REST Error constructors.
The constructors can be used to new up Error objects with default status codes set.
The module ships with the following HttpErrors:
- 400 BadRequestError
- 401 UnauthorizedError
- 402 PaymentRequiredError
- 403 ForbiddenError
- 404 NotFoundError
- 405 MethodNotAllowedError
- 406 NotAcceptableError
- 407 ProxyAuthenticationRequiredError
- 408 RequestTimeoutError
- 409 ConflictError
- 410 GoneError
- 411 LengthRequiredError
- 412 PreconditionFailedError
- 413 RequestEntityTooLargeError
- 414 RequesturiTooLargeError
- 415 UnsupportedMediaTypeError
- 416 RangeNotSatisfiableError
- 416 RequestedRangeNotSatisfiableError
- 417 ExpectationFailedError
- 418 ImATeapotError
- 422 UnprocessableEntityError
- 423 LockedError
- 424 FailedDependencyError
- 425 UnorderedCollectionError
- 426 UpgradeRequiredError
- 428 PreconditionRequiredError
- 429 TooManyRequestsError
- 431 RequestHeaderFieldsTooLargeError
- 500 InternalServerError
- 501 NotImplementedError
- 502 BadGatewayError
- 503 ServiceUnavailableError
- 504 GatewayTimeoutError
- 505 HttpVersionNotSupportedError
- 506 VariantAlsoNegotiatesError
- 507 InsufficientStorageError
- 509 BandwidthLimitExceededError
- 510 NotExtendedError
- 511 NetworkAuthenticationRequiredError
and the following RestErrors:
- 400 BadDigestError
- 405 BadMethodError
- 500 InternalError
- 409 InvalidArgumentError
- 400 InvalidContentError
- 401 InvalidCredentialsError
- 400 InvalidHeaderError
- 400 InvalidVersionError
- 409 MissingParameterError
- 403 NotAuthorizedError
- 412 PreconditionFailedError
- 400 RequestExpiredError
- 429 RequestThrottledError
- 404 ResourceNotFoundError
- 406 WrongAcceptError
Some of the status codes overlap, since applications can choose the most applicable error type and status code for a given scenario. Should your given scenario require something more customized, the Error objects can be customized with an options object.
Getting Started
Install the module with: npm install @restify-ts/errors
Usage
Creating Errors
With @restify-ts/core
you can use @restify-ts/errors
like this:
import { Server, Request, Response } from '@restify-ts/core';
import { BadRequestError } from '@restify-ts/errors';
class Controller
{
run(req: Request, res: Response)
{
if( !req.query.foo )
{
return res.send( new BadRequestError );
}
res.send(200, 'ok!');
}
}
const server = new Server;
server.get('/foo', Controller, 'run');
Checking Error types
You can easily do instance checks against the Error objects:
class Controller
{
redirectIfErr(req: Request, res: Response)
{
const err = req.data.error;
if(err)
{
if(err instanceof InternalServerError)
{
res.send(err);
}
else if(err instanceof NotFoundError)
{
res.redirect('/notfound');
}
}
}
}
Rendering Errors
All Error objects in this module are created with a body
property. restify
supports 'rendering' Errors as a response using this property. You can pass
Errors to res.send
and the error will be rendered out as JSON:
class Controller
{
render(req: Request, res: Response)
{
res.send( new errors.InternalServerError );
}
}
@restify-ts/core
will render an application/json response with an http 500 { message: '' }
Customizing Errors
If you'd like to change the status code or message of a built-in Error, you can pass an options object to the constructor:
class Controller
{
render(req: Request, res: Response)
{
const myErr = new errors.InvalidVersionError
({
statusCode: 409,
message: 'Version not supported with current query params'
});
res.send(myErr);
}
}
Even though InvalidVersionError has a built-in status code of 400, it has been customized with a 409 status code. Restify-ts will now render an application/json response with an http 409:
{
message: 'Version not supported with current query params'
}
Passing in prior errors (causes)
Like WError, all constructors
accept an Error
object as the first argument to build rich Error objects and
stack traces. Assume a previous file lookup failed and an error was passed on:
class Controller
{
wrapError(req, res)
{
if(req.error)
{
const myErr = new errors.InternalServerError(req.error, 'bad times!');
return res.send(myErr);
}
}
}
This will allow Error objects to maintain context from previous errors, giving you full visibility into what caused an underlying issue:
console.log(myErr.message);
// => 'bad times!'
console.log(myErr.toString());
// => InternalServerError: bad times!; caused by Error: file lookup failed!
// if you're using Bunyan, you'll get rich stack traces:
bunyanLogger.info(myErr);
InternalServerError: bad times!
at Object.<anonymous> (/Users/restify/test.js:30:16)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
Caused by: Error: file lookup failed!
at Object.<anonymous> (/Users/restify/test.js:29:15)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
Bunyan support
Since errors created via @restify-ts/errors inherit from VError, you'll get out of
the box support via bunyan's standard serializers. If you are using the
context
property, you can use the serializer shipped with @restify-ts/errors:
import * as bunyan from 'bunyan';
import * as restifyErrors from '@restify-ts/errors';
const log = bunyan.createLogger
({
name: 'myLogger',
serializers: { err: restifyErrors.bunyanSerializer }
});
const err = new restifyErrors.InternalServerError
({
message: 'cannot service this request!',
context: { foo: 'bar', bar: 1 }
});
log.error(err, 'oh noes');
[2016-08-31T22:27:13.117Z] ERROR: log/51633 on laptop: oh noes (err.code=InternalServer)
InternalServerError: cannot service this request! (foo="bar", bar=1)
at Object.<anonymous> (/restify/test.js:11:11)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
You can, of course, combine this with the standard set of serializers that bunyan ships with.
VError support
This serializer also comes with support for VError's new info
property:
const err = new VError
(
{
name: 'BoomError',
info: { foo: 'bar', baz: 1 }
}
,'something bad happened!'
);
log.error(err, 'oh noes');
[2016-08-31T22:21:35.900Z] ERROR: log/50874 on laptop: oh noes
BoomError: something bad happened! (foo="bar", baz=1)
at Object.<anonymous> (/restify/test.js:11:11)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
VError's MultiError is also supported:
const underlyingErr = new Error('boom');
const multiErr = new verror.MultiError
([
new Error('boom')
,new restifyErrors.InternalServerError
(
underlyingErr
,{
message: 'wrapped',
context: { foo: 'bar', baz: 1 }
}
)
]);
log.error(multiErr, 'oh noes');
[2016-08-31T22:48:43.244Z] ERROR: logger/55311 on laptop: oh noes
MultiError 1 of 2: Error: boom
at Object.<anonymous> (/restify/test.js:16:5)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
MultiError 2 of 2: InternalServerError: wrapped (foo="bar", baz=1)
at Object.<anonymous> (/restify/test.js:17:5)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
Caused by: Error: boom
at Object.<anonymous> (/restify/test.js:14:21)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
For more information about building rich errors, check out VError.
Subclassing Errors
You can also create your own Error subclasses by using the provided
makeConstructor()
method. Making a new subclass will add the constructor to
the existing exports object:
errors.makeConstructor('ExecutionError', {
statusCode: 406,
failureType: 'motion'
});
const myErr = new errors.ExecutionError('bad joystick input!');
console.log(myErr instanceof ExecutionError);
// => true
console.log(myErr.message);
// => 'ExecutionError: bad joystick input!'
console.log(myErr.failureType);
// => 'motion'
console.log(myErr.statusCode);
// => 406
console.log(myErr.stack);
ExecutionError: bad joystick input!
at Object.<anonymous> (/Users/restify/test.js:30:16)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
Custom errors are subclassed from RestError, so you get all the built-in goodness of HttpError/RestError. The constructor returned to you accepts all the same signatures accepted by HttpError/RestError.
API
All error constructors are variadic and accept the following signatures:
constructor(message ?: string, ...sprintfArgs: any[]);
constructor(cause: Error, message ?: string, ...sprintfArgs: any[]);
constructor(options: HttpErrorOptions, message ?: string, ...sprintfArgs: any[]);
All VError and WError signatures are also supported, including extsprintf.
You can pass in a message like a regular error:
message
{String} - an error message
Or pass in an options object for more customization:
options.message
{String} - an error message stringoptions.statusCode
{Number} - an http status codeoptions.restCode
{Number} - a description code for your Error. This is used by restify to render an error when it is directly passed tores.send()
. By default, it is the name of your error constructor (e.g., the restCode for a BadDigestError is BadDigest).options.context
{Object} - object of contextual properties relevant to the creation of the error, i.e., the url of a failed http request
In all signatures, you can optionally pass in an Error as the first argument, which will cause WError to use it as a prior cause:
priorErr
{Error} - an Error object
Returns: {Error} an Error object
IMPORTANT: If a printf style signature is used, the Error message will
prefer that over options.message
.
makeConstructor(name , defaults)
Creates a custom Error constructor, adds it to the existing exports object.
name
{String} - the name of your Errordefaults
{Object} - an object of default values that will added to the prototype. It is possible to override the defaulttoString()
andtoJSON()
methods.
Returns: {void}
makeErrFromCode(name , args...)
Create an Error object using an http status code. This uses http
module's
STATUS_CODES
to do the status code lookup. Thus, this convenience method
is useful only for creating HttpErrors, and not RestErrors.
statusCode
{Number} - an http status codeargs
- arguments to be passed on to the constructor
Returns: {Object} an Error object
License
- Copyright (c) 2015 Alex Liu
- Copyright (c) 2017 Костя Третяк
Licensed under the MIT license.
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago