Hey guys!
tl;dr -- We need to get API versioning right. I'm proposing we use major versions in Accept/Content-Type headers.
In order for OpenStack to be successful, we need rock solid APIs. That means having something stable that fully exposes the necessary functionality of the underlying service. In the case of the Compute API, I think we're fairly well off in terms of functionality. However, in order to achieve stability, we still need to get a few things right. I wanted to look at the Compute API first, as that's what I'm most involved in on a daily basis. What I've been concentrating on specifically is versioning.
There are several aspects of API versioning that must be considered:
Numbering
- Major, minor, bugfix?
Backwards Compatibility
- At what level do you support backwards compatibility, if at all?
Communication
- Version in URI, mimetypes, or both?
Versions Collection
- Provide a complete list of supported versions?
Unsupported Versions
- What do you do when a request is made with an unsupported version?
Defaults
- Allow requests without explicit versions?
Scope
- Do versions apply to the complete API or to subsections? ...or both?
In order to help answer these questions, I looked at how some other popular service APIs are designed:
Twitter [1]
- Major version only
- Exposed in URI
Netflix [2]
- Major and minor versions
- Supports 1.0, 1.5, 2.0 (unclear how backwards-compatibile these are)
- Allows users to supply 'v' query param to specify version
- Defaults to 1.0
GitHub [3]
- Major versions only
- Backwards compatability not guaranteed and documented where broken
- v2 supports version in uri
- v3 supports version in Accept header (application/vnd.github.v3+json)
- No version implies latest
Facebook
- No real versioning, just different service endpoints (currently differentiated by subdomains)
- legacy REST api wasn't versioned [4], and was replaced with unversioned Graph API [5]
Amazon EC2 [6]
- One implied major versions
- Timestamped feature releases (minor versions)
- Indicate version with query param
- Assume latest, since it will always be backwards compatibile
Sun Cloud API [7]
- No version in URI
- Allow user to send X-YYYYY-Specification-Version header to indicate what version they are speaking
- Root resource communicates its underlying implementation version and supported specification version(s)
So there obviously isn't one clear way to version a RESTful API. Not every API is created equal, and therefore doesn't need the same capabilities in its versioning mechanism. At this point, it is important to determine what specifically the Compute API needs:
- Our versioning mechanism should not hinder progress within the underlying implementation
- We need to be able to iterate on the design of our API without being tied down
- It needs to be simple to use from the point of view of API developers AND language bindings authors
With those goals in mind, I would like to propose we adopt the following mechanism:
- Use only major versions
- Allow backwards incompatibility between major versions
- Expose version of response in Content-Type header (application/vnd.openstack.compute.v3+json)
- Form request with version in Accept/Content-Type headers
- If no version is provided in request, default to stable
- If an unsupported version is requested, provide a 300 Multiple Choices response w/ list of available versioned mimetypes
- Provide a mechanism that can communicate all supported mimetypes (versions)
I would love to hear your feedback on this proposal, however, I'm not really looking to get into a fight about what's more RESTful ;) I know we already have several (slightly different) versioning mechanisms in place, but this is something that can't be wrong. There's still a lot to figure out here, but I think this is a good subset that we can reach an agreement on. In order for OpenStack to be successful, we need to get these foundation pieces right!
Brian Waldon (bcwaldon)
[1] https://dev.twitter.com/docs
[2] http://developer.netflix.com/docs/REST_API_Conventions
[3] http://developer.github.com/v3/
[4] http://developers.facebook.com/docs/reference/rest/
[5] http://developers.facebook.com/docs/reference/api/
[6] http://aws.amazon.com/documentation/ec2/
[7] http://kenai.com/projects/suncloudapis/pages/Home