celeritas
Version:
This is an API service framework which supports API requests over HTTP & WebSockets.
150 lines (130 loc) • 6.74 kB
JavaScript
;
const mongoose = require('mongoose');
const lodash = require('lodash');
//this method is used to validate data for a call. You pass the schema, and input data into it, and it will return an error if the input data fails anything.
function validate (validationType, apiRoute, schema, data, propertyName = "data") {
switch (validationType) {
case "mongoose": {
try {
var s = mongoose.Schema(schema), model;
model = mongoose.model(apiRoute);
var tryData = new model(data);
return Promise.resolve(tryData.toJSON());
}
catch (err) {
return Promise.resolve(err);
}
}
//"native"
default: {
var s = lodash.cloneDeep(schema);
return Promise.resolve(_validate(s, data, propertyName));
}
}
}
//Subroutine used by the validate method.
function _validate (schema, data, propertyName, isArrayItem = false) {
for (var i in schema) {
//If the schema key is "$any", then the schema value should be an array of possible validation checks, where the first fulfilled check is the data that's returned instead of $any.
if (i == "$any") {
var hasSuccess = false;
var firstError = null;
for (var combo in schema[i]) {
var r = _validate(schema[i][combo], JSON.parse(JSON.stringify(data)), propertyName);
if (firstError == null && r instanceof Error)
firstError = r;
else if (!(r instanceof Error)) {
try {
Object.assign(schema, schema[i][combo]);
Object.assign(data, r);
delete schema[i];
firstError = null;
}
catch (err) {
return err;
}
break;
}
}
if (firstError != null)
return firstError;
break;
}
if (data !== null && typeof data[i] == "undefined") {
if (typeof schema[i].default !== "undefined")
data[i] = schema[i].default;
else if (schema[i] instanceof Array)
data[i] = [];
}
//for each schema property, if the field is required (assume required if not defined), return an error if that field is missing in the input data.
if (data !== null && typeof data[i] == "undefined" && typeof schema[i].type != 'undefined') {
if (typeof schema[i].required !== "undefined" && schema[i].required == true)
return new Error("400 - Bad Request: The parameter '" + propertyName + "." + i + "' is a required field, please try again.");
}
if (["string", "function"].indexOf(typeof schema[i]) > -1)
schema[i] = {type: schema[i]};
if (schema[i].type instanceof Function && ['String', 'Number', 'Date', 'Boolean', 'Object'].indexOf(schema[i].type.name) > -1)
schema[i].type = schema[i].type.name.toLowerCase();
}
for (var i in data) {
var propertyId = isArrayItem ? propertyName : propertyName + "." + i;
if (typeof schema[i] !== "undefined") {
//If the schema[i].type is still an object, then it's another schema declaration. Iterate down through the object.
if (!(schema[i] instanceof Array) && (typeof schema[i].type == "undefined" || typeof schema[i].type === "object")) {
if (typeof data[i] == "undefined")
data[i] = {};
var r = _validate(schema[i], data[i], propertyId);
if (r instanceof Error)
return r;
else
data[i] = r;
}
else {
if (typeof schema[i].type == "function") {
var r = schema[i].type(data[i]);
if (r == false) return new Error("400 - Bad Request: The parameter '" + propertyId + "' failed verification check '" + schema[i].type.name + "'. Please try again.");
}
else if (schema[i] instanceof Array) {
if (data[i] instanceof Array == false) {
if (typeof data[i] == "undefined")
data[i] = [];
else
return new Error("400 - Bad Request: The parameter '" + propertyId + "' should be an array of objects. Please try again.");
}
var checkAgainst = {_item: schema[i][0]};
for (var dataItem in data[i]) {
var r = _validate(checkAgainst, {_item: data[i][dataItem]}, propertyId + "[" + dataItem + "]", true);
if (r instanceof Error)
return r;
else
data[i][dataItem] = r._item;
}
}
else if (schema[i].type !== "*") {
if (schema[i].type == "date") {
if (data[i] != null) {
var tryDate = Date.parse(data[i]);
if (isNaN(tryDate))
return new Error("400 - Bad Request: The parameter '" + propertyId + "' cannot be parsed as a date. Please try again.");
else
data[i] = new Date(tryDate);
}
}
else if (typeof data[i] != schema[i].type.toLowerCase()) {
if (typeof data[i] == "number" && schema[i].type == "string") {
data[i] = data[i].toString();
}
else if (data[i] !== null && (typeof schema[i].required == "undefined" || schema[i].required == true))
return new Error("400 - Bad Request: The parameter '" + propertyId + "' should be of type '" + schema[i].type.toLowerCase() + "'. Please try again.");
}
if (typeof data[i] == "string" && (typeof schema[i].length !== "undefined" && data[i].length < schema[i].length))
return new Error("400 - Bad Request: The paramater '" + propertyId + "' must be at least '" + schema[i].length + "' characters long. Please try again.");
}
}
}
else
delete data[i];
}
return data;
}
module.exports = validate;