Introducing Felicity
We made a thing! And we would love to share it with you!
Felicity is a tool that enhances Node.js APIs that make use of Joi object validation by providing object instantiation, built-in validation, and mock example generation all in one.
The Joi of Validation
Our Node.js microservice architecture is built on top of the Hapi.js framework. I’m not going to take a deep dive into Hapi right now(perhaps a future blog post), but I point it out because we make extensive use of Hapi.js community plugins like Hoek and, more to the point, Joi.
Taken directly from Joi itself
“joi allows you to create blueprints or schemas for JavaScript objects (an object that stores information) to ensure validation of key information”
Joi provides us with the peace of mind that we know exactly what the data coming into our APIs and databases should look like at any given step in the process.
For example, we can define the schema for an incoming request payload and utilize Joi at the Hapi server-level entrypoint to validate the payload before it ever reaches our Node.js request handler:
Another way we utilize Joi is document validation before writing to our Postgres DB:
So What’s The Problem?
With a large microservice architecture, we have several services that may interact with the same data models. This means that we have object instantiation, data validation, and test mock data generation on each service and plugin that must be manually kept up to date as model schemas evolve over time. This opens the doors to inconsistencies and errors originating in hard-coded test mocks/object definitions that may be overlooked when updating. Take this simple and contrived example:
Similar code relating to the same document type may exist on several independent plugins. Say we add a new property or refactor to move names to the document root, we now have to comb through each possibly-relevant repo for every hard-coded line of Javascript to be updated. No thank you. Our solution was to create a single shared plugin that stores our Joi schema for each document type in the stack. Now we can replace the schema definition in our request handler to look like:
That’s cool. Now when we update a Joi schema on our central module, we can just apply the appropriate version bump to each relevant plugin. But that still leaves us with explicit model Object assignments and test mock creation that may or may not be broken. That’s where Felicity comes in.
The Felicity API
Felicity has 2 public methods: entityFor
and example
; let’s take at look at each.
entityFor
The entityFor method accepts a Joi schema and returns a Constructor function. The object instances created by this Constructor are “skeletons” derived from the provided Joi schema. For example:
As a bonus, these object instances created by the Constructors have a sugary method on their prototype chain: validate
. Validate, as you might guess, self-validates the instance against the schema provided to entityFor when the Constructor was created.
The entityFor
method defaults to return null
, 0
, false
, []
, or {}
as determined by key types. More details can be found on the Felicity api documentation.
example
The example method accepts a Joi schema and returns a pseudo-randomly generated Javascript Object based on said Joi schema. For example, using the same schema as above:
By leveraging both Felicity.entityFor and Felicity.example, we have all but eradicated hard-coded definitions in our codebase. It now looks something more like:
Thanks for reading! For more detailed documentation, to ask questions, file issues, or contribute to the project please visit us at the Felicity repo here!
About the Author
Wes Tyler is a Node.js engineer working on the Inbox platform at XO Group, an enthusiastic proponent of open source software, and a huge nerd.Originally published at blog.eng.xogrp.com.