Reputation: 14179
I have a three field form made of a name field, email field and a textarea. I'm using Joi 4.7.0 version along with hapijs. I use the object below validate the input. I receive the data object from an ajax call. When I fill all the three fields with wrong informations I get only the message relative to the first wrong field. Like that:
"{"statusCode":400,"error":"Bad Request","message":"name is not allowed to be empty","validation": {"source":"payload","keys":["data.name"]}}"
validate: {
payload: {
data: {
name: Joi.string().min(3).max(20).required(),
email: Joi.string().email().required(),
message: Joi.string().min(3).max(1000).required()
}
}
}
For explanation let suppose to not fill the three field. I get only one message error and not the message error of the others fields. Why?
Upvotes: 50
Views: 38219
Reputation: 63
In hapi v21
, we can add validate inside routes at the time of server instance creation, like this
const server = Hapi.server({
port: 3000,
host: 'localhost',
routes: {
validate: {
options: {
abortEarly: false, // Add this line
},
},
},
});
And inside a route, we can validate your payload with Joi
{
method: 'POST',
path: '/user',
handler: async function() { },
options: {
validate: {
payload: Joi.object({
data: Joi.object({
name: Joi.string().min(3).max(20).required(),
email: Joi.string().email().required(),
message: Joi.string().min(3).max(1000).required()
})
})
}
}
}
Upvotes: 0
Reputation: 151
After some research, I found out it can be solved 2 ways:
[Segments.BODY]: Joi.object().keys({
value: Joi.string().required().error(new Error('Value is required and has to be a text!')),
})
or
[Segments.BODY]: Joi.object().keys({
password: Joi.string().required().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).min(8).label('Password').messages({
'string.pattern.base': 'Your {#label} does not matche the suggested pattern',
'string.base': `Your {#label} should match the suggested pattern`,
'string.empty': `Your {#label} can not be empty`,
'string.min': `Your {#label} has to be at least {#limit} chars`,
'any.required': `Your {#label} is required`,
}),
})
Upvotes: 2
Reputation: 39005
I'm not integrating with hapi.js, but I noticed that there is a ValidationOptions
object which can be passed along. Inside that object is an abortEarly
option, so this should work:
Joi.validate(request, schema, { abortEarly: false }
This can also be configured as follows:
Joi.object().options({ abortEarly: false }).keys({...});
Check out these type definitions for more ValidationOptions
:
https://github.com/DefinitelyTyped/tsd/blob/master/typings/joi/joi.d.ts
Upvotes: 45
Reputation: 42048
It happens because Joi aborts early by default.
abortEarly
- whentrue
, stops validation on the first error, otherwise returns all the errors found. Defaults totrue
.
*EDIT: Configuration has changed in hapi 8.0. You need to add abortEarly: false
to the routes
config:
var server = new Hapi.Server();
server.connection({
host: 'localhost',
port: 8000,
routes: {
validate: {
options: {
abortEarly: false
}
}
}
});
*See the Joi API documentation for more details.
*Also, see validation
under Hapi Route options.
So Joi stops the validation on the first error:
var Hapi = require('hapi');
var Joi = require('joi');
var server = new Hapi.Server('localhost', 8000);
server.route({
method: 'GET',
path: '/{first}/{second}',
config: {
validate: {
params: {
first: Joi.string().max(5),
second: Joi.string().max(5)
}
}
},
handler: function (request, reply) {
reply('example');
}
});
server.start();
server.inject('/invalid/invalid', function (res) {
console.log(res.result);
});
Outputs:
{ statusCode: 400,
error: 'Bad Request',
message: 'first length must be less than or equal to 5 characters long',
validation: { source: 'params', keys: [ 'first' ] } }
You can however configure Hapi to return all errors. For this, you need to set abortEarly
to false
. You can do this in server configuration:
var server = new Hapi.Server('localhost', 8000, { validation: { abortEarly: false } });
If you run the script now, you get:
{ statusCode: 400,
error: 'Bad Request',
message: 'first length must be less than or equal to 5 characters long. second length must be less than or equal to 5 characters long',
validation: { source: 'params', keys: [ 'first', 'second' ] } }
Upvotes: 56
Reputation: 51
The validation
key no longer works with the Hapi.Server
constructor in Hapi 8.0:
[1] validation is not allowed
I found the solution in a GitHub issue for hapi:
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({
host: HOST,
port: PORT,
routes: {
validate: {
options: {
abortEarly: false
}
}
}
});
// Route using Joi goes here.
server.route({});
server.start(function () {
console.log('Listening on %s', server.info.uri);
});
Upvotes: 5