Welcome to Swagger Spec Compatibility’s documentation!¶
swagger-spec-compatibility
is a Yelp maintained library that provides tools to automatically detect
the safety of Swagger/OpenAPI 2.0 specification changes
with respect to backwards compatibility.
swagger-spec-compatibility
aims to give developers confidence that their spec changes are safe and that clients
built with previous versions of the Swagger spec can continue to communicate correctly.
Disclaimer¶
The detection rules currently supported are built due to the need to cover common breaking changes (that we’ve experienced internally at Yelp) or support received from contributors.
If you’re experiencing breaking changes and you would have the tool help you figure it out before being late, feel free to open issues on the project. You can also open pull requests implementing the rules, we’re always open to contributors.
Errors description¶
Request Contract Changes¶
[REQ-E001] - Added Required Property in Request contract¶
Rationale¶
Adding a required property to an object used in requests leads client request to fail if the property is not present.
Mitigation¶
A possible mitigation consists of adding the property as optional with an associated default value. In this case, the client requests don’t fail to validate and the service can assume that the property is always set.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | swagger: '2.0'
info:
title: Minimal Case of REQ-E001 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: string
type: object
responses:
default:
description: ''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | swagger: '2.0'
info:
title: Minimal Case of REQ-E001 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: string
required:
- property
type: object
responses:
default:
description: ''
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_send = {}
print('Calling the post endpoint with the old client: Succeeded')
old_client.endpoint.post_endpoint(body=object_to_send)
print('Calling the post endpoint with the new client: Failed')
try:
new_client.endpoint.post_endpoint(body=object_to_send)
raise RuntimeError('An error was expected')
except ValidationError:
pass
|
NOTE: The code is taking advantage of bravado
[REQ-E002] - Removed Enum value from Request contract¶
Rationale¶
Removing an enum value from a request parameter is backward incompatible as a previously valid request will not be valid. This happens because a request containing the removed enum value, valid according to the “old” Swagger spec, is not valid according to the new specs.
Mitigation¶
There are no best practices for this type of issue. The general recommendation would be to avoid as much as possible this type of change.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | swagger: '2.0'
info:
title: Minimal Case of REQ-E002 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: string
enum:
- v1
- v2
type: object
responses:
default:
description: ''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | swagger: '2.0'
info:
title: Minimal Case of REQ-E002 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: string
enum:
- v1
type: object
responses:
default:
description: ''
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_send = {'property': 'v2'}
print('Calling the post endpoint with the old client: Succeeded')
old_client.endpoint.post_endpoint(body=object_to_send)
print('Calling the post endpoint with the new client: Failed')
try:
new_client.endpoint.post_endpoint(body=object_to_send)
raise RuntimeError('An error was expected')
except ValidationError:
pass
|
NOTE: The code is taking advantage of bravado
[REQ-E003] - Removing properties from an object with additionalProperties set to False used as request parameter¶
Rationale¶
If the object is defined with additionalProperties set to False then the object will not allow presence of properties not defined on the properties section of the object definition. Removing a definition of an existing property makes objects sent from a client, that is using “old” Swagger specs, to the server be considered invalid by the backend.
Mitigation¶
A possible mitigation could be to not remove the property from the object schema, mark it as deprecated (mostly for documentation purposes) and make sure that your business logic fills the field with a placeholder.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | swagger: '2.0'
info:
title: Minimal Case of REQ-E003 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
additionalProperties: false
properties:
property_1:
type: string
property_2:
type: string
type: object
responses:
default:
description: ''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | swagger: '2.0'
info:
title: Minimal Case of REQ-E003 Rule
version: '1.0'
paths:
/endpoint:
post:
parameters:
- in: body
name: body
required: true
schema:
additionalProperties: false
properties:
property_1:
type: string
type: object
responses:
default:
description: ''
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_send = {'property_1': 'v1', 'property_2': 'v2'}
print('Calling the post endpoint with the old client: Succeeded')
old_client.endpoint.post_endpoint(body=object_to_send)
print('Calling the post endpoint with the old client: Failed')
try:
new_client.endpoint.post_endpoint(body=object_to_send)
raise RuntimeError('An error was expected')
except ValidationError:
pass
|
NOTE: The code is taking advantage of bravado
Response Contract Changes¶
[RES-E001] - Added properties in an object with additionalProperties set to False used in response¶
Rationale¶
If the object is defined with additionalProperties set to False then the object will not allow presence of properties not defined on the properties section of the object definition. Adding a definition of a new property makes object sent from the server to the client be considered invalid by a client that is using “old” Swagger specs.
Mitigation¶
A general suggestion would be to avoid setting additionalProperties to False for request objects as this prevents backward compatible safe object modifications. A possible mitigation to this requires the implementation of a new endpoint that returns the new object schema.
NOTE: Implementing a new endpoint is usually cheap but comes with the complexity of handling multiple versions of similar endpoints.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | swagger: '2.0'
info:
title: Minimal Case of RES-E001 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
additionalProperties: false
properties:
property_1:
type: string
type: object
x-model: get_endpoint_response
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | swagger: '2.0'
info:
title: Minimal Case of RES-E001 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
additionalProperties: false
properties:
property_1:
type: string
property_2:
type: string
type: object
x-model: get_endpoint_response
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from bravado_core.validate import validate_schema_object
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_validate = {'property_2': 'v1'}
print('Validating the get endpoint response with the old client: Failed')
try:
validate_schema_object(
swagger_spec=old_client.swagger_spec,
schema_object_spec=old_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
raise RuntimeError('An error was expected')
except ValidationError:
pass
print('Validating the get endpoint response with the old client: Succeeded')
validate_schema_object(
swagger_spec=new_client.swagger_spec,
schema_object_spec=new_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
|
NOTE: The code is taking advantage of bravado
[RES-E002] - Remove a required property from an object used in responses¶
Rationale¶
Removing a required property from an object leads to false expectation on the client receiving the object. If the client is using “old” service’s Swagger spec it will expect the property to be presentand so it could throw errors. It could be valid to assume that the client won’t perform response validation and this leads to unexpected errors while parsing the response and/or using the missing property.
Mitigation¶
A known mitigation to this issue consists of keeping the required property in the Swagger specs and ensuring that the service populate the field with a placeholder (that has to be valid with the property spec).
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | swagger: '2.0'
info:
title: Minimal Case of RES-E002 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: string
required:
- property
type: object
x-model: get_endpoint_response
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | swagger: '2.0'
info:
title: Minimal Case of RES-E002 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: string
type: object
x-model: get_endpoint_response
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from bravado_core.validate import validate_schema_object
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_validate = {}
print('Validating the get endpoint response with the old client: Failed')
try:
validate_schema_object(
swagger_spec=old_client.swagger_spec,
schema_object_spec=old_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
raise RuntimeError('An error was expected')
except ValidationError:
pass
print('Validating the get endpoint response with the new client: Succeeded')
validate_schema_object(
swagger_spec=new_client.swagger_spec,
schema_object_spec=new_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
|
NOTE: The code is taking advantage of bravado
[RES-E003] - Added Enum value in Response contract¶
Rationale¶
Adding an enum value to a response parameter is backward incompatible as clients, using the “old” version of the Swagger specs, will not be able to properly validate the response.
Mitigation¶
A possible mitigation consists of modifying the endpoint to get the list of enum values supported for the specific request. This way we can ensure (at the business logic level, not on Swagger) that the response will not contain enum values that are not manageable by clients using “old” Swagger spec version.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | swagger: '2.0'
info:
title: Minimal Case of RES-E003 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: string
enum:
- v1
type: object
x-model: get_endpoint_response
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | swagger: '2.0'
info:
title: Minimal Case of RES-E003 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: string
enum:
- v1
- v2
type: object
x-model: get_endpoint_response
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from bravado_core.validate import validate_schema_object
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_validate = {'property': 'v2'}
print('Validating the get endpoint response with the old client: Failed')
try:
validate_schema_object(
swagger_spec=old_client.swagger_spec,
schema_object_spec=old_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
raise RuntimeError('An error was expected')
except ValidationError:
pass
print('Validating the get endpoint response with the new client: Succeeded')
validate_schema_object(
swagger_spec=new_client.swagger_spec,
schema_object_spec=new_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
|
NOTE: The code is taking advantage of bravado
Miscellaneous Changes¶
[MIS-E001] - Delete an endpoint¶
Rationale¶
A Swagger service should be only serve endpoints defined via Swagger specs. Once an endpoint is removed from the Swagger specs this implies that the endpoint is not served anymore and any call to it will fail (as there is no implementation for it; HTTP/400, HTTP/404 or HTTP/500 could be expected in this case).
Mitigation¶
There are no general approaches to make this change without risks. The main recommendations are: ensure that the endpoint is marked as deprecated and notify all the clients about the endpoint removal timeline ensure that the endpoint is not called anymore.
Note: this is not always possible, think about the case of public APIs used by mobile devices. In such case validate with the clients product owners that is possible to returns errors.
PS: be aware that the fact that an endpoint is not called anymore does not implies that it won’t be called in the future (maybe the obsolete client is just not used at the moment)
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | swagger: '2.0'
info:
title: Minimal Case of MIS-E001 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
post:
responses:
default:
description: ''
|
1 2 3 4 5 6 7 8 9 10 | swagger: '2.0'
info:
title: Minimal Case of MIS-E001 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
print('Calling the post endpoint with the old client: Succeeded')
old_client.endpoint.post_endpoint()
print('Calling the post endpoint with the new client: Failed')
try:
new_client.endpoint.post_endpoint()
raise RuntimeError('An error was expected')
except AttributeError:
pass
|
NOTE: The code is taking advantage of bravado
[MIS-E002] - Changed type¶
Rationale¶
Changing the type of a field is not backward compatible as a client using “old” Swagger specs will send the field with a different type leading the service to fail to validate the request. On the other end, if the object containing the updated field is used in the response, it will lead to unexpected client errors when parsing the response and/or using the updated property.
Mitigation¶
There are no best practices for this type of issue. The general recommended approach is: don’t do it and add a new field to the spec.
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | swagger: '2.0'
info:
title: Minimal Case of MIS-E002 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: string
type: object
x-model: get_endpoint_response
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: string
type: object
responses:
default:
description: ''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | swagger: '2.0'
info:
title: Minimal Case of MIS-E002 Rule
version: '1.0'
paths:
/endpoint:
get:
responses:
default:
description: ''
schema:
properties:
property:
type: boolean
type: object
x-model: get_endpoint_response
post:
parameters:
- in: body
name: body
required: true
schema:
properties:
property:
type: boolean
type: object
responses:
default:
description: ''
|
The following snippet triggers the incompatibility error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from os.path import abspath
from bravado.client import SwaggerClient
from bravado_core.validate import validate_schema_object
from jsonschema import ValidationError
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
old_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))),
)
new_client = SwaggerClient.from_url(
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))),
)
object_to_validate = {'property': 'True'}
print('Validating the get endpoint response with old client: Succeeded')
validate_schema_object(
swagger_spec=old_client.swagger_spec,
schema_object_spec=old_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
print('Validating the get endpoint response with the new client: Failed')
try:
validate_schema_object(
swagger_spec=new_client.swagger_spec,
schema_object_spec=new_client.swagger_spec.definitions['get_endpoint_response']._model_spec,
value=object_to_validate,
)
raise RuntimeError('An error was expected')
except ValidationError:
pass
print('Calling the post endpoint with old client: Succeeded')
old_client.endpoint.post_endpoint(body=object_to_validate)
print('Calling the post endpoint with the new client: Failed')
try:
new_client.endpoint.post_endpoint(body=object_to_validate)
except ValidationError:
pass
|
NOTE: The code is taking advantage of bravado
API reference¶
swagger_spec_compatibility Package¶
swagger_spec_compatibility
Package¶
cache
Module¶
cli
Module¶
-
class
swagger_spec_compatibility.cli.common.
CLIProtocol
(*args, **kwargs)[source]¶ Bases:
typing_extensions.Protocol
-
command
= None¶
-
func
= None¶
-
rules
Module¶
-
swagger_spec_compatibility.rules.
compatibility_status
(old_spec, new_spec, rules=<swagger_spec_compatibility.rules._ALL_RULES object>)[source]¶
-
class
swagger_spec_compatibility.rules.added_properties_in_response_objects_with_additional_properties_set_to_false.
AddedPropertiesInResponseObjectsWithAdditionalPropertiesSetToFalse
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'If the object is defined with additionalProperties set to False then the object will not allow presence of properties not defined on the properties section of the object definition. Adding a definition of a new property makes object sent from the server to the client be considered invalid by a client that is using "old" Swagger specs.'¶
-
error_code
= 'RES-E001'¶
-
error_level
= 2¶
-
rule_type
= 1¶
-
short_name
= 'Added properties in an object with additionalProperties set to False used in response'¶
-
-
class
swagger_spec_compatibility.rules.added_required_property_in_request.
AddedRequiredPropertyInRequest
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'Adding a required property to an object used in requests leads client request to fail if the property is not present.'¶
-
error_code
= 'REQ-E001'¶
-
error_level
= 2¶
-
rule_type
= 0¶
-
short_name
= 'Added Required Property in Request contract'¶
-
-
class
swagger_spec_compatibility.rules.added_enum_value_in_response.
AddedEnumValueInRequest
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'Adding an enum value to a response parameter is backward incompatible as clients, using the "old" version of the Swagger specs, will not be able to properly validate the response.'¶
-
error_code
= 'RES-E003'¶
-
error_level
= 2¶
-
rule_type
= 1¶
-
short_name
= 'Added Enum value in Response contract'¶
-
-
class
swagger_spec_compatibility.rules.common.
BaseRule
[source]¶ Bases:
object
-
description
= None¶
-
documentation_link
= None¶
-
error_code
= None¶
-
error_level
= None¶
-
rule_type
= None¶
-
short_name
= None¶
-
-
class
swagger_spec_compatibility.rules.common.
Level
[source]¶ Bases:
enum.IntEnum
An enumeration.
-
ERROR
= 2¶
-
INFO
= 0¶
-
WARNING
= 1¶
-
-
class
swagger_spec_compatibility.rules.common.
RuleProtocol
(*args, **kwargs)[source]¶ Bases:
typing_extensions.Protocol
-
description
= None¶
-
documentation_link
= None¶
-
error_code
= None¶
-
error_level
= None¶
-
rule_type
= None¶
-
short_name
= None¶
-
-
class
swagger_spec_compatibility.rules.common.
RuleRegistry
[source]¶ Bases:
abc.ABCMeta
-
class
swagger_spec_compatibility.rules.common.
RuleType
[source]¶ Bases:
enum.IntEnum
An enumeration.
-
MISCELLANEOUS
= 2¶
-
REQUEST_CONTRACT
= 0¶
-
RESPONSE_CONTRACT
= 1¶
-
-
class
swagger_spec_compatibility.rules.common.
ValidationMessage
[source]¶ Bases:
swagger_spec_compatibility.rules.common._ValidationMessage
-
swagger_spec_compatibility.rules.common.
get_rule_documentation_link
(rule)[source]¶ Helper method that allows to extract documentation link related to a given rule.
If the rule is implemented within swagger-spec-compatibility library then the documentation link will fall back to the “default” read-the-docs link
-
class
swagger_spec_compatibility.rules.deleted_endpoint.
DeletedEndpoint
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'An endpoint has been removed. This change is not backward compatible as holders of stale swagger specs (like old mobile Apps) could continue to call the removed endpoint and this will cause an HTTP error status code (usually an HTTP/400 or HTTP/404)'¶
-
error_code
= 'MIS-E001'¶
-
error_level
= 2¶
-
rule_type
= 2¶
-
short_name
= 'Delete Endpoint'¶
-
-
class
swagger_spec_compatibility.rules.changed_type.
ChangedType
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'Changing the type of a field is not backward compatible as a client using "old" Swagger specs will send the field with a different type leading the service to fail to validate the request. On the other end, if the object containing the updated field is used in the response, it will lead to unexpected client errors when parsing the response and/or using the updated property.'¶
-
error_code
= 'MIS-E002'¶
-
error_level
= 2¶
-
rule_type
= 2¶
-
short_name
= 'Changed type'¶
-
-
class
swagger_spec_compatibility.rules.removed_enum_value_from_request.
RemovedEnumValueFromRequest
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'Removing an enum value from a request parameter is backward incompatible as a previously valid request will not be valid. This happens because a request containing the removed enum value, valid according to the "old" Swagger spec, is not valid according to the new specs.'¶
-
error_code
= 'REQ-E002'¶
-
error_level
= 2¶
-
rule_type
= 0¶
-
short_name
= 'Removed Enum value from Request contract'¶
-
-
class
swagger_spec_compatibility.rules.removed_properties_from_request_objects_with_additional_properties_set_to_false.
RemovedPropertiesFromRequestObjectsWithAdditionalPropertiesSetToFalse
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'If the object is defined with additionalProperties set to False then the object will not allow presence of properties not defined on the properties section of the object definition. Removing a definition of an existing property makes objects sent from a client, that is using "old" Swagger specs, to the server be considered invalid by the backend.'¶
-
error_code
= 'REQ-E003'¶
-
error_level
= 2¶
-
rule_type
= 0¶
-
short_name
= 'Removing properties from an object with additionalProperties set to False used as request parameter'¶
-
-
class
swagger_spec_compatibility.rules.removed_required_property_from_response.
RemovedRequiredPropertyFromResponse
[source]¶ Bases:
swagger_spec_compatibility.rules.common.BaseRule
-
description
= 'Removing a required property from an object leads to false expectation on the client receiving the object. If the client is using "old" service\'s Swagger spec it will expect the property to be present and so it could throw errors. It could be valid to assume that the client won\'t perform response validation and this to unexpected errors while parsing the response and/or using the missing property.'¶
-
error_code
= 'RES-E002'¶
-
error_level
= 2¶
-
rule_type
= 1¶
-
short_name
= 'Removed Required Property from Response contract'¶
-
spec_utils
Module¶
-
class
swagger_spec_compatibility.spec_utils.
Endpoint
[source]¶ Bases:
swagger_spec_compatibility.spec_utils._Endpoint
-
class
swagger_spec_compatibility.spec_utils.
HTTPVerb
[source]¶ Bases:
enum.Enum
An enumeration.
-
DELETE
= 'delete'¶
-
GET
= 'get'¶
-
HEAD
= 'head'¶
-
OPTIONS
= 'options'¶
-
PARAMETERS
= 'parameters'¶
-
PATCH
= 'patch'¶
-
POST
= 'post'¶
-
PUT
= 'put'¶
-
-
class
swagger_spec_compatibility.spec_utils.
StatusCodeSchema
(status_code, mapping)¶ Bases:
tuple
-
mapping
¶ Alias for field number 1
-
status_code
¶ Alias for field number 0
-
util
Module¶
-
class
swagger_spec_compatibility.util.
EntityMapping
(old, new)[source]¶ Bases:
typing.Generic
-
new
¶
-
old
¶
-
walkers
Module¶
-
class
swagger_spec_compatibility.walkers.
SchemaWalker
(left_spec, right_spec, **kwargs)[source]¶ Bases:
swagger_spec_compatibility.walkers.Walker
Walker aware of how a Swagger schema looks like.
The main difference between this walker and Walker is that this walker keeps in consideration some peculiarity of the swagger specs.
The walker implementation should never worry about dereferencing as the traversing is performed on the fully flattened and dereferenced specs
-
fix_parameter_path
(path, original_path, value)[source]¶ Fix an eventual path present on the value returned by the walker.
The SwaggerAwareWalker modifies the indexing approach used for parameters due to the fact that parameters are defined as arrays and modifying their order would not change the semantic.
-
-
class
swagger_spec_compatibility.walkers.
Walker
(left, right, **kwargs)[source]¶ Bases:
typing.Generic
Generic Walker over two objects.
The abstract class strips away the details related to dictionary vs list iterations, path update etc.
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
should_path_be_walked_through
(path)[source]¶ Determine whether to traverse or interrupt traversal of a given path.
This method allows Walkers to skip traversal of area of the specs that are “not interesting”. This will allow to write simpler methods and to avoid needless traversing of the Specs.
-
-
class
swagger_spec_compatibility.walkers.additional_properties.
AdditionalPropertiesDiff
[source]¶ Bases:
swagger_spec_compatibility.walkers.additional_properties.AdditionalPropertiesDiff
-
class
swagger_spec_compatibility.walkers.additional_properties.
AdditionalPropertiesDifferWalker
(left_spec, right_spec, **kwargs)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
additionalPropertiesValue
= None¶
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
diffs
= None¶
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
right_spec
= None¶
-
-
class
swagger_spec_compatibility.walkers.additional_properties.
DiffType
[source]¶ Bases:
enum.Enum
An enumeration.
-
PROPERTIES
= 0¶
-
VALUE
= 1¶
-
-
class
swagger_spec_compatibility.walkers.changed_types.
ChangedTypesDiff
[source]¶ Bases:
swagger_spec_compatibility.walkers.changed_types.ChangedTypesDiff
-
class
swagger_spec_compatibility.walkers.changed_types.
ChangedTypesDifferWalker
(left_spec, right_spec)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
diffs
= None¶
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
right_spec
= None¶
-
-
class
swagger_spec_compatibility.walkers.enum_values.
EnumValuesDiff
[source]¶ Bases:
swagger_spec_compatibility.walkers.enum_values.EnumValuesDiff
-
class
swagger_spec_compatibility.walkers.enum_values.
EnumValuesDifferWalker
(left_spec, right_spec, **kwargs)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
right_spec
= None¶
-
-
class
swagger_spec_compatibility.walkers.request_parameters.
RequestParametersWalker
(left_spec, right_spec)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
fix_parameter_path
(path, original_path, value)[source]¶ Fix an eventual path present on the value returned by the walker.
The SwaggerAwareWalker modifies the indexing approach used for parameters due to the fact that parameters are defined as arrays and modifying their order would not change the semantic.
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
right_spec
= None¶
-
-
class
swagger_spec_compatibility.walkers.required_properties.
RequiredPropertiesDiff
[source]¶ Bases:
swagger_spec_compatibility.walkers.required_properties.RequiredPropertiesDiff
-
class
swagger_spec_compatibility.walkers.required_properties.
RequiredPropertiesDifferWalker
(left_spec, right_spec)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
diffs
= None¶
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
right_spec
= None¶
-
-
class
swagger_spec_compatibility.walkers.response_paths.
ResponsePathsWalker
(left_spec, right_spec)[source]¶ Bases:
swagger_spec_compatibility.walkers.SchemaWalker
-
dict_check
(path, left_dict, right_dict)[source]¶ Compare the left and right content of path in case both objects are dictionaries.
-
left_spec
= None¶
-
list_check
(path, left_list, right_list)[source]¶ Compare the left and right content of path in case both objects are list.
-
paths
= None¶
-
right_spec
= None¶
-
Changelog¶
1.2.0 (2019-03-27)¶
- Expose read-the-docs documentation links for rules defined by the library (PR #9)
1.1.0 (2019-03-07)¶
1.0.1 (2019-02-26)¶
- Updated package metadata
1.0.0 (2019-02-26)¶
- Initial library implementation with definition of the following rules:
- [REQ-E001] - Added Required Property in Request contract
- [REQ-E002] - Removed Enum value from Request contract
- [REQ-E003] - Removing properties from an object with additionalProperties set to False used as request parameter
- [RES-E001] - Added properties in an object with additionalProperties set to False used in response
- [RES-E002] - Remove a required property from an object used in responses
- [RES-E003] - Added Enum value in Response contract
- [MIS-E001] - Delete an endpoint
- [MIS-E002] - Changed type