简体   繁体   English

在 node.js 中验证 REST api 请求的查询参数

[英]Validating query parameters for REST api requests in node.js

I have an object of valid query parameters for each object type for a GET request to the API.我有一个针对每个对象类型的有效查询参数对象,用于对 API 的 GET 请求。

var queryFields = {
  'organisation': ['limit', 'page', 'id', 'search'],
  'actor': ['limit', 'page', 'id', 'search'],
  'version': ['limit', 'page', 'search'],
  'product': ['limit', 'page', 'search', 'id', 'type', 'brand', 'model', 'manufacturerSpid'],
  'asset': ['limit', 'page', 'search', 'order', 'sort', 'id', 'name', 'currentCustodianSpid', 'currentLocationSpid', 'productSpid', 'search'],
  'location': ['limit', 'page', 'search', 'id'],
  'workorder': ['limit', 'page', 'search', 'id', 'type', 'status', 'requirementSpid', ],
  'move': ['limit', 'page', 'search'],
  'transfer': ['limit', 'page', 'search'],
  'requirement': ['limit', 'page', 'search', 'id', 'type', 'source', 'productSpid', 'status', ],
  'artefact': ['limit', 'page', 'search'],
  'attestation': ['limit', 'page', 'search'],
};

I want to use this function to make sure that only these valid parameters are accepted for a request.我想使用这个函数来确保请求只接受这些有效参数。 Right now the promise resolves false with valid, invalid, or 0 parameters.现在,promise 使用有效、无效或 0 参数解析false It seems to be an issue with the way I am filtering.这似乎是我过滤方式的问题。 I pass in the object type and the request.我传入对象类型和请求。 If the request has query parameters, I want to grab the valid parameters from the object, and check that the parameters in the req are all valid matches to ones in the object.如果请求有查询参数,我想从对象中获取有效参数,并检查req中的参数是否都与对象中的参数有效匹配。 If there are any that are invalid, I want to resolve false .如果有任何无效的,我想解决false If there are no parameters, I want to resolve true .如果没有参数,我想解析true If there are only valid parameters, I want to resolve true .如果只有有效参数,我想解析true Is there some tweaking I can do to this function to get that outcome?我可以对此功能进行一些调整以获得该结果吗?

function getQueryFields(object) {
  if (utils.isDefined(queryFields[object])) return queryFields[object];
  return [];
}

function fieldValidator (objType, req) {
  return new Promise(function(resolve) {
    if (utils.isDefined(req.query)) {
      var fields = getQueryFields(objType);
      //Only resolve true with valid fields
      fields = fields.filter(function(field) { return Object.keys(req.query).indexOf(field) > -1;});
      if (Object.keys(req.query) !== Object.keys(fields)) {
        resolve(false);
      } else {
        resolve (true);
      }
    } else {
      resolve(true);
    }
  });
}

There's a few issues with your function.您的函数存在一些问题。 I want to fix the first issues before getting into your actual problem, because it will increase the clarity quite a bit.我想在进入你的实际问题之前解决第一个问题,因为它会增加相当多的清晰度。 First: you don't need Promises, this is a synchronous function.第一:你不需要 Promises,这是一个同步函数。

Rewrite #1:重写#1:

function getQueryFields(object) {
  if (utils.isDefined(queryFields[object])) return queryFields[object];
  return [];
}

function fieldValidator (objType, req) {
  if (utils.isDefined(req.query)) {
    var fields = getQueryFields(objType);
    //Only resolve true with valid fields
    fields = fields.filter(function(field) {
      return Object.keys(req.query).indexOf(field) > -1;
    });
    if (Object.keys(req.query) !== Object.keys(fields)) {
      return false;
    } else {
      return true;
    }
  }
} else {
  return true;
}

Another thing this function could use is an 'early' return.该函数可以使用的另一件事是“提前”返回。 This makes it easier to follow what is going on and reduces the number of branches:这样可以更轻松地跟踪正在发生的事情并减少分支数量:

