From the documentation, joi.validate () can discard fields, but only fields that are objects. I wrote this, avialable in gist , which seems to work fine. It returns a new object containing only those fields of the comparison object that have the same name and type corresponding to the corresponding field of the schema object:
// Recursively strip out fields in objects and subobjects function stripFields(schema, obj) { var newObj = {}; var schemaType = schema.constructor.name; var objType = obj.constructor.name; // If types match and this property is not an Object, return the value if (schemaType !== "Object") { if(schemaType === objType) { return obj; } else { return null; } } var keys = Object.keys(schema); keys.forEach(function(key) { if(key in obj) { // Get instance names for properties var schemaConstructor = schema[key].constructor.name; var objConstructor = obj[key].constructor.name; // Only copy fields with matching types. if (schemaConstructor === objConstructor) { // Handle cases with subObjects if (objConstructor === "Object") { var res = stripFields(schema[key], obj[key]); if (res !== null) { newObj[key] = res; } } else { // Just copy in non-Object properties (String, Boolean, etc.) newObj[key] = obj[key]; } } }; if (newObj === {}) { return null; } }); return newObj; }
In the following test cases, invalid fields are cut correctly:
var stripFields = require("./stripfields"); var schema = { a: 1, b: 1, c:{ foo:"bar", obj:{nestedField:1} }, d:[1] }; var testObj1 = { a: 7, b: 8, c:{ foo:"bar" }, d:[4,5] }; var testObj2 = { a: 1, b: 2, c:{ foo:"bar", obj:{nestedField:213} }, d:[1,3,4], e:"someOtherField" }; var testObj3 = { a: 1, c:{ foo:"some string", bar:1 }, d:"string instead of array" }; var res1 = stripFields(schema, testObj1); var res2 = stripFields(schema, testObj2); var res3 = stripFields(schema, testObj3); var res4 = stripFields([1,2,3], ["a"]); console.log("Results:"); console.log(res1); console.log(res2); console.log(res3); console.log(res4);
Results:
Results: { a: 7, b: 8, c: { foo: 'bar' }, d: [ 4, 5 ] } { a: 1, b: 2, c: { foo: 'bar', obj: { nestedField: 213 } }, d: [ 1, 3, 4 ] } { a: 1, c: { foo: 'some string' } } [ 'a' ]