-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
RFC: Joi plugins/extensions/custom functions #577
Comments
This looks like a good start, but one major issue is that it's using what is effectively a global in an unsafe way, potentially leading to naming collisions and unexpected behavior. For example, imagine if module A and module B both depend on the same version of Joi and both declare a type |
As written, any attempt to override a type will result in an error, I don't think this should be a problem to debug. |
Ah, ok, I missed that part. If I depend on A and B and an error is thrown, I have no recourse or ability to remedy the situation as I don't own those dependencies and those authors could not have anticipated being I the same dependency graph as each other. This would require module authors to define globally unique (as in unique from every other package in npm) types. Also, as a module author I can say that having to come up with and define globally unique names via trial and error is undesirable . |
I'm not sure it's preferable to locally load all extensions. Uniqueness will be partially guaranteed by npm naming, for other cases I don't see how we can solve that. |
Can you clarify? Also, I understand I'm the worst kind of commenter. I identify a problem but, unfortunately I don't have a solution. (Need to think on it more.) Sorry about that. I can say that at my company where we would need to define types for validation in things like service wrappers, this mechanism would not work and we would not be able to use it due to the high likelihood of name reuse. |
If people publish types as modules named joi-type, that should avoid many conflicts, but that doesn't fix the internal ones. So you'd rather require all extensions each time in all your files? |
|
I don't believe the templating language is relevant for this proposal but yes it'll have to be documented. Joi need to maintain a bunch of core features because of parameters validation. |
|
|
Really excited about this, and bonus: asynchronicity! I think maybe you misunderstand the namespace problem brought up by totherik. He's not talking about uniqueness as an NPM module, he's talking about uniqueness in the Joi namespace. I agree, this is a problem. It can be solved fairly readily, however, by allowing Joi to be instantiated rather than using it as a singleton, e.g. It would then be up to the developer to share the Joi instance around, but this is trivial in Node.js since you can just create a simple wrapper that also defines your extensions:
You can drop the requirement for the () by making it instead a method of Joi itself, like Joi has long been my favored validation library, but I've wound up using it almost nowhere because of the two things this proposal will address. Happy happy joy joy! |
Re: the question about cloning/freezing or trusting the developer, I'm in favor of the latter. Solid enforcement appeals to me, but one of the most useful use cases for Joi is in things like HTTP requests, where the performance difference can be solidly beneficial. A suitable compromise is to allow the user to specify an option about whether to freeze the objects or not, and this option could be used when running tests or development, for example, but not in production. |
Thanks for clarifying my comments @myndzi. (Weekend away with the fam so trying to stay offline :) ) So with the pursuit of types-as-npm-modules, is it reasonable to expect that a single application/module may need to depend on incompatible versions of the same npm module type definition? If so, npm can't be used to manage those dependencies. (I'm thinking major revisions of types that aren't required to be backward compatible according to semver.) I don't know all use-cases, but I have to imagine this could be an issue. |
I understood what he meant, npm is indeed a "trick", not a solution, but it might avoid some basic conflicts. I kind of agree on the freezing/cloning/vanilla problem, if you really want to mess up your schemas, that's your responsibility, can't protect users from everything. |
I don't see how the name of the NPM module affects the name of the thing extending Joi in any way, really. Validation is useful for lots of things, and the same name can mean different things in different contexts. Namespacing is a troublesome solution, but extending separate instances seems like a clean way around it... I'm not sure you do understand it, since throwing an error is out of the question. It's not a mistake so much as a circumstance that can arise as a result of two separate modules using Joi for validation. It's not about describing a model and manipulating it from two angles, it's about the fact that node.js modules are inherently singletons, so you run into namespace problems when you use multiple distinct modules that utilize joi for validation... |
Let's take your mongo example as a base. It extends Joi with a type called 'user'. Say you add in something like Passport, which has also utilized Joi for validation and has a 'user' type of its own with a different meaning. You, as the developer, can do nothing about the fact that you're using two modules that want the 'user' namespace, but only one is allowed to have it, unless you do evil things with the path structure which leads into undefined behavior. It's not an error that the mongo module is defining 'user', and it's not an error that passport is defining 'user'. Throwing doesn't solve it, and the developer has no tools to solve it either. Allowing the modules to utilize their own individual instance of Joi, however, cleans this kind of scenario up nicely :) |
@myndzi This can easily be solved by the authors of the modules by choosing more unique names like |
I perfectly understood the problem thanks. I'm trying to find alternatives to that, because what you're proposing doesn't make sense to me. If you inspect your API, you will find several validations with the same type but not the same underlying concept, that bothers me. I have not made this proposal just to offer my own version of custom functions, which would be much simpler if you look at previous PRs about it. Joi is also built for documentation through code, I intend to keep it that way. Now we could introduce an optional |
Any thoughts on alias support? |
What do you think if |
So a module would create a Joi type and export it, so you can add specific types to your custom Joi? Something like this? var mongoUser = require('joi-mongo-user');
var passportUser = require('joi-passport').user;
var Joi = require('joi');
// either this
Joi.user = mongoUser;
Joi.passportUser = passportUser;
// or this
Joi.user = passportUser;
Joi.mongoUser = mongoUser;
module.exports = Joi; joi-mongo-user module.exports = Joi.createType({...}); joi-passport module.exports = {
user: Joi.createType({...}),
otherKey: Joi.createType({...})
} I like it. Although I still like the idea of |
I've updated the proposal, see the diff in https://gist.github.com/Marsup/14597d0c8eaa10c4addb/revisions. |
So |
If anyone is still interested it's published on tag 9-beta, still waiting for feedbacks... |
I'll look at it next week! :) On Thu, May 5, 2016, 4:26 PM Nicolas Morel notifications@github.com wrote:
|
I'll be ready to test it in a week or two. Sorry for the delay. |
From documentation I would expect, that when
|
@peterslivka have any real use case ? It feels like your base should be Any. |
Yes, with
|
So you don't trust your own code to return the type you want ? That doesn't seem like a valid use case to me. I feel like this is the kind of rule that should be checked in your tests, not in joi each time a validation runs. |
Current boolean validator also covert "yes" or "on" string to |
I really like this but I don't see a way to extend everything in one go. Maybe this was by design? If I extend
without defining multiple custom Joi objects for each type via |
@peterslivka ok, I was trying to minimize the number of hooks but you might have a point. |
@Marsup one possibility would be cloning |
@peterslivka another beta out (9.0.0-4) with a new |
@Marsup The coerce hook is very useful (and necessary!). Great addition. |
Just broke the previous contract in 9.0.0-8 because it seems people do weird things with Joi, you now always have to return the value in extension functions. |
I converted my plugin/extension to use the values instead of null and everything still works great. 👍 Easy change. |
Are there any plans to make async validation possible in the validate function? I saw some older discussions about this subject in the repo but don't know what the plans are for the near future? |
It's planned. Can't promise it's "near" future. |
Is there any possible approach for async? |
I vote for Bluebird. |
Any updates on this ? |
Hi everyone, any news ? :) |
Is there any update on adding async validation? |
This issue seems abandoned, so I made a little side project to handle async validation with a syntax pretty much similar to Joi, if you are interested: https://github.com/bodinsamuel/altheia |
It's not abandoned, you're just all commenting on an issue that's been closed forever and everyone moved on to another, namely #1194. |
See https://gist.github.com/Marsup/14597d0c8eaa10c4addb for latest version of the RFC.
The text was updated successfully, but these errors were encountered: