1
\$\begingroup\$

I'm writing an application that is meant to validate data. The data comes in the form of JSON and I'm using JSON Schema to validate the structure and some of the logic along with functions to validate more of the core business logic.

I need to be able to track what has failed the validation and pass that off to another application to be dealt with. So far I have about 50 odd validation tests, 25 core business logic tests and another 25 or so that are just checking and reporting the errors from the JSON schema validation.

I'm using Node.js 9.4 and ES6.

I think i've created something kind of terrible so far and could do with some advice on a better way of implementing this:

Rule.js

class Rule {
  constructor(release) {
    this.release = release;
    this.errors = [];
    this.validator = false;
  }

  static registerRule(rule) {
    Object.assign(this.prototype, rule);
  }

  static registerValidator(validator) {
    if (!this.validator) {
      this.validator = true;
      Object.assign(this.prototype, validator);
    } else {
      throw {
        toString: function() {
          return 'validator already assigned';
        }
      };
    }
  }

  _recordError(error, options) {
    this.errors.push({
      release_id: this.release.id,
      rule: error,
      options: options,
    });
  }
}

module.exports = Rule;

I'll then have a validation rule, which might be either a check to find out the error from my json schema validator, or a business logic style rule:

NoExclusive.js

module.exports = {
  exclusive: function(errors) {
    errors.some( (error) => {
      if (error.parentSchema.regexp === '/^((?!exclusive).)*$/i') {
        this._recordError('NOEXCLUSIVE');
      }
    });
  }
};

I create a validator

Validate.js

module.exports = {
  validate: function(errors) {
    this.exclusive(errors);
    // ... Other rules too

    return this.errors;
  }
};

I then have an index page where I add the validation rules to the Rule object as well as the validator.

index.js

const Rule = require('../../Rule');

Rule.registerRule(require('./NoExclusive'));
// ... Other rules
Rule.registerValidator(require('./Validate'));

module.exports = Rule;

I'll then instantiate it later on in the application, where I pass it the data (release in the constructor).

I don't feel that this is the best way of doing this. I kind of wanted to be able to have 2 different Rule Objects, one for business logic and the other for JSON schema errors, but i've boxed myself in with this method. Is there a better way, or a design pattern I can leverage for this?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.