Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5.0.0 Release Notes #1645

Closed
hueniverse opened this issue May 19, 2014 · 1 comment
Closed

5.0.0 Release Notes #1645

hueniverse opened this issue May 19, 2014 · 1 comment

Comments

@hueniverse
Copy link
Contributor

@hueniverse hueniverse commented May 19, 2014

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.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:
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 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:
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() and alternatives.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 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.
@hueniverse hueniverse added this to the 5.0.0 milestone May 19, 2014
@hueniverse hueniverse self-assigned this May 19, 2014
@hueniverse hueniverse closed this May 19, 2014
@jeveloper
Copy link

@jeveloper jeveloper commented May 20, 2014

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.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants