API versioning section for Commonalities API design guidelines

New proposed text 

REVIEW CLOSED HERE - PLEASE REVIEW PULL REQUEST

See PR in Commonalities: Update versioning section in api design guidelines · Pull Request #215 .

5. Versioning

Versioning is a practice by which, when a change occurs in the API, a new version of that API is released so that the new version and the previous one coexists for a certain period of time.

API versions use a numbering scheme in the format x.y.z, where x, y and z are numbers corresponding to MAJOR, MINOR and PATCH versions. MAJOR, MINOR and PATCH refer to the types of changes made to an API through its evolution. Depending on the change type, the corresponding number is incremented. This is defined in the Semantic Versioning 2.0.0 (semver.org) standard.

5.1. API version

The API version is defined in the "version" field (in the Info object) of the OAS definition file of an API. 

info:

title: Number Verification

description: text describing the API

version: 2.2.0  

....

In line with Semantic Versioning 2.0.0, the API with MAJOR.MINOR.PATCH version number, increments:

  1. The MAJOR version when an incompatible / breaking API change is introduced

  2. The MINOR version when functionality is added that is backwards compatible

  3. The PATCH version when backward compatible bugs are fixed

For more details on MAJOR, MINOR and PATCH versions, and how to evolve API versions, please see versioning in the API release process in the Release Management wiki. 

It is recommended to avoid breaking backwards compatibility unless strictly necessary: new versions should be compatible with previous versions. More information on how to avoid breaking changes can be found in the section below.

5.2 API version in URL

The OAS file also defines the API version used in the URL definition (in the servers object).

The API version in the URL only includes the "x" (MAJOR version) number of the API version as follows:

servers:

    url: {apiRoot}/qod/v2 

NOTE: CAMARA exceptionally allows to use both the MAJOR and the MINOR version number (v0.y) separated by a dot (".") in initial API versions (x=0) in the API version in the URL.

This allows for test and usage of initial API versions as they are evolving rapidly, e.g. /qod/v0.10, or /qod/v0.11alpha1. However, it should be acknowledged that any initial API version may change.

5.3 API versions throughout the release process.

In preparation for its public-release, an API will go through various intermediate versions indicated by version extensions: alpha and release-candidate.

Overall, an API can have any of the following versions:

  • work-in-progress (wip) API versions used during the development of an API before the first pre-release or in between pre-releases. Such API versions cannot be released and are not usable by API consumers.

  • 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 release bug fixing purposes

  • public-release (x.y.z) API versions for publication as part of a meta-release. These API versions only have API version number x.y.z (semver 2.0), no extension. The public-release API can have one of two maturity states: 

    • initial - indicating that the API is still not fully stable (x=0)

    • stable - indicate that the API has reached a certain level of maturity (x>0)

The following table gives the values of the API version (Info object) and the API version in the URL used in the release process of the API, and dependent on whether it is an initial API version (x=0) or a stable API version (x>0).

API versions in  release process

API version
(OAS Info object)

initial (x=0) API version in URL (OAS Servers object)

stable (x>0) API version in URL (OAS Servers object)

API version can be released

API versions in  release process

API version
(OAS Info object)

initial (x=0) API version in URL (OAS Servers object)

stable (x>0) 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)

release-candidate 

x.y.z-rc.n

v0.yrcn

vxrcn

Yes (internal)

public-release

x.y.z

v0.y

vx

Yes

Precedence examples:

  • 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1 < 3.0.0.

  • 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-release)

  • 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-release)

For more information, please see the API versioning page in the Release Management Project Wiki.

Breaking and non-breaking changes

Semantic versioning on breaking changes:

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

  • adding new responses to existing operations. For example: creating a resource can return a 412 response code.

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 returned by the server. For example, adding a new age field to a Person resource, which originally was made up of nationality and name.

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 release and remove it in a later major release (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

Text from current API guidelines

italic means moved to or covered in the new text above

strikethough means not reused

underlined means moved to RM wiki page

5. Versioning

5.1 Versioning Strategy

Service versioning is a practice by which, when a change occurs in the API of a service, a new version of that service is released so that the new version and the previous one coexists for a certain period of time.

Consumers will be migrated to the new version of the service sequentially. When everyone is consuming the latest version of the service, the previous version is removed.

Consumers can distinguish between one version of the service and another, the technique of adding the API version to the context of the base URL will be used, since this technique is the most used in the main reference APIs.

The structure of the URL would have the following form:

https://host:port/api/v1/resource

When we version through the URL, only the "MAJOR version" is included since this would change when a change incompatible with the previous version occurs.

API implementation versioning will follow semantic versioning. Given a MAJOR.MINOR.PATCH version number, it increments:

  1. The MAJOR version when you make an incompatible API change.

  2. The MINOR version when you add functionality that is backwards compatible.

  3. The PATCH version when you fix backward compatible bugs.

Related to the versioning of rest parts involved in Apification projects, best practises are detailed below:

SHARED CODE ON REPOSITORIES

  1. MAJOR - Major of API Contract

  2. MINOR - Minor of API Contract

  3. PATCH - New Updates / Contributions of shared code

MICROSERVICE DEPLOYMENTS (NOT MANDATORY BUT RECOMMENDED)

  1. MAJOR - Major of API Contract

  2. MINOR - Minor of API Contract

  3. PATCH - New Microservice Deployments

5.2 Backwards and Forward Compatibility

Avoid breaking backwards compatibility unless strictly necessary, that means, new versions should be compatible with previous versions.

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 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.

Types of modification

Not all API changes have an impact on API consumers. These changes are often referred to as backward compatible changes. If the API undergoes changes of this type, it should not be necessary to release a new version, it will suffice to replace the current one. What would be very convenient is to notify our consumers with the new changes so that they take them into account.

This is a list of changes to an API that DO NOT affect consumers:

  • Add new operations to the service. Translated to REST, it would be to add new actions on a resource (PUTPOST, ...).

  • Add optional input parameters to requests on existing resources. For example, adding a new filter parameter in a GET on a collection of resources.

  • Modify input parameters from required to optional. For example: when creating a resource, a property of said resource that was previously mandatory becomes optional.

  • Add new properties in the representation of a resource returned by the server. For example, adding a new age field to a Person resource, which originally was made up of nationality and name.

This other list shows changes that DO affect consumers:

  • Delete operations or actions on a resource. For example: POST requests on a resource are no longer accepted.

  • Add new mandatory input parameters. For example: now, to register a resource, a new required field must be sent in the body of the request.

  • Modify input parameters from optional to mandatory. For example: when creating a Person resource, the age field, which was previously optional, is now mandatory.

  • Modify a parameter in existing operations (resource verbs). Also applicable to parameter removal. For example, when consulting a resource, a certain field is no longer returned. Another example: a field that was previously a string is now numeric.

  • Add new responses to existing operations. For example: creating a resource can return a 412 response code.

Compatibility management

Tho ensure this compatibility, the following must be followed.

As API producer:

  • 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.

As 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.