-
-
Notifications
You must be signed in to change notification settings - Fork 209
const is validated by fjs, add strict mode #579
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
Conversation
@Uzlopak and everyone else. I finished a discussion with @Eomm on |
Before i finish this PR i want to come to a conclusion. I know it is not viable. I would actually add a deep compare function for that. I know that this is basically the case were we always come to the conclusion on what the purpose of this PR is. Here i purposefully also used ajv validator as compare function instead the is-my-json-valid, to show that we diverge from the behavior significantly. E.g. {
type: 'object',
properties: {
foo: { type: 'string', nullable: true, const: 'bar'
}
} If we use this schema and use following payload: { foo: null } Then JSON.stringify returns Imho fjs has to either return the same value as json.stringify or need to throw an error. The current behaviour can imho not be correct. |
I think we have different visions that could be summarized to:
Did I miss some cases? ** even if the produced string output does not match the json-schema |
Yeah basically. |
56d087d
to
f00533a
Compare
WELL! I wrote a function which based on the const value generates validation code. I oriented myself on fast-deep-equal. Basically it generates branchless code for validating the input. Maybe this helps to expedite the discussion regarding #532 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my point of view trying to validate all types and throwing an error it's the wrong way. You will inevitably run into validation problems. Why do constants throw an error while other keywords don't? I think that we should use constants when it can speed up serialization, and if the value is not equal to a constant we should fallback to default serialization by type.
I would rather build a serializer which completly validates the input based on the json schema than have a serializer, where I provide a whole schema and in the end only a small part of the schema is actually used. When I write that a field of an input-object has a const value of x, then I expect that it is set accordingly on the input and doesnt get serialized anyway nor how it is done currently with a value which is not set. |
The problem is that we can't build a serializer + validator without having a significant performance drop. Yes, it might work faster than serializer and validator separately, but it will work much slower than the serializer by itself. Basically, you want to rewrite ajv and merge it with fjs, right? |
Maybe it makes sense, to design all those issues as "plugins"? So instead of having here the big discussion regarding what the goal should be, we could have another option So if somebody wants to enable maxLength or minLength validation, just set validate.minLength or validate.maxLength accordingly to true. |
Yes, I'm ok with a solution like that. You can see that in the discussion with @Eomm, we discussed "strict" and "non-strict" versions of fjs. It has something similar with what you suggest. The questions are:
|
In #600 I encapsulate the whole context in a variable. If that gets merged, I could instead of in line 859 |
t.equal(output, '{"foo":"bar"}') | ||
t.ok(validate(JSON.parse(output)), 'valid schema') | ||
t.equal(stringify(input), '{"foo":"bar"}') | ||
t.ok(validate((input))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are validating our test code here
t.ok(validate((input))) | |
t.ok(validate(JSON.parse(output))) |
|
||
t.equal(output, '{"foo":"bar"}') | ||
t.ok(validate(JSON.parse(output)), 'valid schema') | ||
t.throws(() => stringify(input), new Error("The value of '#/properties/foo' does not match schema definition.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, I agree to throw behind an option or plugin
in general, my opinion with FJS, it should never throw/validate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it does not throw, what should it then serialize? just doing JSON.stringify(input) ?
t.equal(output, '{}') | ||
t.ok(validate(JSON.parse(output)), 'valid schema') | ||
t.equal(stringify(input), '{}') | ||
t.ok(validate((input))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should validate the fjs output
I am currently trying to implement some other keywords like
Just to get the feeling on how we can implement it properly. Already enum is pain in the ass, because somehow i get an additional But looks good so far. |
I thouht alot about this. I think the biggest issue is, that if we have a big array or object, than the generated validator will be vey big too. So I wonder how ajv solves this issue. But how fast-json-stringify does with const is also very wrong :/ |
ajv basically stores the schema and builds the validator based on the schema. So it is basically ok, what i implemented here. Maybe it makes sense to optimize further for arrays. |
By having the context now passed through, it was easy to implement a strict mode. |
Defining features such as strict mode is an important decision for a library. If you really want to add it, you should think very carefully so as not to create undesirable consequences.
|
I am not saying that this PR is ready. I am just shuffling the code to determine the next step. E.g. @Eomm wrote that it we should not throw. But required keyword is throwing. So should we make required non-throwing? |
It depends on what you want to archive. I don't understand. That is why I'm asking. It's hard to say the correct answer without input conditions. Everyone might understand strict and unstrict modes differently. What are your definitions of strict and unstrict mode? |
@ivan-tymoshenko @Eomm |
Ok, I think that idea of configuring rules is a good compromise. I think we should create another issue and discuss it there. |
Another part of the question is how the unstrict version of FJS should work. When it should throw an error, when it should ignore some input data, etc. |
Any body who wants to work on this further is invited to do so. But closing it as at the current time there is no eta nor a active discussion. |
Discussion is not a real-time chat, but it could take weeks or months. I don't want to be the one who says "no" nor stops the progress, but AFAIR, I did not read any proposed plan - did I miss it? |
A new @Uzlopak idea: incremental validation: #579 (comment). IMHO, this could be a compromise solution. It allows us to have an existing Fastify configuration. The question is how far we want to go with it. I don't really want to reinvent the Ajv. |
This is what I would expect from fast-json-stringify. Probably needs heavy discussion as it is heavily breaking change.
Checklist
npm run test
andnpm run benchmark
and the Code of conduct