koa-validate icon indicating copy to clipboard operation
koa-validate copied to clipboard

Some helpful validators

Open danneu opened this issue 10 years ago • 3 comments

Here are some validators I use in my project that I think should belong to koa-validate.

  1. notMatch - inverse of match

  2. ensure - executes arbitrary expression. if falsey, then error. (koa-validate needs a generic validator for arbitrary expressions)

    this.checkBody('username')
      .notEmpty('Username required')
      .ensureNot(yield db.findUserByUsername(this.request.body.username), 'Username taken')
    
  3. ensureNot (or perhaps refute) - inverse of ensure

Implementations:

// Ensure that a string does not match the supplied regular expression.
Validator.prototype.notMatch = function(reg, tip) {
    if (this.goOn && reg.test(this.value)) {
        this.addError(tip || this.key + ' is bad format.');
    }
    return this;
};

// Ensure that `assertion`, an arbitrary value, is falsey.
Validator.prototype.ensureNot = function(assertion, tip, shouldBail) {
  if (shouldBail) this.goOn = false;
    if (this.goOn && !!assertion) {
        this.addError(tip || this.key + ' failed an assertion.');
    }
    return this;
};

// Ensure that `assertion`, an arbitrary value, is truthy.
Validator.prototype.ensure = function(assertion, tip, shouldBail) {
  if (shouldBail) this.goOn = false;
    if (this.goOn && !assertion) {
        this.addError(tip || this.key + ' failed an assertion.');
    }
    return this;
};

edit: ignore shouldBail

danneu avatar Feb 17 '15 19:02 danneu

I don't particularly see the need for the not api.

I propose two additional functions though: ensureFn :: Takes a function, calls it with the value ensureYield :: Takes a generator, calls it with the value and yields it.

Simple example:

this.checkBody('username').trim().ensureYield(db.userExists)  // yields db.userExists function with username
this.checkBody('address').trim().ensureFn(isValidBitcoinAddress) // calls sync function with the address value

RHavar avatar Feb 18 '15 16:02 RHavar

I don't think ensureYield is general enough at first glance, but I like the idea of piping the value through a function. I'll play with it.

Also, ensureNot is useful because negating a yield is annoying. You have to wrap the whole expression in parens.

this.checkBody('uname').ensure(!(yield db.findUserByUname(this.request.body.uname)))
this.checkBody('uname').ensureNot(yield db.findUserByUname(this.request.body.uname)) // nicer

Sure, not a big deal, but this library already has a precedent for not in its API.

danneu avatar Feb 18 '15 18:02 danneu

yeah, very powerful! happy Chinese new year!

RocksonZeta avatar Feb 26 '15 02:02 RocksonZeta