[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¶
Old Swagger Specs¶
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
|
New Swagger Specs¶
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
|
Backward Incompatibility¶
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