Pattern Sections
Pattern: Version Identifier
a.k.a. Explicit Versioning, Message-Level Version Information
Context
An API that runs in production evolves. New versions with improved functionality are offered over time. At some point in time, the changes of a new version are no longer backwards compatible; this caused existing clients to break.
Problem
How can an API provider indicate its current capabilities as well as the existence of possibly incompatible changes in order to prevent malfunctioning of API clients due to undiscovered interpretation errors?
Forces
- Accuracy and exact identification of API version
- Guaranteeing that API changes do not lead to accidentally breaking compability between client and provider on the semantic level
- Minimizing impact on the client side caused by API changes
- Traceability of API versions in use for governance
Pattern forces are explained in depth in the book.
Solution
Introduce an explicit version indicator. Include this Version Identifier in the API Description and in the exchanged messages. To do the latter, add a Metadata Element to the endpoint address, the protocol header, or the message payload.
Example
In REST APIs the version of different features can be indicated as follows. The version of specific representation formats supported by the client in the content type negotiation headers of HTTP:
GET /customers/1234
Accept: text/json+customer; version=1.0
...
The version of specific operations is found as part of the resource identifiers:
GET v2/customers/1234
...
The version of the whole API can also be specified in the host domain name:
GET /customers/1234
Host: v2.api.service.com
...
In SOAP/XML-based APIs, the version is usually indicated as part of the namespace of the top-level message element:
<soap:Envelope>
<soap:Body>
<ns:MyMessage xmlns:ns="http://www.nnn.org/ns/1.0/">
...
</ns:MyMessage>
</soap:Body>
</soap:Envelope>
Another possibility is to specify the version in the payload as in the following JSON example. In the initial version 1.0 of the billing API, the prices were defined in Euro:
{
"version": "1.0",
"products": [
{
"productId": "ABC123",
"quantity": 5;
"price": 5.00;
}
]
}
With a new version the requirement of multi-currency was realized.
This leads to the new data structure and the new contents of the
version
element:
{
"version": "2.0",
"products": [
{
"productId": "ABC123",
"quantity": 5;
"price": 5.00;
"currency": "USD"
}
]
}
If no Version Identifier or any
other mechanism to indicate a breaking change had been used, old
software interpreting the version 2.0 of the message would assume that
the product costs 5 EUR although it costs 5 USD. This is because a new
attribute has changed the semantics of an existing one. Passing the
version in the content type as shown above can eliminate this problem.
While it would be possible to introduce a new field
priceWithCurrency
to avoid this problem, such changes lead
to technical debt by aggregating over time, especially in less trivial
examples.
Are you missing implementation hints? Our papers publications provide them (for selected patterns).
Consequences
The resolution of pattern forces and other consequences are discussed in our book.
Known Uses
This pattern has many known uses, both public ones and company- or community-internal ones:
- Most public Web APIs use a simple, unstructured
Version Identifier in the request
URI, and many of them add it to response headers as well. One number
often is sufficient. The Facebook Graph
API and the Twitter APIs use a
n.m
convention (two digits). - GitHub uses the HTTP Accept Header.
- A large European bank places Version Identifiers on the operation level in its WSDL contracts and transmits them as part of the request and response messages.
- The Dynamic Interface described in Brandner et al. (2004) applies the pattern, indicating version identifiers in the service names (i.e., WSDL port types).
- The SOAP-based eCH APIs use XML
namespaces to realize the pattern. An example of such namespace is:
http://www.ech.ch/xmlns/eCH-0134/1
. XML namespaces are commonly defined with URIs.
More Information
Related Patterns
A Version Identifier can be seen as a special type of Id Element and/or Metadata Element; “Enterprise Integration Patterns” Hohpe and Woolf (2003) also discuss more general patterns that are related. The Version Identifier can be further structured, e.g., by using the Semantic Versioning pattern. The lifecycle pattern Two in Production requires explicit versioning; the other life cycle patterns (Aggressive Obsolescence, Experimental Preview, Limited Lifetime Guarantee, Eternal Lifetime Guarantee) may also use it.
Applying the Tolerant Reader pattern from “Service Design Patterns” Daigneau (2011) allows clients to tolerate some changes.
The visibility and role of an API drive related design decisions. For instance, the different life cycles, deployment frequencies, and release dates of provider(s) and client(s) in a Public API scenario for Frontend Integration make it necessary to plan service evolution beforehand and usually do not allow providers to make arbitrary ad hoc changes to already published APIs due to the impact of such changes on clients (e.g., downtimes, test and migration effort caused). Some or all of these clients might not even be known. A Community API providing Backend Integration capabilities between a few stable communication parties that are maintained on the same release cycle (and share a common roadmap) might be able to employ more relaxed versioning tactics. Finally, a Solution-Internal API connecting a mobile app frontend with a single backend (Frontend Integration) owned, developed, and operated by the same agile team might fall back to an ad hoc, opportunistic approach that relies on frequent, automated unit/integration tests within a continuous integration and delivery practice.
Other Sources
Because versioning is an important aspect of API and service design, there is much discussion about it in different development communities. The strategies differ widely, and versioning strategies are passionately debated. Opinions reach from no explicit versioning at all (sometimes just called “versioning”) because an API should always be backwards-compatible to the different versioning strategies compared by M. Little. James Higginbotham describes the available options here.
Chapter 11 of “SOA in Practice” Josuttis (2007) introduces a service life cycle in the context of Service-Oriented Architecture (SOA) design; Chapter 12 discusses versioning.
Chapter 13 of “Build APIs you won’t hate” Sturgeon (2016) discusses seven options for versioning (with the Version Identifier in URLs being one of these options) and their advantages and disadvantages. It also gives implementation hints.
Chapter 15 of “SOA with REST” Erl et al. (2013) deals with Service Versioning for REST.
Schema versioning is introduced in a blog post from Snowplow “Introducing SchemaVer for semantic versioning of schemas”.