Skip to content

Commit

Permalink
Add request body media type update checker (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
blva authored Jul 13, 2023
1 parent 37acfd1 commit b114fc2
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 3 deletions.
3 changes: 3 additions & 0 deletions BREAKING-CHANGES-EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ These examples are automatically generated from unit tests.
[reducing max length in request is breaking](checker/checker_breaking_min_max_test.go?plain=1#L12)
[reducing min items in response is breaking](checker/checker_breaking_min_max_test.go?plain=1#L220)
[reducing min length in response is breaking](checker/checker_breaking_min_max_test.go?plain=1#L62)
[removing a media type from requesst body is breaking](checker/checker_breaking_test.go?plain=1#L617)
[removing an existing optional response header is breaking as warn](checker/checker_breaking_test.go?plain=1#L410)
[removing an existing required response header is breaking as error](checker/checker_breaking_test.go?plain=1#L227)
[removing an existing response with non-successful status is breaking (optional)](checker/checker_breaking_test.go?plain=1#L264)
Expand Down Expand Up @@ -138,6 +139,7 @@ These examples are automatically generated from unit tests.

## Examples of info-level changes for changelog
[Adding a new global security to the API](checker/check-api-security-updated_test.go?plain=1#L11)
[Adding a new media type to request body](checker/check-request-body-mediatype-updated_test.go?plain=1#L11)
[Adding a new media type to response](checker/check-response-mediatype-updated_test.go?plain=1#L11)
[Adding a new oauth security scope](checker/check-components-security-updated_test.go?plain=1#L91)
[Adding a new operation id](checker/check-api-operation-id-updated_test.go?plain=1#L59)
Expand Down Expand Up @@ -173,6 +175,7 @@ These examples are automatically generated from unit tests.
[Removing an existing operation id](checker/check-api-operation-id-updated_test.go?plain=1#L11)
[Removing an existing tag](checker/check-api-tag-updated_test.go?plain=1#L35)
[Removing an optional write-only property from a response](checker/check-response-optional-property-updated_test.go?plain=1#L11)
[Removing media type from request body](checker/check-request-body-mediatype-updated_test.go?plain=1#L33)
[Updating an existing operation id](checker/check-api-operation-id-updated_test.go?plain=1#L35)
[Updating an existing tag](checker/check-api-tag-updated_test.go?plain=1#L60)
[adding a required write-only property to response body is detected](checker/check-response-required-property-updated_test.go?plain=1#L57)
Expand Down
60 changes: 60 additions & 0 deletions checker/check-request-body-mediatype-updated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package checker

import (
"fmt"

"github.com/tufin/oasdiff/diff"
)

const (
RequestBodyMediaTypeAdded = "request-body-media-type-added"
RequestBodyMediaTypeRemoved = "request-body-media-type-removed"
)

func RequestBodyMediaTypeChangedCheck(diffReport *diff.Diff, operationsSources *diff.OperationsSourcesMap, config Config) Changes {
result := make(Changes, 0)
if diffReport.PathsDiff == nil {
return result
}
for path, pathItem := range diffReport.PathsDiff.Modified {
if pathItem.OperationsDiff == nil {
continue
}
for operation, operationItem := range pathItem.OperationsDiff.Modified {
if operationItem.RequestBodyDiff == nil ||
operationItem.RequestBodyDiff.ContentDiff == nil ||
operationItem.RequestBodyDiff.ContentDiff.MediaTypeModified == nil {
continue
}
source := (*operationsSources)[operationItem.Revision]

addedMediaTypes := operationItem.RequestBodyDiff.ContentDiff.MediaTypeAdded
for _, mediaType := range addedMediaTypes {
result = append(result, ApiChange{
Id: RequestBodyMediaTypeAdded,
Level: INFO,
Text: fmt.Sprintf(config.i18n(RequestBodyMediaTypeAdded), mediaType),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}

removedMediaTypes := operationItem.RequestBodyDiff.ContentDiff.MediaTypeDeleted
for _, mediaType := range removedMediaTypes {
result = append(result, ApiChange{
Id: RequestBodyMediaTypeRemoved,
Level: ERR,
Text: fmt.Sprintf(config.i18n(RequestBodyMediaTypeRemoved), mediaType),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}

}
}
return result
}
53 changes: 53 additions & 0 deletions checker/check-request-body-mediatype-updated_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package checker_test

import (
"testing"

"github.com/stretchr/testify/require"
"github.com/tufin/oasdiff/checker"
"github.com/tufin/oasdiff/diff"
)

// CL: Adding a new media type to request body
func TestRequestBodyMediaTypeAdded(t *testing.T) {
s1, _ := open("../data/checker/request_body_media_type_updated_base.yaml")
s2, err := open("../data/checker/request_body_media_type_updated_revision.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.RequestBodyMediaTypeChangedCheck), d, osm, checker.INFO)
require.Len(t, errs, 1)
require.Equal(t, checker.ApiChange{
Id: "request-body-media-type-added",
Text: "added the media type application/json to the request body",
Comment: "",
Level: checker.INFO,
Operation: "POST",
Path: "/api/v1.0/groups",
Source: "../data/checker/request_body_media_type_updated_revision.yaml",
OperationId: "createOneGroup",
}, errs[0])
}

// CL: Removing media type from request body
func TestRequestBodyMediaTypeRemoved(t *testing.T) {
s1, _ := open("../data/checker/request_body_media_type_updated_revision.yaml")
s2, err := open("../data/checker/request_body_media_type_updated_base.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.RequestBodyMediaTypeChangedCheck), d, osm, checker.INFO)
require.Len(t, errs, 1)
require.Equal(t, checker.ApiChange{
Id: "request-body-media-type-removed",
Text: "removed the media type application/json from the request body",
Comment: "",
Level: checker.ERR,
Operation: "POST",
Path: "/api/v1.0/groups",
Source: "../data/checker/request_body_media_type_updated_base.yaml",
OperationId: "createOneGroup",
}, errs[0])
}
16 changes: 16 additions & 0 deletions checker/checker_breaking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,3 +613,19 @@ func TestBreaking_SchemaRemoved(t *testing.T) {
require.Equal(t, "api-schema-removed", errs[1].GetId())
require.Equal(t, "removed the schema 'rules'", errs[1].GetText())
}

// BC: removing a media type from requesst body is breaking
func TestBreaking_RequestBodyMediaTypeRemoved(t *testing.T) {
s1, err := open("../data/checker/request_body_media_type_updated_revision.yaml")
require.NoError(t, err)

s2, err := open("../data/checker/request_body_media_type_updated_base.yaml")
require.NoError(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibility(checker.GetDefaultChecks(), d, osm)
require.NotEmpty(t, errs)
require.Equal(t, "request-body-media-type-removed", errs[0].GetId())
require.Equal(t, "removed the media type application/json from the request body", errs[0].GetText())
}
1 change: 1 addition & 0 deletions checker/default_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func defaultChecks() []BackwardCompatibilityCheck {
RequestParameterDefaultValueChanged,
APIComponentsSecurityUpdatedCheck,
APISecurityUpdatedCheck,
RequestBodyMediaTypeChangedCheck,
}
}

Expand Down
6 changes: 5 additions & 1 deletion checker/localizations/localizations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion checker/localizations_src/en/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,6 @@ response-required-write-only-property-added: added the required write-only prope
response-required-write-only-property-removed: removed the required write-only property %s from the response with the %s status
response-write-only-property-became-optional: the response write-only property %s became optional for the status %s
response-property-became-required: the response property %s became required for the status %s
response-write-only-property-became-required: the response write-only property %s became required for the status %s
response-write-only-property-became-required: the response write-only property %s became required for the status %s
request-body-media-type-removed: removed the media type %s from the request body
request-body-media-type-added: added the media type %s to the request body
4 changes: 3 additions & 1 deletion checker/localizations_src/ru/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,6 @@ response-required-write-only-property-added: добавлено обязател
response-required-write-only-property-removed: удалено обязательное свойство только для записи %s из ответа со статусом %s
response-write-only-property-became-optional: свойство только для записи %s перестало быть обязательным для ответа со статусом %s
response-property-became-required: свойство %s перестало быть необязательным для ответа со статусом %s
response-write-only-property-became-required: свойство только для записи %s перестало быть необязательным для ответа со статусом %s
response-write-only-property-became-required: свойство только для записи %s перестало быть необязательным для ответа со статусом %s
request-body-media-type-added: добавлен тип медиа для тела запроса %s
request-body-media-type-removed: удален тип медиа для тела запроса %s
59 changes: 59 additions & 0 deletions data/checker/request_body_media_type_updated_base.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
openapi: 3.0.1
info:
title: Tufin
version: "2.0"
servers:
- url: https://localhost:9080
paths:
/api/v1.0/groups:
post:
tags:
- Group
operationId: createOneGroup
requestBody:
content:
text/plain:
schema:
type: string
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/GroupView'
description: OK
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/GroupView'
description: Conflict
summary: Create One Project
components:
parameters:
groupId:
in: path
name: groupId
required: true
schema:
type: string
schemas:
GroupView:
type: object
properties:
data:
type: object
properties:
created:
type: string
format: date-time
readOnly: true
pattern: "^[a-z]+$"
id:
type: string
readOnly: true
name:
type: string
required:
- name
63 changes: 63 additions & 0 deletions data/checker/request_body_media_type_updated_revision.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
openapi: 3.0.1
info:
title: Tufin
version: "2.0"
servers:
- url: https://localhost:9080
paths:
/api/v1.0/groups:
post:
tags:
- Group
operationId: createOneGroup
requestBody:
content:
text/plain:
schema:
type: string
application/json:
schema:
$ref: '#/components/schemas/GroupView'
description: Creates one project.
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/GroupView'
description: OK
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/GroupView'
description: Conflict
summary: Create One Project
components:
parameters:
groupId:
in: path
name: groupId
required: true
schema:
type: string
schemas:
GroupView:
type: object
properties:
data:
type: object
properties:
created:
type: string
format: date-time
readOnly: true
pattern: "^[a-z]+$"
id:
type: string
readOnly: true
name:
type: string
required:
- name

0 comments on commit b114fc2

Please sign in to comment.