JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 213
  • Score
    100M100P100Q102528F
  • License GPL-2.0

catch errors in your hapi application and display the appropriate error message/page

Package Exports

  • hapi-error

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (hapi-error) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

hapi-error

Intercept errors in your Hapi web app/api and send a useful message to the client.

Build Status codecov.io Code Climate Dependency Status devDependencies Status HitCount

dilbert-404-error

Why?

By default, Hapi does not give people friendly error messages. This plugin lets your app display consistent, friendly & useful error messages in your Hapi apps.

What?

Try it: http://hapi-error.herokuapp.com/register/not+va-lid

Under the hood, Hapi uses Boom to handle errors. These errors are returned as JSON. e.g:

If a URL/Endpoint does not exist a 404 error is returned: hapi-login-404-error

When a person/client attempts to access a "restricted" endpoint without the proper authentication/authorisation a 401 error is shown:

hapi-login-401-error

And if an unknown error occurs on the server, a 500 error is thrown:

localhost-500-error

The hapi-error plugin re-purposes the Boom errors (both the standard Hapi errors and your custom ones) and instead display human-friendly error page:

hapi-error-screens

Note: super basic error page example is just what we came up with in a few minutes, you have full control over what your error page looks like, so use your imagination!

Note: if the client expects a JSON response simply define that in the headers.accept and it will still receive the JSON erro messages.

How?

Error handling in 3 easy steps:

1. Install the plugin from npm:

npm install hapi-error --save

2. Include the plugin in your Hapi project

Includ the plugin when you register your server:

var Hapi = require('hapi');
var Path = require('path');
var Boom = require('boom');
var server = new Hapi.Server();
server.connection({ port: process.env.PORT || 8000 });

server.route([
  {
    method: 'GET',
    path: '/',
    config: {
      handler: function (request, reply) {
        reply('hello world');
      }
    }
  },
  {
    method: 'GET',
    path: '/error',
    config: {
      handler: function (request, reply) {
        reply(new Error('500'));
      }
    }
  }
]);
// this is where we include the hapi-error plugin:
server.register([require('hapi-error'), require('vision')], function (err) {
  if (err) {
    throw err;
  }
  server.views({
    engines: {
      html: require('handlebars') // or Jade or React etc.
    },
    path: Path.resolve(__dirname, './../lib')
  });

  server.start(function (err) {
    if (err) {
      throw err;
    }
    console.log('Visit:', server.info.uri);
  });
});

module.exports = server;

See: /example/server_example.js for simple example

3. Ensure that you have a View called error_template

Note: hapi-error plugin expects you are using Vision (the standard view rendering library for Hapi apps) which allows you to use Handlebars, Jade, React, etc. for your templates.

Your error_template.html (or error_template.ext error_template.jsx) should make use of the 3 variables it will be passed:

  • errorTitle - the error tile generated by Hapi
  • statusCode - *HTTP statusCode sent to the client e.g: 404 (not found)
  • errorMessage - the human-friendly error message

for an example see: /example/error_template.html

That's it!

Want more...? 😉

Custom Error Messages using Hoek.assert

Hoek (a utility library extensively used internally by Hapi) has an assert method which allows you to "throw" errors one line in your code.

Consider the following Hapi route handler code that is fetching data from a generic Database:

function handler (request, reply) {
  db.get('yourkey', function (err, data) {
    if (err) {
      return reply('error_template', { msg: 'A database error occurred'});
    } else {
      return reply('amazing_app_view', {data: data});
    }
  });
}

This can be re-written (simplified) using Hoek.assert

var Hoek = require('hoek'); // require Hoek somewhere in your code

function handler (request, reply) {
  db.get('yourkey', function (err, data) { // much simpler, right?
    Hoek.assert(!err, 'A database error occurred');
    return reply('amazing_app_view', {data: data});
  }); // this has *exactly* the same effect in much less code.
}

Explanation:

Hoek.assert(!err, 'A database error occurred'); Hoek asserts that there is no error. Which means that if there is an error, it will be "thrown" with the message you define in the second argument.

Output:

hoek-a-database-error-occured


Redirecting to another endpoint

Sometimes you don't want to show an error page; instead you want to re-direct to another page. For example, when your route/page requires the person to be authenticated, but they have not supplied a valid session/token to view the route/page.

In this situation the default Hapi behaviour is to return a 401 (unauthorized) error, however this is not very useful to the person using your application.

Redirecting to a specific url is easy with hapi-error:

const redirectConfig = {
    "401": { // if the statusCode is 401 redirect to /login page/endpoint
        "redirect": "/login"
    }
}
server.register([{
    register: require('hapi-error'),
    options: redirectConfig // pass in your redirect configuration in options
  },
  require('vision')], function (err) {
    // etc.
});  

This will redirect the client/browser to the /login endpoint and will append a query parameter with the url the person was trying to visit.

e.g: GET /admin --> 401 unauthorized --> redirect to /login?redirect=/admin

Redirect Example: /example/redirect_server_example.js

Are Query Parmeters Preserved?

Yes! e.g: if the original url is /admin?sort=desc the redirect url will be: /login?redirect=/admin?sort=desc Such that after the person has logged in they will be re-directed back to to /admin?sort=desc as desired.

And it's valid to have multiple question marks in the URL see: http://stackoverflow.com/questions/2924160/is-it-valid-to-have-more-than-one-question-mark-in-a-url so the query is preserved and can be used to send the person to the exact url they requested after they have successfully logged in.


---

Under the Hood / Implementation Detail:

When there is an error in the request/response cycle, the Hapi request Object has useful error object we can use.

Try logging the request.response in one of your Hapi route handlers:

console.log(request.response);

A typical Boom error has the format:

{ [Error: 500]
  isBoom: true,
  isServer: true,
  data: null,
  output:
   { statusCode: 500,
     payload:
      { statusCode: 500,
        error: 'Internal Server Error',
        message: 'An internal server error occurred' },
     headers: {} },
  reformat: [Function] }

The way to intercept this error is with a plugin that gets invoked before the response is returned to the client.

A simple Error Handler Plugin example:

/**
 * register defines our error_handler plugin
 */
exports.register = function error_handler (server, options, next) {
  // onPreResponse intercepts all errors
  server.ext('onPreResponse', function (request, reply) {
    var req = request.response;
    // console.log(request.response);
    if (req.isBoom) { // reply with a slightly more user-friendly error message
      return reply('Sorry, something went wrong, please retrace your steps.')
        .code(req.output.payload.statusCode);
    }
    reply.continue();
  });
  next(); // continue with other plugins
};

exports.register.attributes = {
  pkg: require('../package.json')
};

This is the basic setup for you can customise in your Hapi app. However if you want a "turnkey" plugin you can use in your project with user-friendly HTML error pages (when the client requests HTML) and App/API-friendly JSON error responses (when the client asks for JSON) then see the code in /lib/index.js and usage instructions above!

Background Reading & Research