Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ilabacheuski/243a8cdc6985e00800f219b7181613bb to your computer and use it in GitHub Desktop.
Save ilabacheuski/243a8cdc6985e00800f219b7181613bb to your computer and use it in GitHub Desktop.
Proper error extension in NodeJs based on https://rclayton.silvrback.com/custom-errors-in-node-js
// Boom is a Hapi framework for creating HTTP error responses.
const Boom = require('boom');
const { ResourceNotFoundError, InternalError } = require('../lib/errors');
const findPerson = require('../lib/people/find');
// This would be a common utility function used across handlers
function mapDomainErrorToHttpResponse(error) {
if (error instanceof ResourceNotFoundError) {
return Boom.notFound(error.message, error.data.query);
}
return Boom.badImplementation('Internal Error');
}
server.route({
method: 'GET',
path: '/people/{name}',
async handler(request, reply) {
try {
reply(await findPerson(request.params.name));
} catch (error) {
reply(mapDomainErrorToHttpResponse(error));
}
},
});
class DomainError extends Error {
constructor(message) {
super(message);
// Ensure the name of this error is the same as the class name
this.name = this.constructor.name;
// This clips the constructor invocation from the stack trace.
// It's not absolutely essential, but it does make the stack trace a little nicer.
// @see Node.js reference (bottom)
Error.captureStackTrace(this, this.constructor);
}
}
class ResourceNotFoundError extends DomainError {
constructor(resource, query) {
super(`Resource ${resource} was not found.`);
this.data = { resource, query };
}
}
// I do something like this to wrap errors from other frameworks.
// Correction thanks to @vamsee on Twitter:
// https://twitter.com/lakamsani/status/1035042907890376707
class InternalError extends DomainError {
constructor(error) {
super(error.message);
this.data = { error };
}
}
module.exports = {
ResourceNotFoundError,
InternalError,
};
const { describe, it } = require('mocha');
const { expect } = require('chai');
const { ResourceNotFoundError, InternalError } = require('../lib/errors');
describe('when looking up People', () => {
it('should throw an error if the person cannot be found', async () => {
expect(() => await findPerson('John Doe'))
.to.throw(ResourceNotFoundError);
});
});
const Person = require('../models/person');
const { ResourceNotFoundError, InternalError } = require('../errors');
async function findPerson(name) {
const query = { name };
let person;
try {
person = await Person.find(query);
} catch (error) {
throw new InternalError(error);
}
if (!person) {
throw new ResourceNotFoundError('person', query);
}
return person;
}
module.exports = findPerson;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment