简体   繁体   English

如何根据“模式”过滤JSON对象

[英]How to filter JSON objects according to “schema”

I build a RESTful api with node.js and express / koa. 我用node.js和express / koa构建一个RESTful api。

I want to filter the JSON data input - for security reasons as well to have only the needed business specific properties. 我想过滤JSON数据输入 - 出于安全原因以及只有所需的业务特定属性。 After filtering the business-specific validation takes place. 过滤后,将进行特定于业务的验证。

How can I throw away unwanted JSON / JS object properties - ie properties not in my database schema as well as empty properties? 如何丢弃不需要的JSON / JS对象属性 - 即不在我的数据库模式中的属性以及空属性?

I think joi is a good library for validation and normalization. 我认为joi是一个很好的验证和规范化库。 You can also sometimes get away with something as simple as _.pick from lodash/underscore. 你有时也可以从lodash / underscore中获取像_.pick这样简单的东西。

You may consider using JSON-schema validators. 您可以考虑使用JSON模式验证器。

http://json-schema.org/implementations.html http://json-schema.org/implementations.html

Validators benchmark: https://github.com/ebdrup/json-schema-benchmark 验证者基准: https//github.com/ebdrup/json-schema-benchmark

Disclaimer: I created ajv 免责声明:我创建了ajv

From the documentation, joi.validate() can strip fields, but only fields that are Objects. 从文档中,joi.validate()可以删除字段,但只能删除作为对象的字段。 I wrote this, avialable in a gist , which seems to work fine. 我写了这个,在一个要点中可用,似乎工作得很好。 It returns a new Object containing only those fields in the comparison object which have the same name and type as the corresponding field in the schema object: 它返回一个新的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;
}

The following test cases properly strip out incorrect fields: 以下测试用例正确地删除了不正确的字段:

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' ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM