koa-better-error-handler
A better error-handler for Lad and Koa. Makes ctx.throw
awesome (best used with koa-404-handler)
Index
Features
- Detects Node.js DNS errors (e.g.
ETIMEOUT
and EBADFAMILY
) and sends 408 Client Timeout error - Detects Mongoose errors and sends 408 Client Timeout error
- Detects common programmer mistakes by detecting errors of TypeError, SyntaxError, ReferenceError, RangeError, URIError, and EvalError and yields generic "Internal Server Error" (only applies to production mode)
- Detects Redis errors (e.g. ioredis' MaxRetriesPerRequestError) and sends 408 Client Timeout error
- Uses Boom for making error messages beautiful (see User Friendly Responses below)
- Simply a better error handler (doesn't remove all headers like the built-in one does)
- Doesn't make all status codes 500 (like the built-in Koa error handler does)
- Supports Flash messages and preservation of newly set session object
- Fixes annoying redirect issue where flash messages were lost upon an error being thrown
- Supports HTML Error Lists using
<ul>
for Mongoose validation errors with more than one message - Makes
ctx.throw
beautiful messages (e.g. ctx.throw(404)
will output a beautiful error object :hibiscus:) - Supports
text/html
, application/json
, and text
response types - Supports and recommends use of mongoose-beautiful-unique-validation
Install
npm install --save koa-better-error-handler
Usage
You should probably be using this in combination with koa-404-handler too!
The package exports a function which accepts four arguments (in order):
cookiesKey
- defaults to false
logger
- defaults to console
useCtxLogger
- defaults to true
stringify
- defaults to fast-safe-stringify
(you can also use JSON.stringify
or another option here if preferred)
If you pass a cookiesKey
then support for sessions will be added. You should always set this argument's value if you are using cookies and sessions (e.g. web server).
We recommend to use Cabin for your logger
and also you should use its middleware too, as it will auto-populate ctx.logger
for you to make context-based logs easy.
Note that this package only supports koa-generic-session
, and does not yet support koa-session-store
(see the code in index.js for more insight, pull requests are welcome).
API
No support for sessions, cookies, or flash messaging:
const errorHandler = require('koa-better-error-handler');
const Koa = require('koa');
const Router = require('koa-router');
const koa404Handler = require('koa-404-handler');
const app = new Koa();
app.context.onerror = errorHandler();
app.context.api = true;
app.use(koa404Handler);
const router = new Router();
router.get('/404', ctx => ctx.throw(404));
router.get('/500', ctx => ctx.throw(500));
app.use(router.routes());
app.listen(3000);
console.log('listening on port 3000');
Web App
Built-in support for sessions, cookies, and flash messaging:
const errorHandler = require('koa-better-error-handler');
const Koa = require('koa');
const redis = require('redis');
const RedisStore = require('koa-redis');
const session = require('koa-generic-session');
const flash = require('koa-connect-flash');
const convert = require('koa-convert');
const Router = require('koa-router');
const koa404Handler = require('koa-404-handler');
const app = new Koa();
app.keys = ['foo', 'bar'];
const redisClient = redis.createClient();
redisClient.on('connect', () => app.emit('log', 'info', 'redis connected'));
redisClient.on('error', err => app.emit('error', err));
const redisStore = new RedisStore({
client: redisClient
});
const cookiesKey = 'lad.sid';
app.use(
convert(
session({
key: cookiesKey,
store: redisStore
})
)
);
app.use(convert(flash()));
app.context.onerror = errorHandler(cookiesKey);
app.use(koa404Handler);
const router = new Router();
router.get('/404', ctx => ctx.throw(404));
router.get('/500', ctx => ctx.throw(500));
app.use(router.routes());
app.listen(3000);
console.log('listening on port 3000');
User-Friendly Responses
Example Request:
curl -H "Accept: application/json" http://localhost/some-page-does-not-exist
Example Response:
{
"statusCode": 404,
"error": "Not Found",
"message":"Not Found"
}
Prevent Errors From Being Automatically Translated
As of v3.0.5, you can prevent an error from being automatically translated by setting the error property of no_translate
to have a value of true
:
function middleware(ctx) {
const err = Boom.badRequest('Uh oh!');
err.no_translate = true;
ctx.throw(err);
}
HTML Error Lists
If you specify app.context.api = true
or set ctx.api = true
, and if a Mongoose validation error message occurs that has more than one message (e.g. multiple fields were invalid) – then err.message
will be joined by a comma instead of by <li>
.
Therefore if you DO want your API error messages to return HTML formatted error lists for Mongoose validation, then set app.context.api = false
, ctx.api = false
, or simply make sure to not set them before using this error handler.
try {
await company.validate();
} catch (err) {
ctx.throw(Boom.badRequest(err));
}
With error lists:
{
"statusCode": 400,
"error": "Bad Request",
"message": "<ul class=\"text-left mb-0\"><li>Path `company_logo` is required.</li><li>Gig description must be 100-300 characters.</li></ul>"
}
Without error lists:
{
"statusCode":400,
"error":"Bad Request",
"message":"Path `company_logo` is required., Gig description must be 100-300 characters."
}
API Friendly Messages
By default if ctx.api
is true, then html-to-text will be invoked upon the err.message
, thus converting all the HTML markup into text format.
You can also specify a base URI in the environment variable for rendering as process.env.ERROR_HANDLER_BASE_URL
, e.g. ERROR_HANDLER_BASE_URL=https://example.com
(omit trailing slash), and any HTML links such as <a href="/foo/bar/baz">Click here</a>
will be converted to [Click here][1]
with a [1]
link appended of https://example.com/foo/bar/baz
.
License
MIT © Nick Baugh