node package manager
Easy collaboration. Discover, share, and reuse code in your team. Create a free org ¬Ľ

koa-better-error-handler

koa-better-error-handler

Slack Status NPM version Build Status Code Coverage Standard JS Style MIT License

A better error-handler for Koa v2+, built for CrocodileJS. Makes ctx.throw beautiful again ‚ú®!

Index

Features

  • 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 ūüĆļ)
  • 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

API

No support for sessions, cookies, or flash messaging:

import errorHandler from 'koa-better-error-handler';
import Koa from 'koa';
import Router from 'koa-router';
 
// initialize our app
const app = new Koa();
 
// override koa's undocumented error handler
app.context.onerror = errorHandler;
 
// specify that this is our api
app.context.api = true;
 
// set up some routes
const router = new Router();
 
// throw an error anywhere you want!
router.get('/404', ctx => ctx.throw(404));
router.get('/500', ctx => ctx.throw(500));
 
// initialize routes on the app
app.use(router.routes());
 
// custom 404 handler since it's not already built in
app.use(async (ctx, next) => {
  try {
    await next();
    if (ctx.status === 404)
      ctx.throw(404);
  } catch (err) {
    ctx.throw(err);
    ctx.app.emit('error', err, ctx);
  }
});
 
// start the server
app.listen(3000);
console.log('listening on port 3000');

Web App

Built-in support for sessions, cookies, and flash messaging:

import errorHandler from 'koa-better-error-handler';
import Koa from 'koa';
import redis from 'redis';
import RedisStore from 'koa-redis';
import session from 'koa-generic-session';
import flash from 'koa-connect-flash';
import convert from 'koa-convert';
import Router from 'koa-router';
 
// initialize our app
const app = new Koa();
 
// define keys used for signing cookies
app.keys = [ 'foo', 'bar' ];
 
// initialize redis store
const redisClient = redis.createClient();
redisClient.on('connect', () => app.emit('log', 'info', 'redis connected'));
redisClient.on('error', err => app.emit('error', err));
 
// define our storage
const redisStore = new RedisStore({
  client: redisClient
});
 
// add sessions to our app
app.use(convert(session({
  store: redisStore
})));
 
// add support for flash messages (e.g. `req.flash('error', 'Oops!')`)
app.use(convert(flash()));
 
// override koa's undocumented error handler
app.context.onerror = errorHandler;
 
// set up some routes
const router = new Router();
 
// throw an error anywhere you want!
router.get('/404', ctx => ctx.throw(404));
router.get('/500', ctx => ctx.throw(500));
 
// initialize routes on the app
app.use(router.routes());
 
// custom 404 handler since it's not already built in
app.use(async (ctx, next) => {
  try {
    await next();
    if (ctx.status === 404)
      ctx.throw(404);
  } catch (err) {
    ctx.throw(err);
    ctx.app.emit('error', err, ctx);
  }
});
 
// start the server
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"
}

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.

With error lists:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "<ul class=\"text-xs-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."
}

License

MIT