You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.path is renamed config.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.response no longer accepts true or false.
Server config validation no longer supports the modify flag (was true by default).
New Features
Pre-validation values (before any defaults are applied or type casting) are now available under request.orig for 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:
varrule={a: Joi.ref('b'),// a must be equal to bb: Joi.number(),c: Joi.default(Joi.ref('b')),// c defaults to b if not presentd: Joi.valid(Joi.ref('b'),Joi.ref('c')),// d must be equal to b or ce: {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:
varrule={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 headers are being validated, the values of params, query, and payload are exposed). The context values can be used in references to create rules that cross input sources:
varserver=newHapi.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() and alternatives.try() which allow adding additional keys or alternatives.
// Defining new custom types:varfullName=Joi.string().min(3).max(255).regex(/\w+ \w+/);varrequiredFullName=fullName.required();// Adding keys to object:varname=Joi.object({first: Joi.string().require(),last: Joi.string()});varextName=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 handle request.params[name] to be null instead of ''.
Look for any route with config.validate.path and rename path to params.
Look for any route using response validation via config.response:
if config.response is set to true or false, change it to { schema: true } or { schema: false }.
if config.response.schema is 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 changes a to 2). If you rely in this behavior, remove the validation rule and instead apply it using the 'onPreResponse' extension point.
Look for server configuration key validation and if you override validation.modify to false in your code, change your handlers and extensions to use request.orig instead (e.g. request.orig.params).
joi changes:
The modify option 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 under request.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 move option is now true by default (old name is removed). To keep the old name alongside the new name, set alias to true.
with(), without(), xor(), andor()` can no longer be set on individual keys, only on the parent object:
{ a: Joi.any().with('b') } is now Joi.object({ a: Joi.any() }).with('a', 'b') }) where the first argument to with() is the subject.
{ a: Joi.any().without('b') } is now Joi.object({ a: Joi.any() }).without('a', 'b') }) where the first argument to with() is the subject.
{ a: Joi.any().xor('b') } is now Joi.object({ a: Joi.any() }).xor('a', 'b') }) where xor() argument order does not matter.
{ a: Joi.any().or('b') } is now Joi.object({ a: Joi.any() }).or('a', 'b') }) where or() argument order does not matter.
Validation error object no longer support the simple() method. The error.message is automatically set to the output of simple() and does not change. The method annotated() is replaced by annotate() which does not modify the error and returns the annotated error string.
Alternatives using the [] notation now allow undefined by default (defaulted to required before). To preserve the previous behavior, replace [Joi.string(), Joi.number()] with Joi.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.
The text was updated successfully, but these errors were encountered:
Thank you for enhancing validation with your awesome lib Joi.
I was in the midst of the breaking changes but then realized what was happening and upgraded from github directly.
Fantastic work ! I'm happy using it for my projects.
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.
Breaking Changes
'{param?}
or{param*}
) path parameters (request.params
) are no longer assigned the empty string.config.validate.path
is renamedconfig.validate.params
.config.response
no longer acceptstrue
orfalse
.validation
no longer supports themodify
flag (wastrue
by default).New Features
request.orig
for modified values.config.validate.headers
.New feature highlights in joi v4.0:
headers
are being validated, the values ofparams
,query
, andpayload
are exposed). The context values can be used in references to create rules that cross input sources:object.keys()
andalternatives.try()
which allow adding additional keys or alternatives.Migration Checklist
?}
and*}
in route paths) and confirm your code can handlerequest.params[name]
to be null instead of''
.config.validate.path
and renamepath
toparams
.config.response
:config.response
is set totrue
orfalse
, change it to{ schema: true }
or{ schema: false }
.config.response.schema
is 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 changesa
to2
). If you rely in this behavior, remove the validation rule and instead apply it using the'onPreResponse'
extension point.validation
and if you overridevalidation.modify
tofalse
in your code, change your handlers and extensions to userequest.orig
instead (e.g.request.orig.params
).joi changes:
modify
option 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()
object.rename()
- key can no longer rename itself, only the object can rename its children.move
option is nowtrue
by default (old name is removed). To keep the old name alongside the new name, setalias
totrue
.with()
,without()
,xor(), and
or()` 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.simple()
method. Theerror.message
is 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.[]
notation now allowundefined
by default (defaulted to required before). To preserve the previous behavior, replace[Joi.string(), Joi.number()]
withJoi.alternatives([Joi.string(), Joi.number()]).required()
.The text was updated successfully, but these errors were encountered: