API versioning
API versioning
The term API version refers to what is written in the version field of an API OAS definition file.
The reference documentation on versioning APIs and event types is part of the Commonalities / documentation
design documents in GitHub.
API VERSIONING IN A NUTSHELL
API versioning is done using SemVer 2.0.0: vx.y.z with x, y and z being numbers indicating MAJOR, MINOR and PATCH versions.
In addition to the target public API versions x.y.z, internally to the CAMARA project during the API release process version extensions are used for pre-releases (described in the section below):0.10.0
alpha API versions
release-candidate API versions
Finally,
work-in-progress (wip) is used as the API version before the first pre-release and between 2 pre-releases
IMPORTANT: CAMARA public APIs with x=0 (v0.y.z) MUST use both the MAJOR and the MINOR version number separated by a dot (".") in the API version in the OAS servers/url field: v0.y, e.g. {apiRoot}/quality-on-demand/v0.10
The following types of API versions are used throughout an API's release process:
work-in-progress (wip) API versions used before the first pre-release or between pre-releases. Having "wip" in the API version field indicates that PRs are ongoing and that the API is not usable by API consumers. The first PR should set the API version to wip, and the next "release PR" shall set the API version to the next (semver) x.y.z version.
alpha (x.y.z-alpha.m) API versions (with extensions) for CAMARA internal API rapid development purposes
release-candidate (x.y.z-rc.n) API versions (with extensions) for CAMARA internal API bug fixing purposes
public (x.y.z) API versions for usage in commercial contexts. Public API versions only have API version number x.y.z (semver 2.0), no extension. The public API can have one of two maturity states:
initial (x=0) - indicating that the API is still not fully stable
stable (x>0) - indicating that the API has reached a certain level of maturity
The use of the different API versions throughout the API release process is illustrated in the following figure.
The next sections provide the definition of terms used and the description of the different API version types when moving through the release process.
Definitions
API version
The API version is defined in the "version" field of the OAS definition file of an API. Its content must follow Semantic Versioning 2.0.0 | Semantic Versioning (semver.org).
An API version has the format: x.y.z where x, y and z are numbers corresponding to MAJOR, MINOR and PATCH versions.
The following bullets are extracted of the semver 2.0 specification (and links to the corresponding spec item).
NOTE: The below text is copied “as is” from semver 2.0 - in CAMARA also 0.y.z API versions can be public APIs: v1.0.0 CAMARA API versions are considered the stable public API, while API versions v0.y.z can be public, but are considered unstable (initial).
Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable. https://semver.org/#spec-item-4
Version 1.0.0 defines the public API. The way in which the version number is incremented after this release is dependent on this public API and how it changes. https://semver.org/#spec-item-5
Patch version Z (x.y.Z | x > 0) MUST be incremented if only backward compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior. https://semver.org/#spec-item-6
Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backward compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if substantial new functionality or improvements are introduced within the private code. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.
Major version X (X.y.z | X > 0) MUST be incremented if any backward incompatible changes are introduced to the public API. It MAY also include minor and patch level changes. Patch and minor versions MUST be reset to 0 when major version is incremented.
Precedence example: 0.10.0 < 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1 < 3.0.0.
API version extensions
During API development and release preparation, API version extensions are used to identify intermediate versions of an API.
The API version extension is added to the "version" field of the OAS definition of an API, as well as to the URL (see below table). Its content must follow the here described syntax and semantics.
The following extensions may be used in the API version:
alpha API versions: -alpha.m
release-candidate API versions: -rc.n
Extensions are post-fixed to the API version numbers and separated from it by a hyphen "-". m and n are numbers starting at 1.
To avoid duplication in the version number in the URL (see next section), both alpha and release-candidate (rc) version extension numbers are numbered consecutively across API versions, including for patch releases. Hence, within an API’s release cycle, alpha and rc numbers will for example be done as follows:
v1.1.0-alpha.1 → v1.1.0-alpha.2 → v1.1.0-rc.1 → v1.1.0-rc.2 → v1.1.0 → v1.1.1-alpha.3 → v1.1.1-rc.3 → v1.1.1
with the URL: /v1alpha1 → /v1alpha2 → /v1rc1 → /v1rc2 → /v1 → /v1alpha3 → /v1rc3 → /v1
Note: API consumers in production using public API versions will always only see /vx (x>0) or /vx.y (x=0).
All extensions must have a number (so just -alpha or -rc is not allowed) and should be minimally -alpha.1 or -rc.1.
The very first version of an API for which a release can be created is 0.1.0-alpha.1.
API version in URL
The OAS API definition file contains the URL definition for the API endpoint which includes the version of the API with the following format:
A lowercase "v" followed by the MAJOR number from the API version, e.g. for quality-on-demand v2.1.0, it will be v2 as follows:
servers:
url: {apiRoot}/quality-on-demand/v2
Once a stable public API version is created, the API version in the URL shall ONLY contain "vx", and never include an extension.
IMPORTANT: For initial public API versions 0.y.z, the MINOR number MUST be included in the URL, e.g. v0.y. A dot (".") is used for readability.
in this stage of the API development, y is used to indicate MAJOR (breaking) changes, and z is used to indicate MINOR (non-breaking) changes. Patches, if needed would also increase z.
For alpha and release-candidate API versions, the API version extension shall be included in the URL, but without any hyphens or dots.
Example: for an alpha API version 2.y.z-alpha.1, the version in the URL is v2alpha1, e.g. {apiRoot}/quality-on-demand/v2alpha1.
API name
The API name is the segment in the url
field in the OAS definition file before the segment holding the API version.
Example: for the above url: {apiRoot}/quality-on-demand/v2
, the API name is quality-on-demand
.
API version types
The following table provides the characteristics of the different API version types that an API will go through during its release process.
API version type | Purpose & characteristics |
---|---|
work-in-progress (wip) | The purpose of a work-in-progress API version is to indicate that the API is unstable due to one or more PRs being committed, possibly resulting in temporary inconsistencies.
|
alpha (alpha) | The purpose of an alpha API version is to support rapid development of an API and the creation of test implementations for feedback purposes.
|
release-candidate (rc) | The purpose of a release-candidate API version is to allow for (only) bug fixing encountered during further API implementation testing.
|
public | The purpose of a public API version is that it can be used by organizations outside CAMARA in application development and commercial contexts.
|
initial | Initial public API versions only exist for new APIs.
|
stable | Stable public API versions are public API versions with x > 0 (x.y.z without version extension). Stable public API versions are the ones recommended for use in commercial applications. The user can expect that subsequent API versions will be backward-compatible with the one they are using, unless explicitly announced otherwise. |
Creation of a public API version
To create a public version of an API the following steps need to be taken:
First, using wip in the API version, develop your API until it is sufficiently stable to create a first alpha API version 0.1.0-alpha.1.
Create one (or more) alpha API versions to stabilize the API.
Create the first release-candidate API version proposed for testing (for the M3 milestone).
Create one (or more) release-candidate API versions following feedback from testers (between the M3 and the M4 milestones).
Create the public API version proposed for the meta-release (for the M4 milestone).
Finally, publish the public API version (in the meta-release).
IMPORTANT
All alpha and release-candidate API versions are INTERNAL to the CAMARA project and meant to be used only for the API development and release management process. Usage for other purpose is at the user's own risk.
The below table gives an overview of the API versioning through the release process. The column headers mean the following:
API version type: refers to the stage in the API life cycle: wip, alpha, release-candidate or public.
API version: (without or with an extension) is what is put in the version field in the API OAS definition file.
NOTE: a public API version shall never have an extension.
API version in URL (initial/stable): is a lowercase "v" followed by the MAJOR number from the API version. This is put in the URL field in the Servers object in the API OAS definition file.
NOTE: for an initial API version (x=0), the API version in the URL is exceptionally allowed to contain both the MAJOR and the MINOR version numbers (v0.y).
API version can be released: A release can be created for the API version (with or without (for alpha) a release package).
The following table gives the values of the API version (Info object) and the API version in the URL (servers object) used during the release process of an API version.
API version types in the release process | API version | initial (x=0) API version in URL (OAS Servers object) | stable (x>=1) API version in URL (OAS Servers object) | API version can be released |
---|---|---|---|---|
work-in-progress | wip | vwip | vwip | No |
alpha | x.y.z-alpha.m | v0.yalpham | vxalpham | Yes (internal pre-release) |
release-candidate | x.y.z-rc.n | v0.yrcn | vxrcn | Yes (internal pre-release) |
public | x.y.z | v0.y | vx | Yes (release) |
Precedence examples for API versions throughout the release process:
0.1.0 < 0.2.0-alpha.1 < 0.2.0-alpha.2 < 0.2.0-rc.1 < 0.2.0-rc.2 < 0.2.0 (initial public version)
1.0.0 < 1.1.0-alpha.1 < 1.1.0-alpha.2 < 1.1.0-rc.1 < 1.1.0-rc.2 < 1.1.0 (stable public version)
Update of a public API version
Updates to a public API version can concern MAJOR, MINOR or PATCH changes to the API definition.
For MAJOR or MINOR changes, the process is the same as for the creation of a public API version (see previous section), going through alpha and release-candidate API versions to create the updated public API version.
MINOR: 0.9.0 → 0.9.1-alpha.1 → ... → 0.9.1-alpha.m → 0.9.1-rc.1 → ... → 0.9.1-rc.n → 0.9.1 (next initial public version)
MINOR: 1.0.0 → 1.1.0-alpha.1 → ... → 1.1.0-alpha.m → 1.1.0-rc.1 → ... → 1.1.0-rc.n → 1.1.0 (next stable public version)
MAJOR: 0.9.1 → 0.10.0-alpha.1 → ... → 0.10.0-alpha.m → 0.10.0-rc.1 → ... → 0.10.0-rc.n → 0.10.0 (next initial public version)
MAJOR: 1.1.0 → 2.0.0-alpha.1 → ... → 2.0.0-alpha.m → 2.0.0-rc.1 → ... → 2.0.0-rc.n → 2.0.0 (next stable public version)
For PATCH changes, the API Sub Project can decide to either
apply a short process to create a maintenance-release of the public API version (no change of release of Commonalities and ICM).
apply the CAMARA API release process, as for MAJOR and MINOR changes resulting in a new API version x.y.z+1: this should be applied when the PATCH version is released that include patches updates to align with a different version of Commonalities and ICM.
2.0.0 → 2.0.1-alpha.1 → ... → 2.0.1-alpha.m → 2.0.1-rc.1 → ... → 2.0.1-rc.n → 2.0.1 (next stable public version)
It is recommended to have maximally 2 consecutive public API versions available at any given point in time.
Event versioning
For CAMARA subscription APIs, events are defined using the CloudEvents format. The CloudEvent specification provides some information on CloudEvent versioning, but some additional CAMARA event versioning guidelines are described in this section.
CloudEvent versioning states the following (quoted):
When a CloudEvent's data changes in a backwardly-incompatible way, the value of the type attribute should generally change. The event producer is encouraged to produce both the old event and the new event for some time (potentially forever) in order to avoid disrupting consumers.
When a CloudEvent's data changes in a backwardly-compatible way, the value of the type attribute should generally stay the same.
For CAMARA events, the type
attribute is the base for event versioning as it contains the event version.
The format of the
type
attribute value is defined by Commonalities in the CAMARA-API-Event-Subscription-and-Notification-Guide document as:org.camaraproject.<api-name>.<event-version>.<event-name>
.The
<event-version>
has the formatvx
.x
is the version number of the event’s structure.
Examples of CAMARA event types (= value of the type
attribute) are:
org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on
org.camaraproject.device-roaming-status-subscriptions.v1.roaming-status
The event version is independent of the API version that the event belongs to.
Example: A v2
API can still use a v1
event version if the event structure is unchanged with this MAJOR API version.
Events are considered to be “first class citizens” just like APIs and have their own versioning throughout their lifecycle. For example,
The same event version may be supported by different versions of an API.
An event client may be subscribed to a given event version from different API providers with different API versions, but expect to receive the same event data.
CAMARA event versioning guidelines
CAMARA event versioning extends the CloudEvent versioning as described in the following table:
Note: unless indicated otherwise, the below applies for both explicit and implicit event subscriptions.
Event version | CAMARA event versioning explanation |
---|---|
v0 .. vn (new subscription API) | For an initial API Stable APIs must use stable events with version number > 0. When publishing a first stable version of an API, any event version with |
vn (n>0) (backward compatible update of an event) | A MINOR or PATCH update of an event structure does not change the event version, but does imply a new MINOR or PATCH version of the API. Such changes to the event structure are backward compatible and should not impact event clients. |
vn → vn+1 (non backward compatible update of an event) | Any MAJOR change to an event structure implies the introduction of the next event version
Note 1: The deletion of an event version implies always a MAJOR API version change. Note 2: The decision to keep previous event version(s) is a decision of the API Sub Project team. Note 3: In case of implicit event subscriptions, only replacement of the previous event version `vn` in the API definition is possible and will imply always a MAJOR API version change. |
v1 (adding a new event) | Introducing a new event to a stable subscription API implies that this event gets the version The introduction of a new event to an existing API is considered as a MINOR API version update, as it shall not impact existing event clients. To force clients to take the new event into account, one can introduce it through a MAJOR API version change. |
removing an event or an event version | Removing an event or an event version from a stable subscription API implies a MAJOR update of the API version. |
Breaking and non-breaking changes
Semantic versioning on breaking changes:
breaking changes imply a MAJOR version increment (that's the fundamental part)
semver FAQ entry: https://semver.org/#if-even-the-tiniest-backward-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly
What is a breaking change?
deleting operations or actions on a resource. For example: POST requests on a resource are no longer accepted.
adding a new mandatory input parameters. For example: now, to register a resource, a new required field must be sent in the body of the request.
modifying or removing a mandatory parameter in existing operations (resource verbs). For example, when consulting a resource, a certain field is no longer returned, or a field that was previously a string is now numeric. (breaks existing payloads)
modifying or removing an endpoint (breaks existing queries)
changing input parameters from optional to mandatory. For example: when creating a Person resource, the age field, which was previously optional, is now mandatory.
modifying responses to existing operations.
adding new responses to existing operations. For example: creating a resource can return a 412 response code.
adding a new version of an event without keeping the previous version in parallel
removing an event version or all versions of an event
breaking changes to an event structure (follows the same rules as for API responses, see above)
What is a non-breaking change?
adding a new endpoint
adding a new operation (POST, GET, ...)
changing a mandatory parameter into an optional one. For example: when creating a resource, a property of said resource that was previously mandatory becomes optional.
adding optional input parameters to requests on existing resources. For example, adding a new filter parameter in a GET on a collection of resources.
adding new properties in the representation of a resource (response) returned by the server. For example, adding a new age field to a Person resource, which originally was made up of nationality and name.
adding a new event
adding a new version of an existing event if the previous event version is kept
non-breaking changes to an event structure (follows the same rules as for responses, see above)
How to avoid breaking changes (API provider) ?
never change an endpoint name; instead, add a new one and mark the original one for deprecation in a MINOR change and remove it in a later MAJOR (see semver FAQ entry: https://semver.org/#how-should-i-handle-deprecating-functionality)
If possible, do the same for attributes
new fields should always be added as optional.
Postel's Law: “Be conservative in what you do, be liberal in what you accept from others”. When you have input fields that need to be removed, mark them as unused, so they can be ignored.
do not change the field’s semantics.
do not change the field’s order.
do not change the validation rules of the request fields to more restrictive ones.
if you use collections that can be returned with no content, then answer with an empty collection and not null.
layout pagination support from the start.
How to avoid breaking changes (API consumer) ?
tolerant reader: if it does not recognize a field when faced with a response from a service, do not process it, but record it through the log (or resend it if applicable).
ignore fields with null values.
variable order rule: DO NOT rely on the order in which data appears in responses from the JSON service, unless the service explicitly specifies it.
clients MUST NOT transmit personally identifiable information (PII) parameters in the URL. If necessary, use headers
Make the information available:
provide an access to the new API version definition file (via a link or dedicated endpoint)
if possible, do the same to obtain the currently implemented API version definition file
Bearing in mind that APIs are continually evolving and certain operations will no longer be supported, the following considerations must be taken into account:
Agree to discontinue an API version with consumers.
Establish the obsolescence of the API in a reasonable period (6 months).
Monitor the use of deprecated APIs.
Remove deprecated APIs documentation.
Never start using already deprecated APIs.