Versioning
Preserving compatibility
|
Don’t Break Backward Compatibility
Change APIs, but keep all consumers running. Consumers usually have independent release lifecycles, focus on stability, and avoid changes that do not provide additional value. APIs are service contracts that cannot be broken via unilateral decisions. |
There are two techniques to change APIs without breaking them:
-
evolve the API, allowing clients to gradually implement changes by following rules for compatible extensions and deprecation
-
introduce new major API version and still support older version(s) for a period in which clients can transition to the new version
Backwards-incompatible changes, requiring a big bang release, are only feasible if:
-
there is a very limited number of clients
-
the release is well coordinated
-
a temporary service interruption is allowed.
In this case, the major version number could be kept the same as only a single version of the API is active at a given time and it can be easier to keep the base URL of the API unchanged.
Rule: Prefer API evolution [api-evol]
We strongly encourage using API evolution when possible and discourage versioning:
-
versioning requires maintaining and supporting two service contracts
-
API evolution maintains stable URIs (e.g. links from other APIs) and allows for a more gradual migration of clients
| Use of media type versioning (using Accept/Content-Type HTTP headers) isn’t included as an option in this guide as it has various practical problems |
API evolution
For extensibility, the JSON body of a RESTful request or response should always be a JSON object instead of an array, string, number, etc. ([evo-object]). This way the request or response can always be extended with new properties.
With Postel’s Law in mind, here are some rules for providers and consumers that allow us to make compatible changes without versioning:
Rule: Compatible extensions [evo-compat]
Apply the following rules to evolve RESTful or asynchronous APIs in a backward-compatible way:
-
New fields may be added to output, if they can be safely ignored by existing clients. Clients MUST ignore unknown fields in output.
-
Add only optional, never mandatory input fields.
-
Never change the meaning of a field.
-
Never change input validation logic to be more restrictive.
-
Enum values can be added, but not removed when used as input parameters.
-
Enum values can be removed when used as output parameters, but not added as clients might not be ready to handle them.
-
A new resource variant (with another name) can be created in addition to the old resource variant.
Note that while clients must ignore unknown response fields, APIs may refuse requests containing unknown fields ([req-valid]).
Redirection (301 Moved Permanently) MAY be supported when a URL has to change, but don’t assume clients are configured to automatically follow them.
Rule: Deprecation [evo-deprec]
Deprecation MAY be used to indicate parts of an API are not recommended to be used anymore. Their deprecation SHOULD be documented in OpenAPI . Deprecated elements MAY be completely removed them after a period in which clients can adapt. Always communicate clearly about the deprecated fields and transition period to clients.
deprecated: true SHOULD be used wherever OpenAPI 3.0 allows it: on operations, parameters, headers and Schema Objects (data types). Otherwise, like on security schemes, the custom extension x-deprecated: true SHOULD be used. AsyncAPI only allows deprecated: true on Schema Objects.
Use of deprecated elements in requests may be monitored by the server in order to evaluate the impact of their removal. However, this isn’t possible for response elements, so there is always remains some risk for breaking clients.
API versioning
Rule: Version numbering [api-version]
The version string of an API SHOULD contain a major, minor and optionally a patch number.
Only the major version of the API is part of the base URL of the API.
Thereby, for a major version only a single minor and patch version can be available in production at a time.
The version of the API MUST be included in the info section of the OpenAPI definition.
Note that reusable OpenAPI documents are to be versioned as well, as specified in OpenAPI.
Following REST API has version 2.1.2, as specified in its OpenAPI definition, while only the major version part v2 is part of the base URL:
openapi: "3.0.4"
info:
title: petShop
description: API exposing my pet shop's functionality
version: "2.1.2"
servers:
url: https://example.org/petShop/v2
Following asynchronous API has version 3.7.1, as specified in its AsyncAPI definition, while only the major version part v3 is part of the asynchronous messages' service and type properties:
asyncapi: 3.0.0
info:
title: Meeting
version: 3.7.1
description: |
The meeting API allows you to manage meetings and get notifications upon meeting changes.
{
"specversion": "1.0",
"id": "450e8400-e29b-41d4-a716-446655440007",
"service": "be.belgif.example.meeting.v3",
"type": "be.belgif.example.meeting.v3.meeting.created",
"...": "..."
}
Similar guidelines apply to sunset an old major version of an API apply as for removal of deprecated elements.
Rule: Removing an old version [ver-del]
Before removing an old API version:
-
provide a transition period supporting old and new versions at the same time before removing the old version
-
always communicate clearly about the transition period to clients
-
use of the old version may be monitored by the server in order to evaluate the impact of their removal.