Rewrite #2:重写#2:

function fieldValidator (objType, req) {
  if (req.query === undefined) {
    return true;
  }

  var fields = getQueryFields(objType);
  //Only resolve true with valid fields
  fields = fields.filter(function(field) {
    return Object.keys(req.query).indexOf(field) > -1;
  });
  return (Object.keys(req.query) === Object.keys(fields));
}

None of this answers your question, but I needed it to get more clarity on what you're doing =)这些都不能回答你的问题,但我需要它来更清楚你在做什么 =)

The issue is actually in comparing Object.keys() .问题实际上在于比较Object.keys() Object.keys() returns an iterator, but every iterator that it returns is unique. Object.keys()返回一个迭代器,但它返回的每个迭代器都是唯一的。

Objects in Javascript can't really compared 'by value'. Javascript 中的对象无法真正“按值”进行比较。 The only way to compare objects by value is to inspect their keys one by one.按值比较对象的唯一方法是一一检查它们的键。

Since you want the properties to exactly match, I think I would change this to:由于您希望属性完全匹配,我想我会将其更改为:

  1. Checking if you have the same number of query parameters.检查您是否具有相同数量的查询参数。
  2. Check if every query parameter that was passed appears in the set of valid query parameters.检查传递的每个查询参数是否都出现在有效查询参数集中。

Based on that, I think this would be my version:基于此,我认为这将是我的版本:

function fieldValidator(objType, req) {
  if (!req.query || Object.keys(req.query).length === 0) {
    // Covers the 'undefined' and 'empty object' case
    return true;
  }

  const fields = getQueryFields(objType);
  const keys = Object.keys(req.query);

  // Do we have enough query parameters?
  if (keys.length !== fields.length) return false;

  // Does every query parameter appear in the list?
  for(const key of keys) {
     if (!fields.includes(key)) return false;
  }
  return true;
}

"Fields" is an array of key names. “字段”是一个键名数组。 You're checking the array of req.query keys against the object keys of the array of key names.您正在根据键名数组的对象键检查 req.query 键数组。 That's the indexes of the array, just consecutive integers, ["0", "1", "2", ... etc] .那是数组的索引,只是连续的整数, ["0", "1", "2", ... etc] Not to mention, you're doing an inequality check between two arrays, which will never be true unless the references are the same, which they're not here.更不用说,您正在两个数组之间进行不等式检查,除非引用相同,否则它们永远不会为真,它们不在这里。 So of course that first condition always fails and resolves to false.所以当然,第一个条件总是失败并解析为 false。 Try it yourself in a console: [1, 2, 3] === [1, 2, 3] will be false (same with loose equality checks) because they're different objects that just happen to have the same entries.在控制台中自己尝试一下: [1, 2, 3] === [1, 2, 3]将是假的(与松散的相等性检查相同),因为它们是恰好具有相同条目的不同对象。

So I think a better approach is to change your filter so it filters away every query field that's in the list, and ensure the final array has no entries (as anything left would be a key that doesn't match the list).所以我认为更好的方法是更改​​您的过滤器,以便过滤掉列表中的每个查询字段,并确保最终数组没有条目(因为剩下的任何内容都是与列表不匹配的键)。

  fields = Object.keys(req.query).filter(function(field) { return fields.indexOf(field) > -1;});
  if (fields.length > 0) {
    resolve(false);
  } else {
    resolve (true);
  }

(I'm assuming you have an untold reason for using a Promise; if not, then I'd go with Marcos Casagrande's suggesting of getting rid of the Promise altogether and just returning true or false from the function directly.) (我假设您有使用 Promise 的不为人知的原因;如果没有,那么我会同意 Marcos Casagrande 的建议,即完全摆脱 Promise 并直接从函数中返回 true 或 false。)

If using expressjs there is a nice way doing this using check api.如果使用 expressjs,那么使用 check api 有一个很好的方法。

https://express-validator.github.io/docs/check-api.html https://express-validator.github.io/docs/check-api.html

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

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