-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Closed
Labels
breaking changesChange that can breaking existing codeChange that can breaking existing coderelease notesMajor release documentationMajor release documentation
Milestone
Description
Summary
hapi v5.0 contains a new version of the joi validation module (v4.0). This version contains significant changes in how joi operates as well as some powerful new features.
- Upgrade time: low - a few hours for most users
- Complexity: low - all the changes are easy to locate and modify
- Risk: low to moderate - use of response validation in prior versions may rely on an existing side-effect bug
Breaking Changes
- The full list of joi breaking changes included is listed here.
- Missing optional (
'{param?}or{param*}) path parameters (request.params) are no longer assigned the empty string. - Route validation config
config.validate.pathis renamedconfig.validate.params. - Response validation no longer modifies the response when type casting is performed (e.g. converting a string to number). Validation will still pass but the data will remain unchanged.
- Response validation config
config.responseno longer acceptstrueorfalse. - Server config
validationno longer supports themodifyflag (wastrueby default).
New Features
- Pre-validation values (before any defaults are applied or type casting) are now available under
request.origfor modified values. - Request headers validation rules can be specified using
config.validate.headers. - Cross input validation (e.g. validating query parameters based on the value of path parameters).
New feature highlights in joi v4.0:
- References - rules can use the value of other keys:
var rule = {
a: Joi.ref('b'), // a must be equal to b
b: Joi.number(),
c: Joi.default(Joi.ref('b')), // c defaults to b if not present
d: Joi.valid(Joi.ref('b'), Joi.ref('c')), // d must be equal to b or c
e: {
f: Joi.string()
},
g: Joi.ref('e.f') // g references a child of e
};- Conditions - write rules where the value of one variable is tested based on the value of another:
var rule = {
a: Joi.any(),
// If a is a number, b must be 'x' - otherwise 'y'
b: Joi.when('a', {
is: Joi.number(),
then: 'x',
otherwise: 'y'
})
};- Context - hapi now sets a validation context object with the values of the other inputs (when
headersare being validated, the values ofparams,query, andpayloadare exposed). The context values can be used in references to create rules that cross input sources:
var server = new Hapi.Server();
server.route({
method: 'GET',
path: '/{user?}',
handler: function (request, reply) { reply('ok'); },
config: {
validate: {
query: {
// When the request path includes a user, enable the verbose query
// parameter, otherwise forbid it.
verbose: Joi.boolean()
.when('$params.user', {
is: Joi.exist(),
otherwise: Joi.forbidden()
})
}
}
}
});- Custom Types - joi v3.0 added support for immutable object which means that adding a rule to an existing joi object returns a new object and leaves the source unchanged. This allows defining types and reusing them (before, adding a rule changes all other references to the original object). In v4.0, joi adds support for
object.keys()andalternatives.try()which allow adding additional keys or alternatives.
// Defining new custom types:
var fullName = Joi.string().min(3).max(255).regex(/\w+ \w+/);
var requiredFullName = fullName.required();
// Adding keys to object:
var name = Joi.object({
first: Joi.string().require(),
last: Joi.string()
});
var extName = name.keys({
middle: Joi.string()
});Migration Checklist
- Look for usage of optional path parameters (search for
?}and*}in route paths) and confirm your code can handlerequest.params[name]to be null instead of''. - Look for any route with
config.validate.pathand renamepathtoparams. - Look for any route using response validation via
config.response:- if
config.responseis set totrueorfalse, change it to{ schema: true }or{ schema: false }. - if
config.response.schemais set to a joi rule, ensure that you are not relying on any type conversions (e.g. the handler is setting{ a: '2' }and the validation changesato2). If you rely in this behavior, remove the validation rule and instead apply it using the'onPreResponse'extension point.
- if
- Look for server configuration key
validationand if you overridevalidation.modifytofalsein your code, change your handlers and extensions to userequest.originstead (e.g.request.orig.params).
joi changes:
- The
modifyoption is no longer available. The original values are not modified but instead a modified copy is returned. Note that the copy is not a full deep clone and may share nodes with the original value to minimize impact on performance. Within hapi, the original values are now available underrequest.orig. When using joi directly, the modified value is return as the second callback argument. rename()- moved to
object.rename()- key can no longer rename itself, only the object can rename its children. - the
moveoption is nowtrueby default (old name is removed). To keep the old name alongside the new name, setaliastotrue.
- moved to
with(),without(),xor(), andor()` can no longer be set on individual keys, only on the parent object:{ a: Joi.any().with('b') }is nowJoi.object({ a: Joi.any() }).with('a', 'b') })where the first argument towith()is the subject.{ a: Joi.any().without('b') }is nowJoi.object({ a: Joi.any() }).without('a', 'b') })where the first argument towith()is the subject.{ a: Joi.any().xor('b') }is nowJoi.object({ a: Joi.any() }).xor('a', 'b') })wherexor()argument order does not matter.{ a: Joi.any().or('b') }is nowJoi.object({ a: Joi.any() }).or('a', 'b') })whereor()argument order does not matter.
- Validation error object no longer support the
simple()method. Theerror.messageis automatically set to the output ofsimple()and does not change. The methodannotated()is replaced byannotate()which does not modify the error and returns the annotated error string. - Alternatives using the
[]notation now allowundefinedby default (defaulted to required before). To preserve the previous behavior, replace[Joi.string(), Joi.number()]withJoi.alternatives([Joi.string(), Joi.number()]).required(). - The language file templates have changed significantly and any custom language files must be reworked using the new formats.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
breaking changesChange that can breaking existing codeChange that can breaking existing coderelease notesMajor release documentationMajor release documentation