Skip to content

Commit

Permalink
OpenAPI Common Parameters (#479)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reuven Harrison authored Feb 4, 2024
1 parent 270ba7b commit a3b4664
Show file tree
Hide file tree
Showing 54 changed files with 1,093 additions and 522 deletions.
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

0 comments on commit a3b4664

Please sign in to comment.