Skip to content
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

OpenAPI Common Parameters #479

Merged
merged 21 commits into from
Feb 4, 2024
4 changes: 2 additions & 2 deletions ALLOF.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ diff --side-by-side data/allof/simple.yaml data/allof/revision.yaml
In order to reduce such false-positives, oasdiff supports the ability to replace allOf by a merged equivalent before comparing the specs, like this:

```
oasdiff breaking data/allof/simple.yaml data/allof/revision.yaml --flatten
oasdiff breaking data/allof/simple.yaml data/allof/revision.yaml --flatten-allof
```
In this case no breaking changes are reported, correctly.
The `--flatten` flag is also supported with `diff` and `changelog`.
The `--flatten-allof` flag is also supported with `diff`, `changelog`, `delta` and `summary`.

In order to see how oasdiff merges allOf, you can use the dedicated `flatten` command:
```
Expand Down
74 changes: 37 additions & 37 deletions BREAKING-CHANGES-EXAMPLES.md

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions COMMON-PARAMS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Common Parameters

### Common Parameters Definition
Parameters shared by all operations of a path can be defined on the path level instead of the operation level.
Path-level parameters are inherited by all operations of that path.
A typical use case are the GET/PUT/PATCH/DELETE operations that manipulate a resource accessed via a path parameter.

### There are two ways to handle Common Parameters in oasdiff
1. By default, oasdiff compares path parameters and operation parameters separately.
2. The `--flatten-params` merges common parameters from the path level into the operation level before running the diff.

For example, this command outputs two breaking changes:
```
oasdiff changelog data/common-params/params_in_path.yaml data/common-params/params_in_op.yaml
```
Output:
```
2 changes: 2 error, 0 warning, 0 info
error [new-request-path-parameter] at data/common-params/params_in_op.yaml
in API GET /admin/v0/abc/{id}
added the new path request parameter 'id'

error [new-required-request-parameter] at data/common-params/params_in_op.yaml
in API GET /admin/v0/abc/{id}
added the new required 'header' request parameter 'tenant-id'
```


Adding the `--flatten-params` eliminates the errors:
```
oasdiff changelog data/common-params/params_in_path.yaml data/common-params/params_in_op.yaml --flatten-params
```
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ docker run --rm -t tufin/oasdiff changelog https://raw.githubusercontent.com/Tuf
- [API deprecation](API-DEPRECATION.md)
- [Multiple versions of the same endpoint](MATCHING-ENDPOINTS.md)
- [Merge allOf schemas](ALLOF.md)
- [Merge common parameters](COMMON-PARAMS.md)
- [Path prefix modification](#path-prefix-modification)
- [Path parameter renaming](#path-parameter-renaming)
- [Excluding certain kinds of changes](#excluding-specific-kinds-of-changes)
Expand Down
36 changes: 18 additions & 18 deletions checker/checker_breaking_min_max_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestBreaking_RequestMaxLengthSmaller(t *testing.T) {
maxLengthTo := uint64(11)
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -39,7 +39,7 @@ func TestBreaking_ResponseMaxLengthSmaller(t *testing.T) {
maxLengthTo := uint64(11)
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -53,7 +53,7 @@ func TestBreaking_RequestMinLengthSmaller(t *testing.T) {
s1.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinLength = uint64(13)
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinLength = uint64(11)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -67,7 +67,7 @@ func TestBreaking_MinLengthSmaller(t *testing.T) {
s1.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinLength = uint64(13)
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinLength = uint64(11)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Equal(t, checker.ResponseBodyMinLengthDecreasedId, errs[0].GetId())
Expand All @@ -84,7 +84,7 @@ func TestBreaking_RequestMaxLengthGreater(t *testing.T) {
maxLengthTo := uint64(14)
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -101,7 +101,7 @@ func TestBreaking_ResponseMaxLengthGreater(t *testing.T) {
maxLengthTo := uint64(14)
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -117,7 +117,7 @@ func TestBreaking_MaxLengthFromNil(t *testing.T) {
maxLengthTo := uint64(14)
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -135,7 +135,7 @@ func TestBreaking_ResponseMaxLengthFromNil(t *testing.T) {
maxLengthTo := uint64(14)
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = &maxLengthTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -151,7 +151,7 @@ func TestBreaking_RequestMaxLengthToNil(t *testing.T) {

s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = nil

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -167,7 +167,7 @@ func TestBreaking_ResponseMaxLengthToNil(t *testing.T) {

s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = nil

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -183,7 +183,7 @@ func TestBreaking_MaxLengthBothNil(t *testing.T) {
s1.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = nil
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MaxLength = nil

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -197,7 +197,7 @@ func TestBreaking_ResponseMaxLengthBothNil(t *testing.T) {
s1.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = nil
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MaxLength = nil

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -211,7 +211,7 @@ func TestBreaking_RequestMinItemsSmaller(t *testing.T) {
s1.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinItems = 13
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinItems = 11

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -225,7 +225,7 @@ func TestBreaking_ResponseMinItemsSmaller(t *testing.T) {
s1.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinItems = 13
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinItems = 11

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -241,7 +241,7 @@ func TestBreaking_RequeatMinItemsGreater(t *testing.T) {
s1.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinItems = 13
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.MinItems = 14

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -255,7 +255,7 @@ func TestBreaking_ResponseMinItemsGreater(t *testing.T) {
s1.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinItems = 13
s2.Spec.Paths.Value(securityScorePath).Get.Responses.Value("201").Value.Content["application/xml"].Schema.Value.MinItems = 14

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -272,7 +272,7 @@ func TestBreaking_MaxSmaller(t *testing.T) {
maxTo := float64(11)
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Schema.Value.Max = &maxTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -289,7 +289,7 @@ func TestBreaking_MaxSmallerInResponse(t *testing.T) {
maxTo := float64(11)
s2.Spec.Paths.Value(installCommandPath).Get.Responses.Value("default").Value.Headers["X-RateLimit-Limit"].Value.Schema.Value.Max = &maxTo

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand Down
8 changes: 4 additions & 4 deletions checker/checker_breaking_property_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestBreaking_NewRequiredProperty(t *testing.T) {
}
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{"courseId"}

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -48,7 +48,7 @@ func TestBreaking_NewNonRequiredProperty(t *testing.T) {
},
}

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand All @@ -72,7 +72,7 @@ func TestBreaking_PropertyRequiredEnabled(t *testing.T) {
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{"courseId"}

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
Expand All @@ -98,7 +98,7 @@ func TestBreaking_PropertyRequiredDisabled(t *testing.T) {
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s2.Spec.Paths.Value(installCommandPath).Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{}

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), &s1, &s2)
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.Empty(t, errs)
Expand Down
Loading
Loading