RocksonZeta / koa-validate

validate koa request params and format request params
https://github.com/RocksonZeta/koa-validate
MIT License
284 stars 32 forks source link

Some helpful validators #6

Open danneu opened 9 years ago

danneu commented 9 years ago

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

RHavar commented 9 years ago

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
danneu commented 9 years ago

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.

RocksonZeta commented 9 years ago

yeah, very powerful! happy Chinese new year!