openapi-contrib / openapi-schema-to-json-schema

Due to the OpenAPI v3.0 and JSON Schema discrepancy, you can use this JS library to convert OpenAPI Schema objects to proper JSON Schema.
https://www.npmjs.com/package/@openapi-contrib/openapi-schema-to-json-schema
MIT License
242 stars 20 forks source link

Add an option to convert examples. #17

Closed gilbsgilbs closed 4 years ago

gilbsgilbs commented 4 years ago

According to the OpenAPI spec, there are two ways of providing examples for a schema⁽¹⁾:

As examples aren't supported in JSON Schema Draft 4, this library currently drops the example field by default and leaves the examples field untouched (which may produce invalid schemas I guess). Since JSON Schema Draft 7 however, it is possible to use the "examples" keyword ⁽²⁾:

9.5. "examples" The value of this keyword MUST be an array. There are no restrictions placed on the values within the array. When multiple occurrences of this keyword are applicable to a single sub-instance, implementations MUST provide a flat array of all values rather than an array of arrays.

This keyword can be used to provide sample JSON values associated with a particular schema, for the purpose of illustrating usage. It is RECOMMENDED that these values be valid against the associated schema.

Implementations MAY use the value(s) of "default", if present, as an additional example. If "examples" is absent, "default" MAY still be used in this manner.

This PR adds an option to convert OpenAPI's example and examples fields to JSON Schema Draft 7 examples.


⁽¹⁾ https://swagger.io/docs/specification/adding-examples/ ⁽²⁾ https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5

gilbsgilbs commented 4 years ago

~Mmh, my bad, turns out examples aren't supported in the 04 draft. So while practically useful, this PR may generate schemas with a dangling schemas property :thinking: . Maybe we could add this as an option then, WDYT?~ Made it an option.

philsturgeon commented 4 years ago

Examples in OAS2/3/JSON Schema are all very different, and it's a hell I continue to be stuck in every day.

https://phil.tech/2020/openapi-examples/

The OAS3 examples object lives outside the schema object, and this package only touches the schema object, so I'm not sure this PR will be salvagble.

gilbsgilbs commented 4 years ago

Thanks for your reply. That's interesting, I wasn't aware that OAS2 and OAS3 examples were that different.

I'm fine with closing this PR, but I'd like to understand your reasoning a bit more because I don't think I'm in line:

To give you a bit more context on why I need this: I'm trying to generate mocks of the schemas using this library. It can generate random data or just read from a random example.

Thanks for the great work.

gilbsgilbs commented 4 years ago

After checking again, appears that I'm just wrong. examples MUST be defined outside schemas and this is a mess. Sorry for the noise.

philsturgeon commented 4 years ago

I think the article I shared explains it better than I could explain it here. It took a long time to write it, but a very brief summary of key points:

  1. It has nothing to do with OAS2.
  2. OAS3 “examples” have nothing to do with JSON Schema “examples” they’re totally different concepts
  3. This library only works with the OAS Schema Object, and OAS3 examples do not and cannot live inside the schema object, even if you get creative with a $ref you’re either doing something invalid or wildly unconventional.

Lmk if you have more questions after reading the article. :)

On Tue, Oct 20, 2020 at 10:05, gilbsgilbs notifications@github.com wrote:

Thanks for your reply. That's interesting, I wasn't aware that OAS2 and OAS3 examples were that different.

I'm fine with closing this PR, but I'd like to understand your reasoning a bit more because I don't think I'm in line:

  • this library focuses only on OAS3, so let's leave OAS2 aside for the moment.
  • you say that OAS3 examples live "outside" the schema object. If I understand correctly, this is a possibility but not a requirement and is only provided as a way to provide examples for non-schema objects (such as responses) or as a way to reuse examples by defining them in the dedicated components/examples section (just like you can already reuse schemas by using a $ref to components/schemas). While responses examples look indeed out-of-scope (as this lib only parses schemas as you noted), per-field examples look very supportable to me and is what this PR focuses on. FWIW, I think every single OAS3 and OAS3.1 example linked in your article will work as long as it lives inside the schema (which is the only thing you pass in to this lib anyways).
  • $ref resolving is already clearly stated as out-of-scope, so the user is already expected to manually resolve any reference to the components/examples section. Therefore even examples defined outside schemas should actually work in practice.
  • At the end of the day, I think this PR's option behaves in an expected and predictable manner. You pass in an OpenAPI schema (not spec) and it returns a single JSON schema with the examples in it as JSON schema expects them. If you don't want this you can just leave the option disabled and no cats will be harmed. I don't think it will introduce a lot of maintenance burden either (as it probably won't be widely enabled and the spec wont change every few days anyways).

To give you a bit more context on why I need this: I'm trying to generate mocks of the schemas using this library. It can generate random data or just read from a random example.

Thanks for the great work.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

philsturgeon commented 4 years ago

No worries! Our messages swapped in space. Thanks for reading and understanding!

On Tue, Oct 20, 2020 at 11:03, gilbsgilbs notifications@github.com wrote:

After checking again, appears that I'm just wrong. examples MUST be defined outside schemas and this is a mess. Sorry for the noise.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

gilbsgilbs commented 4 years ago

Another approach that would maybe be more acceptable and that would fill my use-case elegantly would be to add a "hook" option that would get called for each inner schema. Just like the patternPropertiesHandler option but that would unconditionally get called to let the user patch a schema. Would such option be something you would consider? May I open another PR or do you prefer discussing it in a separate issue?