Conditional requirement dependent on value of othe

2019-08-29 06:32发布

问题:

Conditional requirement dependent on value of other fields in Cerberus has been discussed many times. Usage of dependencies doesn't meet the needs because fields can be unknown when conditions are satisfied. Usage of oneof was recommended but it may be too hard to work when several conditions and dependencies are met. What's the universal solution now?

回答1:

Quick Answer (TL;DR)

  • The "composite validation" approach allows for conditional (context-aware) validation rules.
  • The python cerberus package supports composite validation "out of the box".
  • Composite validation allows for easily-human-readable rules with highly-flexible granularity on triggering conditions.

Detailed Answer

Context

  • python 2.7
  • cerberus validation package

Problem

  • Developer JasperHuangCreator wishes to apply triggering conditions to finely-tuned validation rules.

Solution

  • This approach can be accomplished with composite data validation.
  • Under this use-case, composite validation simply means creating a sequential list of validation rules, such that:
    • Each individual rule operates on a composite data variable
    • Each individual rule specifies a "triggering condition" for when the rule applies
    • Each individual rule produces one of three mutually-exclusive validation outcomes: validation-success, validation-fail, or validation-skipped

Example

Sample documents
aadocuments = []
aadocuments.append(yaml.safe_load('''
    person_fname:         homer
    person_lname:         himpson
    person_age:           33
    prize_caption:        free beer for life
    prize_email:          prizes@abcbooze.com
    prize_category:       alchohol
'''))
aadocuments.append(yaml.safe_load('''
    person_fname:         helen
    person_lname:         himpson
    person_age:           16
    prize_caption:        free ammo for life
    prize_email:          prizes@zzzguns.com
    prize_category:       firearms
  '''))
Sample validation rules
- rule_caption:     check-required-fields
  rule_vpath:       "@"
  validation_schema:
    person_fname:
      type: string
      required: true
    person_lname:
      type: string
      required: true
    person_age:
      type: string
      required: true

- rule_caption:     check-age-range
  rule_vpath:       '@|@.person_age'
  validation_schema:
    person_age:
      "min": 2
      "max": 120

- rule_caption:     check-underage-minor
  rule_vpath:       '[@]|[? @.person_age < `18`]'
  validation_schema:
    prize_category:
      type: string
      allowed: ['pets','toys','candy']
    prize_email:
      type:     string
      regex:    '[\w]+@.*'
  • The code above is a YAML formatted representation of multiple validation rules.
  • The code above specifies the triggering condition through use of the rule_vpath name-value pair.

Rationale

  • This approach can be extended to any arbitrary level of complexity.
  • This approach is easily comprehensible by humans (although the jmespath syntax can be a challenge at first).
  • Any arbitrarily complex set of conditions and constraints can be established using this approach.

Pitfalls

  • The above example uses jmespath syntax to specify rule_vpath, which tells the system when to trigger specific rules, this adds a dependency on jmespath.

See also

  • complete code example on github