
V8n – Fluent validation library for JavaScript - bruno02221
https://github.com/imbrn/v8n
======
anonytrary
It looks over-engineered, complicated and non-intuitive. In 90% of cases,
vanilla business logic will be concise enough. I've used validation modules
like Meteor's check[0] before, and I think that's a good example of how much
surface area a validation library API should have.

[0]
[https://docs.meteor.com/api/check.html](https://docs.meteor.com/api/check.html)

~~~
coldtea
> _It looks over-engineered, complicated and non-intuitive. In 90% of cases,
> vanilla business logic will be concise enough_

Typical top HN comment.

Yeah, very complicated:

    
    
      v8n()
        .number()
        .between(0, 100)
        .even()
        .not.equal(32)
        .test(74); // true

~~~
anonytrary
Apart from the contrived example you cited, why do we need an abstraction for
detailed value checking? Conditional statements are already a thing. Just use
modules and readable function names:

    
    
      // helpers.js
      const isNumber = typeof n === "number" && isFinite(n)
      const isTestScore = n => isNumber(n) && n >= 0 && n <= 100;
     
      // business-logic.js
      const uploadScore = (n, cb) => {
        if (!isTestScore(n)) 
          return cb(new Error("invalid test score"));
        // super contrived, but let's do it
        if (n === 32 || n%2) 
          return cb(new Error("we don't like oddities and we hate 32"));
        // do something with valid test score n
      }
    

IMHO, a validation library should validate types and structure and should know
nothing about the specific values of your data. The values are likely relevant
to your business logic and should be handled there for finer-grained error
handling, logical branching, etc.

~~~
coldtea
> _Apart from the contrived example you cited, why do we need an abstraction
> for detailed value checking?_

We don't "need" an abstraction for anything, in the sense that we need oxygen.
We _want_ abstractions, and they usually make us more productive, which is
something different.

Case in point the above horribly noisy procedural code for something that this
library abstracts into neat, purpose specific, calls.

I think the code answers its own question.

~~~
anonytrary
What happens when you want to know why your value failed the test? Easy, just
break up your chained v8n call into smaller chunks and handle each one
individually -- but wait, now we're back to the same procedural code we
started with!

Never fear; the devs implement hooks that let you do something when a certain
part of the chain fails. Cool -- but now all of our code is tightly coupled to
the structure imposed by the hook syntax.

Okay, better solution: how about an array of "reasons" is returned that tells
you why your test failed. Now we've got to tell v8n what reason text we want
(if any) for each part of the chain that fails, so we're back to having to
declare a bunch of messages somewhere, which is what people already do.

Yeah, we want abstraction, but we want the _right_ abstraction. Premature
generalization/abstraction is a common pitfall among even the best developers.
This library could be useful for some cases, but I'm not convinced it _should_
be used for everything it _can_ be used for.

Is this 32?

~~~
coldtea
> _What happens when you want to know why your value failed the test? Easy,
> just break up your chained v8n call into smaller chunks and handle each one
> individually_

You seem confused. You just need to substitute .check() instead of .test() and
you get a ValidationException if your value doesn't validate that tells you
exactly which rule failed.

And that's just the two two basic result values (true/false on validation or
Exception) that the devs implemented.

Nothing in this kind of design prevents returning any kind of detailed error
or array of errors etc if one wants too.

> _kay, better solution: how about an array of "reasons" is returned that
> tells you why your test failed. Now we've got to tell v8n what reason text
> we want (if any) for each part of the chain that fails, so we're back to
> having to declare a bunch of messages somewhere_

Woooosh. The validation library is not about not having to write our own
messages for the user. It's about not writing our own tests when the dozens of
built-in ones are just as good. Plus they give structure that's better than a
bunch of if/elses.

> _Yeah, we want abstraction, but we want the right abstraction. Premature
> generalization /abstraction is a common pitfall among even the best
> developers._

