[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

Old Swagger Specs

 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: ''

New Swagger Specs

 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: ''

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
# -*- 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