I have been using Joi validation for a while now, for most situations it is pretty solid, but every time I need to do something custom it require a bit more work. As a learning experiment i have been thinking of writing my own lightweight JSON validation "boilerplate".
The premises:
- This validation is server only (NodeJs), which means I can use modern javascript functions/methods.
- I'm using a JSON body parser so i know that POST data is valid JSON, that means i dont have to care about certain values like NaN och undefined.
Lets consider this small piece of JSON coming from a POST:
{
"name": "Anders",
"dur": 3600000,
"staff": [
"Eric",
"John",
],
"unwantedProp": "foo"
}
I want to
- Make sure the following properties exist:
name,dur, andstaff. Ignore all other. - Make sure
nameis string. - Make sure
duris number. (Or convert if string). - Make sure
staffis array, and only contains strings. - Create a bad request error directly when something is wrong.
To get started i wrote this piece of code and put it in a module.
var error = function (message, status) {
var e = new Error(message);
e.status = status;
return e;
};
module.exports.validateClient = function(json, callback) {
var result = {};
if (!json.hasOwnProperty('name')) {
return callback(error('name is not defined', 400));
} else if (typeof json.name === 'string') {
result.name = json.name
} else {
return callback(error('name must be a string', 400));
}
if (!json.hasOwnProperty('dur')) {
return callback(error('dur is not defined', 400));
} else if (typeof json.dur === 'number') {
result.dur = Math.floor( json.dur )
} else if (typeof json.dur === 'string') {
result.dur = parseInt(json.dur, 10);
} else {
return callback(error('dur must be a number', 400));
}
if (!json.hasOwnProperty('staff')) {
return callback(error('staff is not defined', 400));
} else if (Array.isArray(json.staff)) {
var valid = true
json.staff.forEach(function (elem) {
if (typeof elem !== 'string') {
valid = false;
}
})
if (valid) {
result.staff = json.staff;
} else {
return callback(error('staff may only contain strings', 400));
}
} else {
return callback(error('staff must be an array', 400));
}
callback(null, result);
};
I then use this function like:
hlpr.validateClient(req.body, function(err, result) {
if (err) return next(err);
res.json(result);
})
Even though this works, I know it's a total mess of if statements... and its totaly non reusable. This brings me to my somewhat vague question. Can someone please give me some guidelines of how to break down this mess into smaller reusable functions that can be applied to other JSON data... Maybe help me with an example of a modularized part of my if-statement mess.