In this post I will briefly demonstrate the ClassyHash gem, which is a fast data validation gem written in pure Ruby. I recently released version 0.2.0 of ClassyHash, with some cool PRs integrated and quite a few new features. Here’s a quick example:
1 2 3 4 5 6 7 8 9
Continue reading to learn about ClassyHash’s history and see a basic ClassyHash validation tutorial.
When to use ClassyHash
ClassyHash is versatile, thanks to its speed. You can use it as your sole validation mechanism, or as a quick sanity check before passing data to something like ActiveRecord. If you are writing an API or message queue that needs to process a lot of requests, ClassyHash can be your front-line defense against accidentally malformed requests and developer mistakes.
Since ClassyHash schemas are plain Ruby
Hashes, it’s easy to create a private
gem to share schemas across internal codebases. That way you can validate API
calls and queued messages against the same schema in all of your projects.
The ClassyHash origin story
At my previous employer I was responsible for integrating an e-commerce site running Solidus with the Oracle E-business Suite used by the rest of the company. One of the tools I created to help with this process is the ClassyHash gem.
The e-commerce site needed to pass a lot of order data into the Oracle system for processing and fulfillment, and shipment updates needed to be returned to the e-commerce site. To make it easier to develop the internal APIs and to prevent accidentally mismatched data formats, I wrote the ClassyHash gem.
Validation needed to be fast, so it could be used everywhere without worrying
about overhead. ClassyHash achieves its speed by using built-in Ruby data
structures and avoiding memory allocation where possible. Schemas are written
in a Ruby DSL, with
Arrays to describe
Validation also needed to be reliable, so ClassyHash has 100% test coverage.
To demonstrate writing a ClassyHash schema, we’ll extend the hypothetical example above to support mixed user and repo queries, then write a schema for replies to the extended API. You can find complete documentation of the ClassyHash DSL in the ClassyHash README.
This API design is exaggerated a bit to show off some ClassyHash features.
First let’s define separate schemas for User and Repo queries, the two object
types that can be queried in our extended API. To write a basic ClassyHash
schema for a
Hash, we create a
Hash containing the keys we expect, with the
Class of the values we expect.
1 2 3 4 5
Next, we’ll define a schema for an individual query. We’ll use the
multiple-choice feature of ClassyHash, represented as an
Array of basic
constraints, to allow querying either a User or a Repo. Also new here is the
TrueClass to represent either
true, we’ll add more data to our reply (defined below).
1 2 3 4 5 6 7
Finally, we will allow an array of queries to be made. We will use a ClassyHash generator to create an array length constraint, so API users can’t make too many queries at once.
1 2 3 4
With our schema complete, let’s suppose we received a JSON request to our API
and we want to validate it. We will pass
true for the
which will treat any extra keys as an error.
1 2 3 4 5
It can also be useful to validate responses before sending them, to help catch implementation bugs. We’ll follow the same inside-out design process as our request schema to create a reply schema, starting with the definitions for our base objects.
This schema introduces the
:optional flag on a multiple-choice constraint.
We’ll mark the keys that only get sent for
:verbose queries as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Since we allow multiple queries, we also need to allow multiple replies.
1 2 3 4
Validation is the same as the request schema.
1 2 3 4 5 6 7
Invalid replies will raise an error.
1 2 3 4 5 6 7 8 9 10
So that’s how you write validation schemas in the ClassyHash DSL. ClassyHash is
packaged as a Ruby Gem, distributed through rubygems.org. You can simply add
ClassyHash to your