Over a million developers have joined DZone.

Evolving APIs using Grape API Versioning

DZone's Guide to

Evolving APIs using Grape API Versioning

Free Resource

Today’s data climate is fast-paced and it’s not slowing down. Here’s why your current integration solution is not enough. Brought to you in partnership with Liaison Technologies.

I’ve seen two common API versioning strategies in the wild. The first is to use a single API version and gradually deprecate methods. This usually means introducing new API routes, while retiring old ones, and representing the same objects in multiple, versioned, formats. Fast forward a few years and you are likely to inherit a significant amount of technical debt. The second strategy involves making a clean cut, leaving the version one of the API alone and building a fresh, new, API version two.

Starting with the next release of Grape (likely 0.6.0) you will have a third alternative: building a new API version incrementally on top of a previous one. There’re no hacks involved. Consider the following trivial API.

    module Acme
      class V1 < Grape::API
        format :json
        version 'v1', using: :header, vendor: 'acme', format: :json
        desc "Returns the current API version, v1."
        get do
          { version: 'v1' }
        desc "Returns pong."
        get "ping" do
          { ping: "pong" }

Define the next API version.

    module Acme
      class V2 < Grape::API
        format :json
        version 'v2', using: :header, vendor: 'acme', format: :json
        desc "Returns the current API version, v2."
        get do
          { version: 'v2' }

At this point we want v1 to be identical to v2, except for the root method. We’ll start by allowing v1 to respond to both v1 and v2 requests.

    version [ 'v2', 'v1' ], using: :header, vendor: 'acme', format: :json

Mount v2 before v1 and allow v2 to cascade the request to the next Rack middleware by adding cascade: true to its version declaration. Rack::Cascade works by passing on any requests until a middleware replies with something else than a 404.

new Rack::Cascade([ Acme::V2, Acme::V1 ])
version 'v2', using: :header, vendor: 'acme', format: :json, cascade: true

Try it on my demo project in https://github.com/dblock/grape-on-rack-v1-inside-v2.

By default we get the root of v2 and the ping method implemented on v1.

    curl http://localhost:9292/
    curl http://localhost:9292/ping
With version two, we get the same thing.
    curl http://localhost:9292 -H "Accept:application/vnd.acme-v2+json"
    curl http://localhost:9292/ping -H "Accept:application/vnd.acme-v2+json"
With version 1 we get the old behavior.
    curl http://localhost:9292 -H "Accept:application/vnd.acme-v1+json"
    curl http://localhost:9292/ping -H "Accept:application/vnd.acme-v1+json"
The only fix needed in Grape for this was to enable multiple versions specified with version, committed in 2be499c51.

This came up on the Grape mailing list.

Is iPaaS solving the right problems? Not knowing the fundamental difference between iPaaS and iPaaS+ could cost you down the road. Brought to you in partnership with Liaison Technologies.


Published at DZone with permission of Daniel Doubrovkine. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}