Search code examples
ruby-on-railsrestapisemantic-versioning

REST Api and semantic versioning


My team has built several APIs and are now public. We are now adding features to one of our APIs that will be non-breaking for our existing clients, so this would be considered a minor update according to https://semver.org. We now realize we want to follow semantic versioning principles. We are also doing URI versioning. So let's say we're on v1.0.0 and now we should update it to v1.1.0. At the advice of other posts, if we decided to only ever expect the major version in the route, e.g. /api/v1/animals, but all clients would be upgraded to the latest version of v1 since it should be backwards compatible, this tells me that semantic versioning is handled internally. How is that typically handled? We have a Rails app and if our structure was as so:

/controllers
  /api
    /v1.0.0
      animals_controller.rb

If we updated to minor version v1.1.0, should we create a new v1.1.0 folder with a new animals_controller.rb file inside of it? Or if the changes are backwards compatible, then should the changes be in animals_controller.rb inside of v1.0.0? But if we do that, then really, shouldn't it just be:

/controllers
  /api
    /v1
      animals_controller.rb

? I'm getting the impression that semantic versioning is internal and not necessarily required to be exposed to the consumers... Is it just a matter of using tags?


Solution

  • The reason to make a real REST API is to get evolvability … a "v1" is a middle finger to your API customers, indicating RPC/HTTP (not REST) -- Fielding, 2013

    Part of the point of REST is that identifiers (URI) can be just identifiers, and the domain application protocol is described by hypermedia.

    So yes, if you are "doing REST correctly", then semantically versioned URI are a waste of everyone's time (because as far as the clients are concerned, the URI are opaque. Remember, URI shorteners work.)

    Where versioning tends to matter is in the semantics of the link relations and media-types. Trying to introduce backwards incompatible changes there makes a huge mess, so a lot of work is done to maintain compatibility (which HTML5 is still text/html), and breaking compatibility is preferably implemented by introducing a new name (text/not-html-anymore).