#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 на самом деле не могут сравниваться «по значению». Единственный способ сравнить объекты по значению — проверять их ключи один за другим.
Поскольку вы хотите, чтобы свойства точно совпадали, я думаю, я бы изменил это на:
- Проверка, одинаковое ли у вас количество параметров запроса.
- Проверьте, отображается ли каждый переданный параметр запроса в наборе допустимых параметров запроса.
Исходя из этого, я думаю, что это будет моя версия:
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.