Premature generalization/abstraction? You might be seeing this pattern for the
first time, but this library follows a very standard pattern for validation
libraries, that has been with us, and used in tons of production code, for
over 2 decades. Apache Commons did that since ages. Even the fluent interface
take on such libs is nothing new.

------
danlugo92
For validating entire objects:
[https://github.com/hapijs/joi](https://github.com/hapijs/joi)

~~~
Klathmon
I've also used AJV before.

[https://github.com/epoberezkin/ajv](https://github.com/epoberezkin/ajv)

~~~
root_axis
My company migrated everything away from joi in favor of AJV. Joi isn't
serialisable and the maintainers are hostile to the idea of adding that
capability. There are some 3rd party extensions to add serialization support,
but they are not feature-complete. I also find the declarative nature of JSON
Schema preferable to joi's semi-imperative API which is occasionally quite
difficult to debug.

------
devman2
hmm, did a naive quick speed test. Man, this lib is extremely expensive... 500
times slower than doing the same comparison in vanilla JS

    
    
      const num= 74;
      ( (typeof num === 'number') && (num > -1 && num < 101) && (num % 2 === 0) && (num !== 32) )
    

compared to their first example:

    
    
      v8n().number().between(0, 100).even().not.equal(32).test(74);

~~~
anonytrary
Welcome to your average Javascript package -- does something trivial in the
most over-engineered and expensive way imaginable.

------
partycoder
This should be a Show HN.

I read the code, and I do not think this library is suitable for real-world
use.

Consider `makeTestType`
([https://github.com/imbrn/v8n/blob/master/src/v8n.js#L973-L98...](https://github.com/imbrn/v8n/blob/master/src/v8n.js#L973-L981)):

    
    
        return () => value => {
          return (
            typeof value === type ||
            (value === null && type === "null") ||
            (Array.isArray(value) && type === "array")
          );
        };
    

This means that null and "null" (as a string) are now numbers.

    
    
        v8n().number().test("null") // true
    

It also means that an array of numbers is a number... something that is
counterintuitive for the user of the library.

In addition to that, most of the time you want to deal with finite numbers. A
validation library should have an API that reflects this, but this is not the
case for v8n.

~~~
twiss
No, it doesn't mean that. You can try it out here:
[https://runkit.com/embed/ev53mh0z4nxt](https://runkit.com/embed/ev53mh0z4nxt)

`makeTestType("null")()(null)` return true, but
`makeTestType("number")()(null)` doesn't. The signature of `makeTestType` is
`type: String => () => value: Any => Boolean`.

------
Ciantic
Great, but this can be done with type-safety too. See this
[https://github.com/pelotom/runtypes](https://github.com/pelotom/runtypes) \--
it isn't purely meant for validation, but not much is needed to use it for it.

------
lgessler
It seems like the main purpose of the exception-based validation function
`check` is to provide an explanation for failures. Could this have also been
achieved by returning an error object with the same information in it? This is
what clojure.spec does:
[https://clojure.github.io/spec.alpha/clojure.spec.alpha-
api....](https://clojure.github.io/spec.alpha/clojure.spec.alpha-
api.html#clojure.spec.alpha/explain-data)

~~~
LinaLauneBaer
Sometimes you want to do a lot of other stuff in the same scope and simply
bail out on any error without having to check every return value.

------
sandstrom
Another interesting validation library (in early alpha/beta stage, though) is
cross-check:

[https://github.com/cross-check/cross-
check/tree/master/packa...](https://github.com/cross-check/cross-
check/tree/master/packages/schema)

It supports 'draft data', which can be used by auto-safe functionality or
similar.

------
sbr464
I didn't see promises mentioned, curious how those would be handled if
provided a custom function that is a promise?

------
ahallock
I've been interested in clojure spec for a while, but I'm stuck in JS land.
There's a port called js.spec, and I think it works really well for
validation.

------
proneb1rd
First I thought that was about some extension for V8. Naming things is hard.
:/

------
mabynogy
I won't use it but it looks good. The readme is very clear.

