We're considering versioning the CMR API and we'd like to get feedback on the preferred approach. We're not sure which approach we want to use yet so if you have feedback we'd appreciate it. The following information is from my winter 2016 ESIP presentation.

API Versioning Strategies

URI Path

The version is placed somewhere inside the path of the URL.

https://cmr…/search/v2/collections
  • Popular (Twitter, etc)
  • Problems
    • URIs should be stable. A client has to look inside the URI to know which version of the API it's using. It may have to modify the URL to choose a different version.
    • Granularity problems
      • What does v2 in the URL above refer to? Is it versioning just the search API or searching collections api? 

Query Parameter or Custom Header

This is similar to putting the version in the URI path except it's sent as a query parameter or header

https://cmr…/search/collections?ver=2 
  • Easy to use.
  • Problems
    • It's still technically part of the URI and has similar downsides the URI.
    • Granularity issues are worse than the URI. The version is very ambiguous here. 

Content Negotiation

Content Negotiation means that the client specifies versions for the request content type and response content type separately via the built in HTTP mechanisms. HTTP supports the headers Accept and Content-Type to indicate what's being requested or sent.

GET https://cmr…/search/collections
Accept: application/vnd.nasa.cmr.reference.v2+json

In this example a collection search is sent and the client has requested the version 2 of the CMR reference response in JSON format. (That doesn't currently exist now. We have a reference format in XML only)

  • RESTful
  • Request and responses are versioned separately. (Unambiguous granularity)
  • URLs stay the same
  • Problems
    • More difficult to specify.

Some clients may have difficulty sending HTTP headers. We could offer content negotiation via a URL extension as a workaround for those clients.

GET https://cmr.../search/collections.ref_v2_json
  • No labels

5 Comments

  1. I generally lean toward content negotiation, but do note that it assumes a well-defined media type. Clients need to know what assumptions they can make in terms of the names, structure, and presence of fields within a given version of a media type so that both clients and the CMR can be on the same page about what constitutes a new version.

    The one thing that content negotiation doesn't quite cover is query format. If you change the name or format of a query parameter, the accept header isn't an appropriate place for clients to express that they want to use one or the other query version (nor is Content-Type in the case of GET parameters). It is much easier to maintain backward compatibility in query formats, though.

    Finally, I expect clients will want an easy way to query the latest version of the API. I could see reasons for and against allowing it, as it circumvents versioning somewhat, but there should be a good answer to the question of whether to allow it.

  2. FWIW, at NSIDC we took the URI path approach. Example URL: http://nsidc.org/api/dataset/metadata/v2/oai?verb=Identify

    The version number refers to the concepts to the left of the version number in the URL (the "api/dataset/metadata") part.

    I think Content Negotiation is the "right" way to do it, but there were enough unknowns with regard to client capabilities that using the URL path was deemed the most robust solution at this point in time. The query parameter/custom header approach is the least desirable, in my opinion.

  3. Any thoughts on providing a RAML based description http://raml.org/ to help track capabilities between versions.

    One can generate documentation for each version: e.g. https://rawgit.com/raml2html/raml2html/master/examples/example.html#

    1. user-7b92a

      I hadn't heard of RAML before. It looks interesting. Thanks for the link!. We have an associated issue for CMR API Versioning. I made a note that we should investigate RAML as one possible option.

      Have you used RAML before or used an API that used RAML?

      1. There is also http://swagger.io/  which provides similar capabilities for top down or bottom up approaches.