Comments (33)
@wtrocki , how do you plan to flatten oneOf/anyOf? Is it really possible?
allOf can be flattened to get fully equivalent schema, but oneOf/anyOf cannot...
from oasdiff.
This project can potentially be used to implement this feature: https://github.com/mokkabonna/json-schema-merge-allof
from oasdiff.
@reuvenharrison , understood. Unfortunately I have almost zero experience with Golang and NodeJS. I use my own fork of https://github.com/equinor/openapi-flattener to dereference original OpenAPI and remove "allOf" before feeding it to oasdiff.
I will need some time to polish my forked version (significantly improved original one), then I will publish the link here.
from oasdiff.
We're making progress on this issue and want to test our code with real use cases. Could any of you provide a spec that uses
allOf
and specify the library used for flattening? Your input would be really helpful. Thanks.
As I posted earlier in this chat I used a combination of https://github.com/mokkabonna/json-schema-merge-allof and https://github.com/equinor/openapi-flattener. First - as is, second needed to change to support 'allOf' constructs in different parts of OpenAPI spec (e.g. callbacks, parameters) which was not supported originally.
from oasdiff.
@reuvenharrison I have investigated the issue and there are a couple of ways to do it:
- Preprocessing step that does flattening as mentioned by @anikitin
- Write dedicated optional flattening for oneOf and allOf in oasDiff controlled by cli flags
IMHO option nr2 is superior as it would enable oasdiff to test the whole experience end to end and
minimize issues like duplicate reports when schema.component is reused across different apis.
Transformation logic should cater to 3 different constructs:
Approach for flattening/normalization/transformation
When performing flattering 2 different strategies can be taken:
- Whole schema flattening involving resolving every dependency
- Targetted flattening like mentioned in this jira
Full Schema Flatten
. This approach will fix some of the confusion with Cardiff reporting multiple breaking changes for a single model change. It will focus on the final API. There are some existing examples of golang libraries that perform such mechanisms:
- https://goswagger.io/usage/flatten.html (https://github.com/go-openapi/analysis/blob/master/flatten.go)
Flattenining strategies
Involves triggering dedicated transformations:
- AllOf (https://github.com/tcdsv/kin-openapi/tree/merge-allof)
- OneOf
- AnyOf
from oasdiff.
Looks reasonable, seems like it is not difficult to implement. It requires only to change the scheme diffs calculation to merge recursively properties of all allOf instances before diff calculation if the option is specified in Config. I suppose I could try implement it if nobody else does it in a week.
from oasdiff.
Any progress? I am trying to work around by preprocessing the spec before applying oasdiff.
Resolving allOf also requires full or partial dereferencing. Haven't built a solution which fully satisfies me so far...
from oasdiff.
Hi @anikitin
If you use refs instead of inline schemas under the allOf tag, oasdiff will detect changes properly, perhaps this could provide a workaround.
To support inline schemas we would need to merge the schemas before the diff which could be quite complicated. If we reduce the scope to merge only certain kinds of schemas it can be easier. Is your example of objects and properties comprehensive or do you expect to merge other kinds of schemas under allOf?
from oasdiff.
Hi @anikitin please let me know if you have any updates.
from oasdiff.
Closing due to inactivity.
from oasdiff.
Sorry, didn't notice your previous comment.
If you use refs instead of inline schemas under the allOf tag, oasdiff will detect changes properly, perhaps this could provide a workaround.
Good to know and it will help in some cases but not solve the problem globally.
We have hundreds of specs written by different people and most of the valid OpenAPI constructs are just allowed, so in some cases it is more convenient to use inline, we don't prevent it today.
To support inline schemas we would need to merge the schemas before the diff which could be quite complicated. If we reduce the scope to merge only certain kinds of schemas it can be easier. Is your example of objects and properties comprehensive or do you expect to merge other kinds of schemas under allOf?
I think we are mostly interested in resolving request/response schemas for path methods, potentially callbacks as well (stretch goal). I don't remember where else we can use allOf practically...
from oasdiff.
Continuing the topic: if you can support it for paths/{path}/{method}/requestBody/schema and paths/{path}/{method}/responses/{code}/{contentType}/schema it would help in 99% of cases
from oasdiff.
i have the same issue regarding oneOf tag. no resolving. semantically equivalent schemas inside that tag are recognised as different and semantically not equivalent schemas with same schema name are not recognised as different.
from oasdiff.
@floty could you please submit two specs and the command-line to replicate this?
from oasdiff.
i have the same issue regarding oneOf tag. no resolving. semantically equivalent schemas inside that tag are recognised as different and semantically not equivalent schemas with same schema name are not recognised as different.
oneOf/anyOf might be more tricky. allOf can be just expanded before comparison, while it is not possible to do the same for oneOf/anyOf ... I have no ideas how it can be resolved, unless some guidelines are introduced for spec authoring which limit where these tags can appear in the spec.
from oasdiff.
Before we go ahead and invest in this "merge schemas" feature I want to emphasize two limitations:
- Merging schemas may have unexpected results, for example, when two schemas under AllOf have the same property with conflicting values. This may cause an unexpected diff.
- Merging schemas works only for AllOf and not for the other composites: OneOf or AnyOf.
The only robust solution for this problem is to define composite schemas using $refs instead of inline schemas. oasdiff can compare composite schemas with $refs because the $ref link is used as a unique ID that allows us to know which schemas correspond to each other across the two specs. This is impossible when schemas are defined inline.
To clarify, this is a composite schema with "referenced" schemas:
schema:
oneOf:
- $ref: '#/components/schemas/schema1'
- $ref: '#/components/schemas/schema2'
And this is a composite schema with "inline" schemas:
schema:
oneOf:
- type: object
properties:
name:
type: string
- type: object
properties:
id:
type: int
Your feedback is welcome.
from oasdiff.
@floty could you please submit two specs and the command-line to replicate this?
Here are some examples:
- identical_specs_showing_diff_1.zip
identical specs (one with inline, one with ref schema) but output diff with "modified: field: oneOf: added: 1, deleted: 1", expectation: no diff - identical_specs_showing_diff_2.zip
identical specs (both with ref schema but different schema names) but output diff with "modified: field: oneOf: added: 1, deleted: 1", expectation: no diff - different_specs_no_diff.zip
not identical specs (one field is missing) but no diff with option "-breaking-only", expectation: diff
I think resolving the schemas (convert to inline definition) before comparing can be the solution for fixing the oneOf issue.
from oasdiff.
Thanks @floty.
We could add a syntactic comparison to detect cases where the composite schema is identical (cases 1 and 2 above).
Case 3 is not breaking. If you define the deleted property as "required" then it will be breaking.
In general, as I mentioned above, the only solution for oneOf is to use $refs (with fixed names), otherwise there is no reliable way to associate the objects in the original spec and the revised spec.
I don't understand your suggestion, "convert to inline definition", perhaps you can elaborate?
from oasdiff.
We could add a syntactic comparison to detect cases where the composite schema is identical (cases 1 and 2 above).
Yes, handling cases 1 and 2 would be great.
Case 3 is not breaking. If you define the deleted property as "required" then it will be breaking.
You are completely right. I didn't pay attention to that.
In general, as I mentioned above, the only solution for oneOf is to use $refs (with fixed names), otherwise there is no reliable way to associate the objects in the original spec and the revised spec.
But that is only valid if you do not consider the order of the oneOf field? If the order is relevant you can directly compare every schema from first to last oneOf element. Than there is no problems regarding reliability I think.
I don't understand your suggestion, "convert to inline definition", perhaps you can elaborate?
What I mean: probable solution for handling the problem of case 1 and 2 can be to convert every "reference" schema into "inline" schema inside your comparing algorithm (see your post above for meaning of "referenced" and "inline" schema). With than, the comparing algorithm can only works on inline schemas and no naming conflicts can occur (like different schema names of case 2). Is it clearer now?
from oasdiff.
I think the processing of "allOf" and "anyOff/oneOff" can be controlled by two different command line options. For the latter case constraints should be documented. Also "discriminator" definition should be also taken into account when processing "anyOf/oneOf": change in discriminator is a potentially breaking change.
from oasdiff.
We have also detected false positives due to this issue. Do we have a plan to sort this? Can I help somehow?
from oasdiff.
We need to develop the ability to merge the schemas appearing under AllOf and then apply the normal schema comparison on the resulting merged schema.
As mentioned above we can take inspiration from this javascript project.
I started working on this here but then @fenollp suggested to do it as part of kin-openapi which makes sense.
I'm happy to cooperate on this if you are interested.
from oasdiff.
I started implementing this here: https://github.com/oasdiff/kin-openapi
from oasdiff.
@reuvenharrison , so how it can be used as a CLI tool once it is moved to kin-openapi? Would be still interested to try your fix but
you removed the branch...
Since the fix is controlled by a separate configuration option, it looks to be pretty safe to merge it into main branch, no?
from oasdiff.
I am working on the PR here: https://github.com/oasdiff/kin-openapi
The idea is to make it available to everyone who is using kin-openapi, a large community that will help us optimize this feature, and also to use it in oasdiff.
from oasdiff.
@reuvenharrison , I use a workaround now which flattens the spec with a separate tool before feeding it to oasdiff.
Anyway, let me know if you have any ETA on this feature. Would be great to have it as a part of oasdiff!
from oasdiff.
I started work on this but didn't make much progress yet. Help wanted :-)
Could you share the tool you use to flatten the spec for the benefit of other users?
from oasdiff.
I'm glad to share that @tcdsv has taken ownership on this and is making good progress towards a solution:
https://github.com/tcdsv/kin-openapi/tree/merge-allof
Anyone who is interested is welcome to join the effort.
from oasdiff.
We're making progress on this issue and want to test our code with real use cases. Could any of you provide a spec that uses allOf
and specify the library used for flattening? Your input would be really helpful. Thanks.
from oasdiff.
@tcdsv the GitHub OpenAPI specs contains allOf
:
https://github.com/github/rest-api-description/tree/main/descriptions
from oasdiff.
I agree it will not be fully equivalent.
Algo:
- Detect the model with oneOf/anyOf field on the existing component.
- For each child object (ref in the oneOf) move properties and
allOf
refs to the parent - Remove children components from OpenAPI (replace all references with parent)
- Skip the process if there are duplicates/inconsistencies.
from oasdiff.
We just submitted a PR to merge allOf subschemas: getkin/kin-openapi#828
The accompanying branch on oasdiff takes advantage of the Merge
function in getkin to merge allOf subschemas before diff.
Your comments are welcome.
from oasdiff.
Closed with #374
from oasdiff.
Related Issues (20)
- `response-property-became-required` is added for required properties that are newly added to response bodies HOT 1
- Non-friendly error message
- oasdiff flatten doesn't output paths HOT 1
- YAML/JSON field name typo: "reuired" -> "required" HOT 1
- Feature request: Support external metadata
- Verbose CLI output to help troubleshoot (especially in composed mode) HOT 5
- oasdiff error in composed mode when the same path appears in different files HOT 1
- Race condition while parsing command line arguments if telemetry is enabled HOT 1
- "Error resolving reference/map key not found" when running oasdiff across the set of files with intensive external refs HOT 1
- Supporting "--fail-on" option for changelog command
- basePath and servers.ulr support HOT 3
- Add support for AWS API Gateway extensions to OpenAPI HOT 6
- Diff tool gets confused when a new inline enum value is added and a new enum type is added at the sime time HOT 4
- Changelog does not log adding a new optional request body HOT 2
- `latest` docker container (April 8th) introduces a bug that causes false positives HOT 1
- --flatten-allof panic HOT 3
- Unmarshalling errors don't provide offset HOT 6
- Support breaking-changes and changelog for schemas with multiple types
- Support "flatten allOf" for schemas with multiple types
- Typo in description of incompatible changes HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from oasdiff.