Hapijs и Joi: проверить параметры запроса с присутствием: «запрещено»

Моя цель — создать маршрут index для сообщений. Пользователь должен иметь возможность указать некоторые параметры запроса (например, теги, тип), но не должен иметь возможность указывать другие. Чтобы уточнить:

Это нормально:

/posts
/posts?tags=food
/posts?type=regular&tags=stackoverflow

Это не нормально:

/posts?title=Hello

Это конфигурация пакета hapi:

servers: [
        {
            host: 'localhost',
            port: 3000,
            options: {
                labels: ["api"],
                validation: {
                    abortEarly: false,
                    presence: 'forbidden'
                }
            }
        }
    ],

Обратите внимание на опцию presence: forbidden.

Это конфигурация маршрута:

handler: function (request, reply) {
    Post.find(request.query, function (err, posts) {
        if(err) {
            console.log(err);
        }

        reply(posts);
    });
},
validate: {
    query: {
        type: Joi.string().optional(),
        tags: Joi.string().optional()
    }

}

Моя идея заключалась в том, что проверка должна разрешать любое подмножество параметров type и tags (включая пустой запрос). Однако после выполнения любого из разрешенных запросов я получаю следующую ошибку:

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "value is not allowed",
    "validation": {
        "source": "query",
        "keys": [
            "value"
        ]
    }
}

Это почему? Ключа с именем value, конечно же, нет. Как заставить проверку вести себя так, как я хочу?


person zir    schedule 06.10.2014    source источник


Ответы (1)


Если вы определяете объект схемы, не являющийся типом, Joi внутренне преобразует его в тип object(). Итак, эта схема:

var schema = {
    type: Joi.string().optional(),
    tags: Joi.string().optional()
};

становится:

var schema = Joi.object().keys({
    type: Joi.string().optional(),
    tags: Joi.string().optional()
});

Поскольку вы устанавливаете presence в forbidden в настройках сервера, оно применяется к типу объекта, поэтому схема становится следующей:

var schema = Joi.object().forbidden().keys({
    type: Joi.string().optional(),
    tags: Joi.string().optional()
});

Как видите, он помечает основной объект как запрещенный, что не позволяет использовать никакие значения, кроме undefined:

var Joi = require('joi');

var schema = Joi.object().forbidden().keys({
    type: Joi.string().optional(),
    tags: Joi.string().optional()
});

var value = {};

Joi.validate(value, schema, { presence: 'forbidden' }, function (err, value) {

    console.log(err);
});

Он выводит:

{ [ValidationError: value is not allowed]
  name: 'ValidationError',
  details: 
   [ { message: 'value is not allowed',
       path: 'value',
       type: 'any.unknown' } ],
  _object: {},
  annotate: [Function] }

Итак, что вам нужно сделать, это пометить основной объект либо required, либо optional, чтобы переопределить forbidden:

validate: {
    query: Joi.object().required().keys({
        type: Joi.string().optional(),
        tags: Joi.string().optional()
    })
}
person Gergo Erdosi    schedule 06.10.2014
comment
Благодарю вас! Этот ответ прояснил несколько других вопросов, которые у меня были. Казалось бы, что я действительно хотел в качестве глобальной настройки, так это присутствие: «требуется». Я не осознавал, что «запрещенная» настройка была такой строгой. - person zir; 07.10.2014