Surprised by Joi

On numbers not being numbers

Wilfred Springer
East Pole
2 min readMay 10, 2018

--

I love Joi. I won’t explain it here in all detail, but if you — like me — feel like class based type systems don’t cut it, and you’re looking for something small and sensible, something that offers a fluent syntax for defining soft schemas for your objects — please check out Joi.

However, tonight I was stunned to find out about a property of Joi that I’m not all that excited about.

Now, the first two lines make perfect sense. But the third line. What the hell is going on there? Sure, it’s a string that would be a valid number if you’d use parseInt, but that doesn’t make it numeric, doet it?

If you never use Joi.assert, then it wouldn’t be the worst problem:

In this particular case, I’m no longer using Joi.assert, but I’m using Joi.attempt instead. That method not only verifies that the type meets my requirements, but it will also do some last minute modifications, such as filling in default values in case it’s an object with properties with default values. The same happens if you use Joi.validate, which is accepting a callback.

I’m quite relieved that most of the code I wrote in the past is using Joi.validate and not Joi.assert, and knowing all of this, I will never ever use assert again. With Joi.assert, you might think you’re safe if you’re writing code like this:

But as it turns out, you really are not: the first call of sum would throw an error (as expected), and the second call would produce the sum correctly (also as expected), but the third one would return ‘32’ instead, which I find surprising.

I was so surprised by it that I thought it was a bug. So I started digging through the issues and the source code, and then I found that there is a test actually verifying this behavior.

Lesson learned: use Joi.validate or Joi.attempt if you have a forgiving contract, or use the strict modifier if you don’t:

--

--

Wilfred Springer
East Pole

Double bass playing father of three, hacker and soul searcher