Express is a microframework that according to the 2018 Node.js User Survey Report is used by 4 out of 5 back-end and full-stack node.js developers. Thanks to its simplicity, the always-growing range of available middleware, and an active community, the Express user base is still growing.
Arguably, the simplicity of Express is its most significant advantage, but it comes with the cost of a bare-bones API for handling requests, and leaves the rest to the developer. In general, it’s fantastic! We’re developers, and we love to roll out the solutions that we can tailor to meet our requirements.
The two most common tasks for each RESTful application are error handling and payload validation. I like to keep my controllers lean, so for me, middleware is the way to deal with framework-ish features like these two.
The code is available on GitHub: MichalZalecki/express-errors-handling.
Hapi.js is another framework for building web services in Node.js. Hapi.js extracts input validation out of controllers into an intermediate layer between the router and route handlers. Hapi is very modular and its schema validation component is a separate library called Joi. We are going to use Joi with our Express application through Celebrate, an Express middleware for Joi.
Using Celebrate with Joi is a quick and easy way to validate your schema and respond with a well-formatted error message. It also helps keep your controllers lean, so you can assume that data from the request payload is well formatted.
This is how a sample error response may look like:
Some errors are accidental like database constraint violations, a lost connection, a third-party service timeout. While others are expected under precisely defined conditions like token expiration, incorrect input data beyond their format (trying to register with the same email twice), etc.
I aim to unify error handling and make it possible to return errors early in order to avoid deeply nested code and minimize the effort needed to handle exceptions. I like to wrap my route handlers with
enhanceHandler which is a higher order function that formats the output and sets the correct status based on the returned value from the actual route handler.
If you use TypeScript, then start by defining the type for the route handler which allows you to specify the type for params and body of the request.
Depending on the middleware you use, it may be possible to extend Express request and add additional properties.
The essential part of
enhanceHandler is utilizing the Boom library. Boom is a set of factory functions for errors that correspond to HTTP errors. Boom, like Joi, is a library designed to be used with Hapi.js, but doesn’t depend on it.
To better understand each case that is handled by
enhanceHandler, read these tests on GitHub.
enhanceHandler just pass an actual route handler as a parameter and you can now return Boom errors from your controllers.
Whether you like this approach or not, and consider it elegant as I do, it is a matter of preference. The most important thing is flexibility, so you can adjust it to your liking. Hope you will at least enjoy this poem:
Express is awesome, but Hapi is too.
Do not add more code out of the blue.
Combine the best tools and code just the glue.
You can buy me a coffee, I like a cold brew.
Originally published at michalzalecki.com on December 8, 2018.