Проверка параметров запроса для запросов REST api в node.js

#javascript #node.js #rest

#javascript #node.js #rest

Вопрос:

У меня есть объект с допустимыми параметрами запроса для каждого типа объекта для запроса GET к API.

 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'],
};
  

Я хочу использовать эту функцию, чтобы убедиться, что для запроса принимаются только эти допустимые параметры. Прямо сейчас обещание разрешается false с допустимыми, недопустимыми параметрами или 0. Похоже, это проблема с тем, как я фильтрую. Я передаю тип объекта и запрос. Если в запросе есть параметры запроса, я хочу получить допустимые параметры из объекта и проверить, что все параметры в req являются допустимыми совпадениями с параметрами в объекте. Если есть какие-либо недопустимые, я хочу разрешить false . Если параметров нет, я хочу разрешить true . Если есть только допустимые параметры, я хочу разрешить true . Могу ли я как-то изменить эту функцию, чтобы получить такой результат?

 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);
    }
  });
}
  

Комментарии:

1. Вам не нужно усложнять этот код с помощью Promise , все там синхронно. Вы можете вернуть boolean напрямую. А также, в этом нет необходимости, utils.isDefined достаточно простого if(req.query) . Который также не нужен, если вы используете express , req.query всегда определяется как пустой объект, если нет параметра.

2. Покажите, как вы используете fieldValidator

Ответ №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;
}
  

Еще одна вещь, которую могла бы использовать эта функция, — это «ранний» возврат. Это упрощает отслеживание происходящего и уменьшает количество ветвей:

Переписать # 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));
}
  

Ничто из этого не отвечает на ваш вопрос, но мне это было нужно, чтобы получить больше ясности в том, что вы делаете =)

Проблема на самом деле в сравнении Object.keys() . Object.keys() возвращает итератор, но каждый итератор, который он возвращает, уникален.

Объекты в Javascript на самом деле не могут сравниваться «по значению». Единственный способ сравнить объекты по значению — проверять их ключи один за другим.

Поскольку вы хотите, чтобы свойства точно совпадали, я думаю, я бы изменил это на:

  1. Проверка, одинаковое ли у вас количество параметров запроса.
  2. Проверьте, отображается ли каждый переданный параметр запроса в наборе допустимых параметров запроса.

Исходя из этого, я думаю, что это будет моя версия:

 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;
}
  

Комментарии:

1. !req.query часть верна, но empty array комментарий — это не так. ![] есть false . В любом случае, req.query это не будет массив, если это исходит от express и он никоим образом не модифицируется req.query .

2. @MarcosCasagrande Я обновил комментарий до ‘Пустой объект’. Я чувствую, что это то, что искал OP, но не уверен. Что касается express … невозможно точно сказать, так ли это, поэтому не хотел делать поспешных выводов!

3.На самом деле, !{} по-прежнему равно false, единственными ложными значениями в javascript являются: null , undefined , 0 '' , false

4. @MarcosCasagrande да, но я полагаю, что это то, чего хотел OP, основываясь на описании. Возможно, ваша интерпретация отличается.

5. Цитата из OP: «Если параметров нет, я хочу разрешить true»

Ответ №2:

«Поля» — это массив имен ключей. Вы проверяете массив запроса.запрашивайте ключи к ключам объектов из массива имен ключей. Это индексы массива, просто последовательные целые числа ["0", "1", "2", ... etc] . Не говоря уже о том, что вы выполняете проверку неравенства между двумя массивами, которая никогда не будет истинной, если ссылки не совпадают, чего здесь нет. Итак, конечно, что первое условие всегда терпит неудачу и принимает значение false. Попробуйте сами в консоли: [1, 2, 3] === [1, 2, 3] будет false (то же самое с неплотными проверками равенства), потому что это разные объекты, которые просто случайно имеют одинаковые записи.

Поэтому я думаю, что лучший подход — изменить ваш фильтр, чтобы он отфильтровывал каждое поле запроса, находящееся в списке, и убедиться, что в конечном массиве нет записей (поскольку все, что осталось, было бы ключом, который не соответствует списку).

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

(Я предполагаю, что у вас есть невысказанная причина для использования Promise; если нет, то я бы согласился с предложением Маркос Касагранде полностью избавиться от Promise и просто возвращать true или false напрямую из функции.)

Ответ №3:

При использовании expressjs есть хороший способ сделать это с помощью check api.

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