Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@psi-4ward
Created December 8, 2017 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save psi-4ward/e0a6fb3e04f13bf9929601af0de67d41 to your computer and use it in GitHub Desktop.
Save psi-4ward/e0a6fb3e04f13bf9929601af0de67d41 to your computer and use it in GitHub Desktop.
feathersjs schema validation based on Ajv with switch and $async support
const Ajv = require('ajv');
const ajvKeywords = require('ajv-keywords');
const ajvAsync = require('ajv-async');
const errors = require('@feathersjs/errors');
const app = require('../app');
module.exports = function validateSchemaHookFactory(schema, options) {
const patch = options && options.patch;
if(options) delete options.patch;
// Set some defaults
options = Object.assign({
allErrors: true,
format: 'full',
errorsFormatter: errs => errs
}, options);
// Init Ajv with async support
const ajv = ajvAsync(new Ajv(options));
// Add switch support, @see http://epoberezkin.github.io/ajv/keywords.html#switch-proposed
ajvKeywords(ajv, ['switch']);
// Add idExists keyword to check service references
// @see http://epoberezkin.github.io/ajv/#asynchronous-validation
/*
const schema = {
"$async": true,
"properties": {
"userId": {
"type": "string",
"idExists": { "service": "users" }
},
}
};
*/
ajv.addKeyword('idExists', {
async: true,
type: 'string',
validate: async function checkIdExists(schema, data) {
try {
return await app.service(schema.service).get(data);
} catch(e) {
throw new Ajv.ValidationError([{
keyword: 'idExists',
message: 'id not found in service ' + schema.service
}]);
}
}
});
// Compile schema
const validate = ajv.compile(schema);
// Return the validateSchemaHook
return async function validateSchemaHook(hook) {
let data = hook.data;
// validate complete data object for PATCH requests
if(patch) {
const oldData = await this.get(hook.id);
data = {...oldData, ...data};
}
try {
// validate() returns false for synchronous schemas
// or promise rejection for asynchronous
if(!await validate(data)) {
// noinspection ExceptionCaughtLocallyJS
throw { errors: validate.errors };
}
return hook;
}
catch(e) {
// Transform to feathers error
throw new errors.BadRequest('Validation failed', {
errors: options.errorsFormatter.call(hook, e.errors),
...hook.data
});
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment