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
Astronomy 2.0 Validation #251
Comments
Since I have been thinking about similar things working on SimpleSchema v2, here are my thoughts:
|
|
I'm hoping that someone can build a form package that will be compatible with all kinds of different schema/model packages. One necessary thing to do is to standardize how errors are reported. |
Also, this means that I can write a forms section for the Meteor Guide that is compatible with Astronomy. |
@stubailo If we want to have forms package that would be compatible with all kinds of schemas packages then MDG would have to provide some base that we should build upon. Right now I have this problem that I don't know where is Meteor heading. It's changing too fast its core principles to keep up with packages updates. However, if it goes about |
Would it not have been just awesome if astronomy and simple-schema/collection2 shared some common definitions, for example a schema format (JSON schema?) and a common extensible custom validator registration API (which would then allow @aldeed to get rid of functions) Astronomy and simple schema / collection2 would then depend on that common base to improve in their own opinionated directions. |
ValidationError is the first of those. By not putting it inside the Meteor repository (which we will do with more and more core technology in the future), we are actually making it easier to iterate and make improvements. We're going to remove the SimpleSchema dependency. What else do you need? Perhaps we can make it happen. Since you and @aldeed are the two most prominent schema-related package authors right now, I can't think of anyone else who is in a better position to agree on a schema definition language going forward. |
Also, to clear up what I can do here, @justinsb and I are the newly formed Data Team here at MDG, so we're going to be focused full-time on making Meteor's data system better than ever before. It's great already I think, but it hasn't seen significant improvements in 2 years or so, and we want to get on top of that. |
@stubailo Ok great! So if we are in the subject of schemas/models. Is MDG planing any GraphQL integration? Should be consider supporting it? What are your plans if it goes about improvements to data system? |
We're hoping to announce our near-term plans in 1-2 weeks, I'm sure we can cross that bridge when we get there. If you guys can agree on a single schema format, I'd guess it will be the main one for Meteor for at least 6 months to a year, and will probably still be relevant in a lot of places even when something related to GraphQL comes about. I don't know if you've seen GraphQL definitions, but they are quite verbose for simple things. |
Ok, can't wait what are you planning. |
Currently we aren't thinking about models, it's mostly about the data loading mechanics. If we start thinking about models, we'll make sure to reach out to the relevant people, yourself included. |
Oh I see. That's nice :) Thanks! |
@aldeed so maybe let's arrange Skype/Hangout meeting, so we can talk about what our plans for SS2.0 and A2.0 are. Maybe we will be able to come up with similar way of defining schema and validators. Even if not, it's always nice to share experience :) |
@jagi Sounds good, I will email you. @serkandurusoy Functions and custom validators are probably the one thing that can't be reconciled between packages because SimpleSchema needs to provide information about and have logic for validating modifiers. The extensibility of the schema options and packages like autoform which read them for alternative purposes add to the mess. We may be able to get the rest of the schema syntax pretty close, but to me JSONSchema is too verbose, and I think |
I get the complexities and pain points involved. But then, conversion packages may be even more dangerous because there is no bidirectional and one-to-one mapping, furthermore a they may fall behind as the contenders move along. Even add-ons have such problems. For example, I'm an avid user of autoform and have tried out semantic and materialize templates only to find out as autoform progressed that I need to either maintain the template add ons myself or revert back to the autoform default bootstrap because that's what is maintained in line with the core by the core developer. The point is, if we want astronomy and ss/c2 codebases to communicate well the only realistically viable option would be for them to actually share common code. I fear other strategies would only render futile as they progress in different directions. Furthermore, I also believe that such common core should be provided by a core meteor api so that noone can easily choose to ignore it. |
@aldeed Ok I will reply to your email and we will arrange a meeting. fields: {
firstName: String,
tags: [String],
address: Address
} However it does not mean that we will have 1:1 schema definition. I think it will be on my side to create conversion package. Something like |
Hmm, I think it could be a good idea to borrow some schema definition ideas from GraphQL. Like Geoff said in his forum post recently, we are investigating ways to use GraphQL to improve Meteor data loading, and it will be nice if you can just write your schema once and get a GraphQL endpoint out of it as well! |
I think it could be something like |
Sounds awesome. |
I think having an option to run certain validators on certain type of operation would also make sense. Like if we are able to declare a validator for 'insert' only or 'update' only. By default they would run on all type of operations. |
Have you considered something like this for custom validation functions? Having access to other fields is something I needed sometimes in my current validators: function(field, fields) {
// field.value; field.isSet
// fields.fieldName.value; field.fieldName.isSet
} |
@zimt28 and how would it work? Does it does something that is not possible with the way I've provided? |
@jagi I just didn't see a way to access other fields. Or would they be available via Tell me if the following is far away from how you'd actually use Astronomy, but the code would look like this: {
password: {
type: 'string',
optional: true
},
passwordConfirmation: {
validators: function (field, fields) {
var password = fields.password;
if (password.isSet && field.value !== password.value) {
throw new Astro.ValidationError({ validator: 'passwordMismatch' });
}
}
}
} |
I agree with @zimt28. Being able to use other fields in validation of a field can come in handy. I think you can still manage this by using a hook like BeforeSave, but it would be messy and pertains to validation so should be a part of the validation function signature. |
@zimt28 @talha-asad yes I will probably provide access to the document using context ( |
@jagi Sounds good 👍 If we could have something like `.isSet(fieldName)`` on the document level it would make sense. Sometimes you want to run a validation only if the document has something explicitly set and not a default value. |
@jagi @talha-asad What I like about the syntax I posted above is that it doesn't use the context ( The examples at the very top use both |
@talha-asad for that purpose there will be a method @zimt28 I can't agree on that. Let's imagine a situation when we have arguments I agree that using context is not always the best option and maybe I will just provide the |
@jagi I see. I'm currently using SimpleSchema and planning to make the switch with Astronomy 2, so all my thoughts are based on that background. You're right, having too many arguments doesn't improve the syntax. However, try it and let us know what you come up with :) My point is just that I'd like a consistent way to access fields 👍 |
Yes I agree. In events system in Astronomy 2.0 I'm using the |
I like the approach but i don't understand what would |
I think I will use similar approach if it goes about validation to allow access to the parent document from the validator of the nested document. |
I'm in the middle of work with validation. I haven't been able to finish all things that I wanted. So just give me one more day. It's much more complicated than I thought it will be. |
No rush jagi. Take your time. Good things take time. 👍 Thanks for the explaining the events, though i was thinking what will happen if a field is double nested inside a document. Will you still be able to access the root document as it won't be possible using |
|
Couple thoughts for posterity:
my function
will be run (again just using some kind of validator function registration api. Options should be able to be arbitrarily complex, and since I can define methods on an Astronomy model, if
|
I would agree with @ianserlin last point. Using |
@ianserlin @talha-asad right now context of the validation function is set to the default one provided with the function. All necessary parameters are passed to the function as arguments. It's only a matter of choosing if it should receive some @ianserlin If it goes about custom validators, in deed, it can solve a problem of passing function to validation. However, I don't care about that. We can pass functions. It's especially necessary in the |
I wonder if it's possible to add more custom error message support. Right now I think for most of the built-in validators the error message are developer-centric. But I feel it will be nicer to show more understandable error message directly to the end user. The best thing I can think of is to have "field-level", "validator-level" and "document-level" custom error message support. Taking the sample code of v2.0 that you wrote above as example, I think it'll be nice if we could do: validator-level custom errror message firstName: {
type: 'string',
validators: {
minLength: {
args: [3],
error: 'The minimum length is 3'
}
maxLength: 20
},
}
// Or
firstName: {
type: 'string',
validators: {
minLength: 3,
maxLength: 20
},
error: {
minLength: 'Firstname should contain at least 3 characters'
},
} field-level custom errror message firstName: {
type: 'string',
validators: {
minLength: 3,
maxLength: 20
},
error: 'Please enter a valid firstname'
} document-level custom errror message {
fields: {
firstName: {
type: 'string',
validators: {
minLength: 3,
maxLength: 20
},
}
},
error: 'The validation fails'
} I know it's a lot of work..., but hopefully it will make the validators more flexible :) |
It would definitely make code much more complicated. Of course it would be much more flexible. In Astronomy 1.0 there is the The problem with your syntax is that it would be almost impossible to distinguish if an object passed to the validator is the validator's definition or the validator's param. I will explain it in more details: There are validators where you have to pass object as a param. firstName: {
if: { // it's an object param passed to the validator
condition: function() {},
true: /* ... */,
false: /* ... */
}
} and if you would want to pass object with the error message, then it would make hard to distinguish if it's a param or validator's definition. firstName: {
if: {
param: { condition: /* ... */, true: /* ... */, false: /* ... */ },
message: 'Error message'
}
} I don't want to make to many checks of arguments. But I will think about a better more flexible approach. |
Thanks for your explanation! I was unaware of the However, I believe that syntax could cause unclearness when you have lots of fields and want to lots of custom error. As inspired by your last comment and the existing firstName: {
type: 'string',
validators: {
minLength: 3,
maxLength: 20
},
error(e) {
// 'e' is the validation error event where e.data.fieldName = 'firstName'
switch (e.data.validator.name) {
case 'minLength':
return 'the minimum length ...';
case 'maxLength':
return 'the max length ...';
default:
return 'the default error';
}
}
} It works in consistent with the existing |
The most obvious way of generating or just passing error message would of course be your first proposal about passing object a few properties instead just only param. However, as I said it may cause some problems but I will investigate this issue further. The idea, you've proposed in the last comment seems to be quite nice however you still need some switch-case of ifs. It would definitely be nice to have ability to just provide string error to each individual validator. In fact, it was possible in 1.0. The validator function was taking error message as the last argument. However, that approach was a lot more complicated from the code level and required a lot more of code to be written to define validators. |
Yeah I totally agree with you. And the ideas of passing the error message as the last argument also came across my mind before. And right, it is applicable for validators defined in the format of v1.0. For the last comment I made, I feel it's a good tradeoff. Of course you must have done much more research than I do, and I'm sure you will come up with a great choice. I also like the idea about having consistent schema definition and/or error handling from the discussion above. Really hope you guys could reach a consent on that topic. |
Ok validators are working, not everything is implemented yet but there are several things that needs discussion. First I will present you what ideal syntax for defining validators would be which will be very hard to implement. And the second example is a syntax that is easy to implement, does not require a lot of checks but requires a little bit more code to write. Ideal syntax fields: {
firstName: {
type: String,
validators: { // Single validator with the param
minLength: 5
}
},
lastName: {
type: String,
validators: { // Multiple validators with params and custom error message
minLength: {
param: 2,
message: 'Too short'
},
maxLength: {
param: 10,
message: 'Too long'
}
}
},
birthDate: {
type: Date,
validators: { // Validator with the function that resolves to the param
lte: function() {
let date = new Date();
return date.setFullYear(date.getFullYear() - 18);
}
}
}
} Easy syntax but more code to write fields: {
firstName: {
type: String,
validators: [{ // Single validator with the param
type: 'minLength',
param: 5
}]
},
lastName: {
type: String,
validators: [{ // Multiple validators with params and custom error message
type: 'minLength',
param: 2,
message: 'Too short'
}, {
type: 'maxLength',
param: 10,
message: 'Too long'
}]
},
birthDate: {
type: Date,
validators: [{ // Validator with the function that resolves to the param
type: 'lte',
resolveParam: function() {
let date = new Date();
return date.setFullYear(date.getFullYear() - 18);
}
}]
}
} I've added comment for every Single validator with the param The validators list has to be an array of objects instead of just an object. So, we have to provide validator Multiple validators with params and custom error message Here more important is custom error message. Because as we discussed above, we just provide array of validators so multiple validators is nothing special here. However, if it goes about custom error message, we only have to provide the Validator with the function that resolves to the param Another very important thing when taking about validators is ability to resolve parameter during validation instead of class creation. Thanks to that we can for example validate the SUMMARY So the question is: Do you like the second syntax? I know it's not ideal but will cover more situation you can deal with and more over it will be less error prone. Just would like to here your opinion. |
Yeah it looks like the second one has more consistent syntax and easier to understand, but more verbose too. I am okay with both syntax and I think they almost make equal sense to me, but after reviewing both proposals, I tend to like most of the last proposal I made about using field-level error event. I think one criterion to decide which syntax to choose is what makes helps productivity most in the real world scenario. I'm taking my work flow as an example (and I assume most people work in a similar manner). Initially, in the development phase, I want to define the model quickly, concisely and accurately. Then your original proposal for validator 2.0 will shine here: firstName: {
type: 'string', // or String
validators: {
minLength: 3,
maxLength: 20
}
} This code works perfectly for my need. In this phase I won't care about what how beautiful the error message is as long as it helps me identify the error. So I won't bother writing custom errors. Then after I have tested the model enough times, and decide to go for production, then I will start to care about UI/UX thing, and want to customize the error messages. And I want to make sure the core validation logic to remain unchanged. So having the ability to just that one extra attribute firstName: {
type: 'string', // or String
validators: {
minLength: 3,
maxLength: 20
},
error(e) {
switch (e.data.validator.name) {
case 'minLength':
return 'The minimum length is 3';
case 'maxLength':
return 'The maximum length is 20';
default:
return 'Some error happened';
}
}
} Also, in fact what you just proposed is more of a validator-level custom error, and it should work in harmony with the field-level error event. So I guess probably we could have both in case people have different preferences? |
Generating validation error is another thing. Of course it can be just string message or function that gets resolved to the string message. I could introduce two properties The thing that I've mostly wanted to focus in my previous comment was also ability to provide |
I am happy with the second approach. It's not like i would be writing models all the time that i would really be willing to save up on coding bytes. However if we could have the first approach i would be all for it, as long as it doesn't cause other problems. |
Ok validators are working. There are two more little things to work. You can test it out in RC.1. I'm closing this issue |
Hi, the astronomy package has program "validator" methods, however, what does the user define with the schema? It is a declarative definition.
|
Every field is required by default so you don't require anything. If you want to make field optional you do: fields: {
email: {
type: String,
optional: true
}
} You do not require something to be null. However, you can create more complex validation rules where field value can be null in some situations depending on another field value. |
Could you confirm that this kind of complex validation is not yet implemented into the v2 ? anotherField: {
type: 'string',
validators: {
if: {
condition: function() {
return this.field === 'abc';
},
true: { /* some validators */ },
false: { /* some validators */ }
}
}
} |
There is no |
When validation depends on a field's value of the object instance being evaluated how do I get the document instance in the customer validation creation? Validator.create({
name: 'maxLength',
parseParam(param) {
if (!Match.test(param, Number)) {
throw new TypeError(
`Parameter for the "maxLength" validator has to be a number`
);
}
},
isValid({ value, param }) {
if (!_.has(value, 'length')) {
return false;
}
return value.length <= param;
},
resolveError({ name, param }) {
return `Length of "${name}" has to be at most ${param}`;
}
}); |
`isValid({ doc, value, param }) {` everything is in documentation
On Dec 13, 2016 9:07 PM, "Frank Pimenta" <notifications@github.com> wrote:
When validation depends on a field's value of the object instance being
evaluated how do I get the document instance in the customer validation
creation?
Validator.create({
name: 'maxLength',
parseParam(param) {
if (!Match.test(param, Number)) {
throw new TypeError(
`Parameter for the "maxLength" validator has to be a number`
);
}
},
isValid({ value, param }) {
if (!_.has(value, 'length')) {
return false;
}
return value.length <= param;
},
resolveError({ name, param }) {
return `Length of "${name}" has to be at most ${param}`;
}
});
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#251 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABAKXX_FGmc10EpPiwH0E2pDB6kSGeNLks5rHvsCgaJpZM4G_4nF>
.
|
I found it later. I'm sorry for it. |
No problem |
Hi, I'm designing validation API for Astronomy 2.0. Validation will be performed automatically on every save but it will be possible also to perform it on demand without saving. The problem is that validation API in 1.0 was not intuitive. I would like to come up with the best possible approach that would satisfy almost everyone and would be full featured. First I will present my ideas and I want to hear your opinion on it.
Field validators
Field validators are assigned to the given field. Each field is required by default (should it be required by default?) so you don't have to add
required
validator. Let's take a look at the simplest way of defining validators:I think it's much better way of defining validators then in 1.0 which was:
All validators are registered in the
Validators
namespace so we can add theValidators.
prefix during validation. All validators for a field has to pass for the field to be valid.More complex validation rules
But what if we want to have more complex validation rules for a field? One way would be using similar approach as in Astronomy 1.0 but without the
Validators.
prefix. Sometime it looks like MongoDB query so I think it's a good direction.Custom validation function
However, I think that the best solution that would be the most flexible is providing function and throwing validation error by ourself.
Of course, we have to write more code but it's required to properly generate validation error message. You have to know that all above validators were field validators. So if we execute:
It will run all validators for the
firstName
field. But what if we want to have both standard validators and function validator.Combining standard validators with function validator
Document validator
I was also think about document level validator. Which would only be called on save or when validating entire document with
doc.validate()
. Such validator would be provided in the form of function. But I don't know if there is a need for document level validators. Developer were able to use Astronomy 1.0 without document level validators. The nice thing is that having validator for thefirstName
field we can still compare it with thelastField
name which is done in document level validators. But it was possible with standard field validators in 1.0 and will be possible in 2.0.Throw validation error from any place
You can also throw validation error from any place like event. However you would probably choose
before
events. Let's take a look at the example.Thanks to that you can add validators that will only be executed during insert but not update. However, it will require more code.
Let me know what you think
The text was updated successfully, but these errors were encountered: