Hapijs和Joi:验证存在的查询参数:'禁止'

Hapijs and Joi: validate query params with presence: 'forbidden'

本文关键字:参数 禁止 查询 Joi 验证 存在 Hapijs      更新时间:2023-09-26

我的目标是为帖子创建索引路由。用户应该能够指定一些查询参数(如标签、类型),但不能指定其他参数。澄清:

这没关系:

/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()
    }
}

我的想法是,验证应该允许typetags参数的任何子集(包括空查询)。然而,在做出任何允许的请求后,我得到了以下错误:

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

为什么?当然,没有名为value的密钥。如何使验证按照我希望的方式进行?

如果定义了一个非类型模式对象,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] }

因此,您需要做的是将主对象标记为requiredoptional以覆盖forbidden:

validate: {
    query: Joi.object().required().keys({
        type: Joi.string().optional(),
        tags: Joi.string().optional()
    })
}