I'm using LGTM to validate REST API inputs and found myself repeating the same validations over and over. For example, all my GET endpoints need to validate LIMIT and OFFSET so I have something like this:
var getUsersValidator = LGTM.validator()
// Validate limit
.validates('limit')
.optional()
.integer(validationJsonError.serialize({
detail:'The "limit" value must be an integer',
errorAttribute: 'limit'
}))
.minValue(0, validationJsonError.serialize({
detail:'The minimum value for the "limit" is 0',
errorAttribute: 'limit'
}))
// Validate 'offset'
.validates('offset')
.optional()
.integer(validationJsonError.serialize({
detail:'The "offset" value must be an integer',
errorAttribute: 'offset'
}))
.minValue(0, validationJsonError.serialize({
detail: 'The minimum value for the offset is 0',
errorAttribute: 'offset'
}))
// Additional validations
.build();
var getPostsValidator = LGTM.validator()
// Repeat above for limit and offset
Note that instead of returning string messages I return a JSON API error object (http://jsonapi.org/format/#errors). I know in all the examples you return a string but returning the object and then formatting all the JSON API errors into a single JSON API compliant response works really well (might be worth mentioning in the docs that you can return a custom object).
What I'd like to be able to do is compose together different validators to run together as a single compound validation or be able to easily construct a new compound validator from primitive validators (a validator that validates one attribute or property). I'm having a hard time figuring out a clean way to do this.
var limit = LGTM.validator()
.validates('limit')
.optional()
.integer(validationJsonError.serialize({
detail:'The "limit" value must be an integer',
errorAttribute: 'limit'
}))
.minValue(0, validationJsonError.serialize({
detail:'The minimum value for the "limit" is 0',
errorAttribute: 'limit'
}));
var offset = LGTM.validator()
.validates('offset')
.optional()
.integer(validationJsonError.serialize({
detail:'The "offset" value must be an integer',
errorAttribute: 'offset'
}))
.minValue(0, validationJsonError.serialize({
detail: 'The minimum value for the offset is 0',
errorAttribute: 'offset'
}));
var user = LGTM.validator()
.maxLength(25)
.required();
var posts = LGTM.validator()
.maxLength(200)
.required();
// My new validators
var getUserValidator = LGTM.build([limit, offset, user]);
var getPostsValidator = LGTM.build([limit, offset, posts]);