-
Notifications
You must be signed in to change notification settings - Fork 430
Support nullable #522
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
Closed
Closed
Support nullable #522
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| export const input = { | ||
| type: 'object', | ||
| properties: { | ||
| foo: { | ||
| type: 'string', | ||
| nullable: true | ||
| }, | ||
| bar: { | ||
| type: ['string', 'number'], | ||
| nullable: true | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| { | ||
| "name": "Nullable adds null to type", | ||
| "in": { | ||
| "$id": "a", | ||
| "type": "object", | ||
| "properties": { | ||
| "foo": { | ||
| "type": "string", | ||
| "nullable": true | ||
| }, | ||
| "bar": { | ||
| "type": ["string", "number"], | ||
| "nullable": true | ||
| } | ||
| }, | ||
| "required": [], | ||
| "additionalProperties": false | ||
| }, | ||
| "out": { | ||
| "$id": "a", | ||
| "type": "object", | ||
| "properties": { | ||
| "foo": { | ||
| "type": ["string", "null"] | ||
| }, | ||
| "bar": { | ||
| "type": ["string", "number", "null"] | ||
| } | ||
| }, | ||
| "required": [], | ||
| "additionalProperties": false | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This won't work in all cases, since not every schema defines an explicit
typefield.For example, consider the following schema:
The expected output would be:
But with your code, we wouldn't emit
| nullbecauseschema.typeis not defined.I'd suggest a more general approach using
anyOf, similar to what @goodoldneon started in #411. The place to start would be to write a bunch of tests to make sure you're handling all the cases aroundanyOf: titles, properties, etc.Uh oh!
There was an error while loading. Please reload this page.
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.
Cheers for the review.
The key reason I think we should not use
anyOfis that these two are not equivalent when it comes to validationThe following object will fail for 1, but succeed for 2:
I realise that currently your library resolves to the same thing for both:
But I'm not sure that's correct. In any case, perhaps it's best for the normalizer to resolve to the correct json schema equivalent, which for
nullable: trueis 1.If I were to add a check for the
propertiesproperty, and infertype: 'object', would that work? Are there any other edge cases I'm missing going down this route?Uh oh!
There was an error while loading. Please reload this page.
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.
Yep, this is a separate bug for sure!
This is tricky, since when it isn't explicitly defined,
typeis inferred based on a set of heuristics. Defaulting toobjectwould introduce| objectto emitted types for any input schema that doesn't explicitly supply atype, which would be a bug. (Try making the change and see how tests break.)The AJV docs are a little unclear to me, to be honest. If my schema is:
{ "type": "string", "enum": ["a", "b"], "nullable": true }Clearly my intention is to say "this schema can be
"a","b", ornull". I wonder why the AJV interpretation is "this schema can be"a"or"b", and notnull".Either way, some possible solutions:
anyOfinstead oftype. Adjust your normalizer rule: if a schema has bothenumthat does not includenullandnullable: true, emit a warning that this is a user error and the user should fix their schema, then proceed to normalize toanyOf(schema, null). Same forconst, per the AJV docs. We could then separately fix the bug you called out, where iftypecontains a type not captured by theenum, we should normalize away the excesstypeand emit a warning about the likely user error.type. Add a normalizer rule to infer an explicittypefor each schema -- essentially, hoisting part of our heuristics to the normalization phase. This may be a pretty big change, and tricky to get right.Open to other ideas, if you have.
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.
Thanks! I found this while looking for further background on the behaviour AJV have adopted with this OpenAPI extension: https://github.com/OAI/OpenAPI-Specification/blob/main/proposals/2019-10-31-Clarify-Nullable.md
It seems that although this is still in proposal stage, AJV have decided to follow the recommendations. Even as far as throwing an error when attempting to compile a schema where
nullable: trueis used without atype: https://github.com/ajv-validator/ajv/blob/1b07663f3954b48892c7210196f7c6ba08000091/spec/options/nullable.spec.tsIs it best to follow this do you think? If so I think the current behaviour matches it, but I can add the same test scenarios as this ajv spec. Perhaps emit a warning where AJV throws an exception?
p.s. I do actually agree with you, to me it would seem more intuitive for
nullable: trueto just allow for null regardless of the rest of the schema.