My goal is to create a index route for posts. User should be able to specify some query params (ie. tags, type) but shouldn't be able to specify others. To clarify:
This is okay:
/posts
/posts?tags=food
/posts?type=regular&tags=stackoverflow
This is not okay:
/posts?title=Hello
This is hapi pack config:
servers: [
{
host: 'localhost',
port: 3000,
options: {
labels: ["api"],
validation: {
abortEarly: false,
presence: 'forbidden'
}
}
}
],
Please notice the presence: forbidden
option.
This is route config:
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()
}
}
My idea was that the validation should allow any subset of type
and tags
params (including empty query). However, after making any of allowed requests i'm getting a following error:
{
"statusCode": 400,
"error": "Bad Request",
"message": "value is not allowed",
"validation": {
"source": "query",
"keys": [
"value"
]
}
}
Why is that? There is of course no key named value
. How to make the validation behave the way i want it to?
If you define a non-type schema object, Joi converts it internally to an object()
type. So this schema:
var schema = {
type: Joi.string().optional(),
tags: Joi.string().optional()
};
becomes:
var schema = Joi.object().keys({
type: Joi.string().optional(),
tags: Joi.string().optional()
});
Because you set presence
to forbidden
in server settings, it is applied to the object type, so the schema becomes:
var schema = Joi.object().forbidden().keys({
type: Joi.string().optional(),
tags: Joi.string().optional()
});
As you can see it marks the main object as forbidden which will not allow any value except 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);
});
It outputs:
{ [ValidationError: value is not allowed]
name: 'ValidationError',
details:
[ { message: 'value is not allowed',
path: 'value',
type: 'any.unknown' } ],
_object: {},
annotate: [Function] }
So what you need to do is to mark the main object either required
or optional
to override forbidden
:
validate: {
query: Joi.object().required().keys({
type: Joi.string().optional(),
tags: Joi.string().optional()
})
}