poppinss / indicative

Indicative is a simple yet powerful data validator for Node.js and browsers. It makes it so simple to write async validations on nested set of data.
https://indicative.adonisjs.com/
MIT License
417 stars 52 forks source link

Is their a way to throw "not allowed" validation errors? #212

Closed ElMatella closed 5 years ago

ElMatella commented 5 years ago

Hi, thank you for this great package!

Is their a way to throw "not allowed" validation errors if some key is not present in the validation rules?

Example:

const rules = {
    'foo': 'required|string'
}

const data = {
    foo: 'olas',
    bar: 'lol'
}

await indicative.validateAll(data, rules)

That would throw "bar is not allowed". I know that this looks more like Schema validation than data validation. Is this something achievable with indicative or should I use another library on top like joi?

Anyways I can't find such an option in the documentation..

Thank you and have a nice day :)

AndrewJo commented 5 years ago

I think the lack of rule dictates that you don't intend on validating on that attribute. If you know attributes you want to blacklist ahead of time, you can specify conflicting rules which will never validate:

const rules = {
  'bar': 'required_without_any:foo|required_with_any:foo'
}

I only use Indicative for basic input data validation. Things like attribute whitelisting is done at a controller level (or middleware level). In fact, I do something like this (this is an AdonisJs example but feel free to adapt it to whatever framework you're using):

const { isFunction } = require('lodash')

/**
 * BaseController is an abstract class that requires implementing class to override
 * permitAttributes.
 */
class BaseController {
  constructor () {
    if (this.permitAttributes === undefined) {
      throw new TypeError('Must override permitAttributes property')
    }
  }

  /**
   * Sanitizes incoming request body.
   * @param {Request} request
   */
  sanitize (requestOrBody) {
    const body = isFunction(requestOrBody.all) ? requestOrBody.all() : requestOrBody
    return pick(body, this.permitAttributes)
  }
}

module.exports = BaseController

You can then use it in your controller like so:

class MyController extends BaseController {
  get permitAttributes () {
    // Only allow 'foo' attribute
    return ['foo']
  }

  async update ({ request, response }) {
    const body = this.sanitize(request)

    // ... do something with the request body. The body variable will only contain foo attribute.

  }
}

This is a very similar approach to how Rails framework utilizes the strong parameters convention to whitelist permitted attributes before mass assigning request body attributes to a model.

RomainLanz commented 5 years ago

Hey @ElMatella, @AndrewJo! 👋

In fact, it's planned to add in a future version of the Adonis Validation Provider a way to remove key that aren't validated, this will probably add a setting in indicative itself to do it.

In the meanwhile, you can use the workaround provided by @AndrewJo.

ElMatella commented 5 years ago

Hi, thanks a lot for both of your responses! I close the issue then.