Today Candlepin has only one API which causes a problem with revising and backwards compatibility. There are a few ways we can solve this and they each have their pros and cons. They all have a common solution which is versioning the API, the difference is in implementation.
This is a classic form of versioning APIs used by many sites. Smugmug, Google, and many others.
The change involves adding the version to the URL in either straight up number
or v#. For example, /candlepin/VERSION/owners/
i.e. /candlepin/v1.1/owners/
or /candlepin/1.1/owners/
.
I think if we go with this approach it’s best to create a new Java package with the versions in it or some other way of breaking up the resources i.e. candlepin.resource.1.1.OwnerResource. One possible solution to avoid duplication of code is to inherit from older resources. 1.1.OwnerResource would extend resource.OwnerResource. The big downside to this approach is the deep tree we will end up with. If we want to avoid the tree, we can use composition and call the unchanged methods from the other resources.
Another idea floating around is creating media types to handle the versions. Peter Williams used this idea to version his APIs: http://barelyenough.org/blog/2008/05/versioning-rest-web-services.
Bill Burke outlines using media types to distinguish API versions in his
RESTful Java with
JAX-RS
book. Effectively, you define a new media type under the vendor tree vnd
for
example: application/vnd.rht.customers+json
or
application/vnd.candlepin.owners+json;version=1.1
.
Then you add @Produces
to the methods that are upgraded.
Benefits to using the media type are we can continue to use the same resources classes and urls.
Legacy clients would be unchanged, Candlepin would continue to accept plain
JSON. New clients would send up
application/vnd.candlepin.owners+json;version=1.1
as the accept header.
Sending newer version to older api version.
curl -k -u admin:admin -H "Accept: application/vnd.candlepin.status+json;version=2.0" https://localhost:8443/candlepin/status/newstatus/
{"displayMessage":"Runtime Error No match for accept header at org.jboss.resteasy.core.registry.Segment.match:119"}
Sending no header defaults to JSON (that’s candlepin doing that):
curl -k -u admin:admin https://localhost:8443/candlepin/status/newstatus/
{"result":true,"version":"0.6.2","release":"1","standalone":true,"timeUTC":"2012-05-15T16:58:40.862+0000"}
Sending non matching header (older client to a new method):
curl -k -u admin:admin -H "Accept: application/vnd.candlepin.status+json" https://localhost:8443/candlepin/status/newstatus/
{"displayMessage":"Runtime Error No match for accept header at org.jboss.resteasy.core.registry.Segment.match:119"}
Calling updated version of status:
curl -k -u admin:admin -H "Accept: application/vnd.candlepin.status+json;version=1.1" https://localhost:8443/candlepin/status/
{"result":true,"version":"0.6.2","release":"1","standalone":true,"timeUTC":"2012-05-15T17:01:16.536+0000"}
Using 2 methods with same url but different @Produces
to differentiate versions:
curl -k -u admin:admin -H "Accept: application/vnd.candlepin.status+json;version=1.1" https://localhost:8443/candlepin/status/
{"result":true,"version":"0.6.2","release":"1","standalone":true,"timeUTC":"2012-05-15T17:13:28.328+0000"}
curl -k -u admin:admin -H "Accept: application/vnd.candlepin.status+json;version=1.5" https://localhost:8443/candlepin/status/
{"result":true,"version":"status1.5","release":"5","standalone":true,"timeUTC":"2012-05-15T17:13:52.613+0000"}
Today we do a lot of work to maintain backwards compatibility with older
clients. Maybe it is possible to simply use the /status
url to determine a
particular Candlepin version that supports the feature needed by the client.
Please add your questions and comments to the bottom with your username.