Open moberegger opened 4 months ago
For posterity, I have also created an issue in json_schemer
.
Thanks for the report, @moberegger.
openapi_first dereferences them out when creating the schemas
That is correct. I will have to take a deeper look if thatโs an issue here. Iโll have a closer look and will get back to you.
UPDATE: This is the issue exaclty. By resolving all $refs during load openapi_first basically breaks discriminator
. The OAS says : "When using the discriminator, inline schemas will not be considered."
Marking this as a bug.
Hey @moberegger I don't have a solution for this, but maybe a workaround: Maybe you can make use of one of the JSON schema conditionals instead of using discriminator
?
There is a discussion about replacing / removing discriminator in OpenAPI 4.0
Maybe you can make use of one of the JSON schema conditionals instead of using discriminator?
Haven't looked into this yet, so unsure if this would work; I am not too familiar with json-schema
so still need to wrap my head around it. Unfortunately, for my current situation it's not an option for legacy tech debt reasons that are not at all your problem ๐. We currently have another soon-to-be-deprecated pipeline generating the schemas and getting that to be "json schema aware" isn't tenable. Our schema is also 3.0, which from my reading doesn't have full compatibility with json-schema
.
I'm currently migrating our project to something green field (which your library has been an immense help with, by the way), and once that is done we'll have full control over the schema. Plan is to update the spec to 3.1 once it's all said and done, and then at that point I'll kick tires on your json-schema
suggestion. Again, none of this is your problem! ๐
For the time being, I made a patch to openapi_first
that removes the discriminator
from the schema before creating the validator.
module Schema
def initialize(schema, **kwargs)
super(clean_unions!(schema), **kwargs)
end
private
DISCRIMINATOR = 'discriminator'
UNIONS = [ALL_OF = 'allOf', ANY_OF = 'anyOf', ONE_OF = 'oneOf'].freeze
def clean_unions!(schema)
schema.delete(DISCRIMINATOR) if UNIONS.any? { |key| schema.key?(key) }
schema.each do |_, value|
if value.is_a?(Hash)
clean_unions!(value)
elsif value.is_a?(Array)
value.each { |element| clean_unions!(element) if element.is_a?(Hash) }
end
end
end
end
It's a bit of an aggressive approach, but has solved my problem for the time being.
I'd be more than happy to make a PR to openapi_first
if a strategy similar to the above is an acceptable solution that you'd be happy with, but I don't know if this would cause problems for you elsewhere. Given your comments in https://github.com/davishmcclurg/json_schemer/issues/192#issuecomment-2263774926, maybe this helps keep openapi_first
compatible?
I am happy to hear you found a solution to work around this issue ๐จ ๐๐ผ. Also appreciate the positive feedback.
I have not thought about it a lot, but I see two approaches solving this issue:
I feel like option 1 would be better, but I also don't know how to do that, yet.
So something a long the lines you did, but the goal would be to keep validation intact somehow.
I just realized I didn't explain what the patch did ๐. The patch I provided just "tricks" json_schemer
into not looking for the $ref
s and instead just has it validate across all the inline union types. There is definitely a tradeoff doing it this way, though; since it can't use the discriminator as a hint, I believe that the validator has to do more work since it has to validate against all the types rather than just the one the discriminator points to. I think this also results in more errors when validation fails, because you'll get multiple errors against each type instead of errors targeted to the type the discriminator points to. So it's still validating... but doing so in a much less efficient and intuitive way.
I do like your first option. In fact, that's how I thought openapi_first
was working before reading through the source before creating this issue! Wish I could be of more help here, but I'm still rather new to the Openapi specification so still trying to get up to speed on that.
Sincerely appreciate your responsiveness on this. If I learn anything new or come up with another idea, I'll be sure to let you know. Least I can do.
This should be fixed on main via https://github.com/ahx/openapi_first/pull/294. I am keeping this open until the fix has been released.
Can you give this a try @moberegger ? Thanks again for the report!
Tried it out and still see the unions being dereferenced. There are a couple differences between my setup and your integration test, though. One difference is that my union is nested inside other schemas and is not the top level schema response for the endpoint. The other difference is that we're using file references (ex: $ref: ./Dog.yml
) which may be impacting how it gets loaded (I noticed that this process has also changed on main
, so still familiarizing myself with it).
I'll try to dig in and see what is causing the difference in behaviour. It might be something I'm doing on my side that is causing the problem. If I'm able to figure out the root cause, I'll report back with a minimal reproduction/example.
The other difference is that we're using file references (ex: $ref: ./Dog.yml) which may be impacting how it gets loaded
Yes. And this should not work without using mapping
, because JSON Schema cannot deduce "dog" from "schemas/dog.yaml". I just added another integration test to reproduce an issue with that and fixed it. It now uses the ref_resolver option of json_schemer to resolve the $ref (PR).
My plan is to use json_schemer's ref_resolver option in more places and remove some code related to that.
If I'm able to figure out the root cause, I'll report back with a minimal reproduction/example.
Just a quick feedback on main or a reproducible example would be super great. I would like to add integration tests for these cases, solve them and then make the code easier to follow. โฆand have main change less frequently.
Ran into an issue with
oneOf
unions, but only when using adiscriminator
property. I am not sure if this is anopenapi_first
issue or ajson_schemer
issue, so I'd though I'd try here first.Given a simple YAML configuration like
and using the
ResponseValidation
middlewareand responding with some simple hardcoded data
The following error occurs
If I remove the
discriminator
property and just haveEverything works.
I dug into the
openapi_first
andjson_schemer
source a bit and what I think is happening is thatjson_schemer
expects those$ref
s to be there, butopenapi_first
dereferences them out when creating the schemas. I can see a response schema being created with the spec doc loaded asThe presence of the
discriminator
seems to triggerjson_schemer
to look for the$refs
. The tests seem to indicate thatjson_schemer
supportsoneOf
unions, but they suggest that it needs to be aware of the entire schema (or at least theref
s), where asopenapi_first
takes a modular approach and creates separate request and response schemas for each path.Again, don't know if this is an
openapi_first
problem or ajson_schemer
problem. It does seem likejson_schemer
expects the entire specification to be given to it, which is not howopenapi_first
is currently using it. That being said, this is the only issue I have run into thus far in a project that is making heavy use of$ref
s, so perhaps it's ajson_schemer
bug withdiscriminator
s because that shouldn't assume that$ref
s are being used.Perhaps instead of dereferencing, a ref map is created that can then be provided to
json_schemer