Open JamesHinshelwood opened 3 years ago
Also very interested in 3.1.x support. @JamesHinshelwood I'd be down to help out if you start working on this 😎
Support for 3.1 is going to be great. It would necessitate a pretty significant change to how this crate functions. In particular, this crate just defines some structs (and enums) and lets you serde_json your data into them. (Oddly, given the numbering) 3.1 was an incompatible change. For example in 3.0.x the exclusiveMaximum
was of type boolean; in 3.1 it's a number. There are some other differences: https://github.com/OAI/OpenAPI-Specification/releases/tag/3.1.0-rc0
The key benefit of 3.1 (IMO) is that it brings OpenAPI into closer alignment with JSON Schema. As such, I'd like to see an OpenAPI 3.1 crate that uses a JSON Schema crate as part of its implementation (whereas this crate currently defines its own schema type). Unfortunately, the best JSON Schema crate I've found (https://github.com/GREsau/schemars/) is only sporadically maintained.
There are some key questions:
{ "type": "null" }
while there's no way to represent this in 3.0.x. Presumably serialization could fail with some error type...On all three of those questions I'd love your input: @JamesHinshelwood and @blazeworx
And with respect to @glademiller, I think that if I were to invest time into a 3.1.x crate I'd ask for your blessing to fork this crate into my employer's org and publish under a different name.
With OAS 3.1 bringing OAS schema closer to JSON schema, I too think that building something that uses schemars
might make sense.
One thing to consider is that schemars
itself has "generating OAS 3.1 schema" support on its Road map to 1.0. Not sure how that will end up playing out and what that will look like.
As far as your questions go, I think the answer for all of those depends on wether or not this should be a standalone 3.1.x only crate or not?
As far as your questions go, I think the answer for all of those depends on wether or not this should be a standalone 3.1.x only crate or not?
Yeah! For my recent uses, I'd prefer to have a crate that could deserialize from either 3.1 or 3.0. I'm only really interested in writing out 3.0.x now because 1. there isn't that much value in 3.1 and 2. the tooling for 3.1 is anemic right now.
What would you like to see?
To answer what would be desired from my side... All I would want is to serialise and deserialise 3.1.x OpenAPI documents. The only other bit of tooling we're using is Redoc, which already appears to be updated to 3.1.x.
However, I obviously wouldn't object to this crate supporting some combination of both 3.0.x and 3.1.x if that's helpful for others.
@ahl For your use case (deserialising from either 3.0.x or 3.1.x) do you think it would be sufficient to write a mapping to convert between v3.0 and v3.1, then write something like
let api: OpenAPIv31 = serde_json::from_str(api).or_else(|_| convert_to_3_1(serde_json::from_str::<OpenAPIv30>(api)));
(or vice-versa if you want to end up with a 3.0 document of course)
This would let us keep the v3.0 and v3.1 types separate while still providing some level of interchangeability?
In terms of borrowing an existing JSON schema implementation, I think it would make sense to do so if an appropriate one is available. If not, it probably makes sense for us to create one separately from this crate? What were your objections to https://github.com/GREsau/schemars/ ? It looks reasonably well maintained to me?
I had a go at adding support for 3.1.x in a branch here - https://github.com/JamesHinshelwood/openapiv3/tree/openapiv3.1
The basic approach is that we have entirely distinct OpenAPI
structs for 3.0 and 3.1, plus an enum at the root of the crate to differentiate them. I'm not entirely happy with the approach, as it can be slightly annoying when importing stuff to have to chose between v3_0
and v3_1
but maybe we can solve that by enabling each with a feature flag, so only people using both will be bothered?
For schemas, I'm using Schema
from schemars which seems to work pretty well.
Let me know what you think! I have no attachment to the approach, just wanted to see what it would look like in practice.
I'll try and find some 3.1.x test cases to validate this. I had a go at the 3.0.x fixtures and all seemed to pass with the 3.1.x deserializer, except for authentiq.yaml
- I didn't yet investigate why.
I like the implemention of OpenAPI 3.1. But is it really a common use case to use both 3.0 and 3.1 at the same time? I would guess not, so I want to suggest to release 1.0 with support for 3.0 and 2.0 with support for 3.1
But is it really a common use case to use both 3.0 and 3.1 at the same time?
From a server's perspective? No
But from a client's / tooling's perspective that needs to deal with whatever version the server returns, I'd guess having support for as many versions as possible at the same time is desired.
Thanks for the positive comments. I will try and find some time in the next week to clean up my branch and submit it as a PR here so we can get some proper feedback.
I just found this and, I too, am very interested in 3.1. Is there anything that I can do to help move this along?
The basic approach is that we have entirely distinct OpenAPI structs for 3.0 and 3.1, plus an enum at the root of the crate to differentiate them. I'm not entirely happy with the approach, as it can be slightly annoying when importing stuff to have to chose between v3_0 and v3_1 but maybe we can solve that by enabling each with a feature flag, so only people using both will be bothered?
After attempting to create a code-generator using the result, I am having serious second thoughts about the approach.
Switching between the two versions at the top of the document isn't the problem. It's the fact that I have to implement two distinct, but nearly identical code generators for the v3.0 and v3.1 versions. Every single type is different.
We need to unify these somehow. I'm not sure if traits are the way to go, or if there is something more clever here.
So far, I think the best approach would be to provide a way to "pull" the 3.0 implementation "through" the 3.1 implementation.
This could be done with a trait. I am thinking an As<T>
trait might be the most flexible. E.g. all of the v3_0:: and v3_1:: types, T, would implement As
I've already implemented From<T>
for most of the implementation, so if this is the preferred direction, I will convert the From's to As's to provide a reference based approach for both structs.
I haven't prototyped it, but my plan with https://github.com/oxidecomputer/progenitor is to convert the 3.0.x import into 3.1 at the root and use that. I'm already converting from openapiv3::Schema
into schemars::Schema
(in order to use https://github.com/oxidecomputer/typify) so I'd get to just delete all that code.
The more I think about it, maybe the From<T>
is the best approach.
So, as you say, just convert at the beginning. With this in mind, we should probably borrow your v3.0 -> schemars::Schema to correctly implement the From<v3_0::Schema>
, since it is rather involved.
FYI I intend to make a concrete proposal year in January at the latest. Agreed that 3.1 support would be great. I'm increasingly convinced that relying on schemars
is the wrong approach due to its lack of support for the relevant JSON Schema draft and sporadic maintenance of the repo. Moving this repo may also be worth consideration.
I have a fork of this crate at https://github.com/kurtbuilds/openapiv3 , and recently added support for V2 and transforming (1 way) from V2 to V3.0. That structure might be good inspiration for eventual V3.1 support.
If I can help pull things through I'm happy to lend a hand here. There are some great crates that currently can't support 3.1 because of the lack of support here.
@ahl Did a proposal ever end up being put forward?
Would be amazing to see progress on this.
FWIW to readers of this issue, the oas3
crate is specifically an OpenAPI v3.1 crate.
OpenAPI v3.1.x has some features that would be desirable for us. So it would be neat if this crate could parse OpenAPI v3.1.x documents.
I'm not sure what the best approach for this would be though, particularly if we want to maintain support for OpenAPI v3.0.x in some form. Perhaps a separate variant of
openapiv3::OpenAPI
(maybe behind a feature flag) used for representing v3.1 documents instead of v3.0 ones?Would v3.1.x support be something you'd consider adding to this crate at all? I'd be willing to put in the work if so :)