Daniel Doubrovkine bio photo

Daniel Doubrovkine

aka dB., @awscloud, former CTO @artsy, +@vestris, NYC

Email Twitter LinkedIn Github Strava
Creative Commons License

I’ve begun experimenting with Hypermedia APIs a bit more seriously, trying to come up with a good infrastructure for the next version of the Artsy API. It might even be a public one, but I am not making any promises right now. I’ve played with serialization and attempted to use ActiveModel::Serializers with the grape-activemodel_serializers gem and HAL with Roar. It turned out that we do need a little bit of help with Roar, so I released a new gem called grape-roar, which enables using Grape’s present keyword.

Check out an example application deployed at grape-with-roar.herokuapp.com, source code in https://github.com/dblock/grape-with-roar.

First, swap the JSON formatter for Grape::Formatter::Roar. It’s implementation is almost identical to the default JSON formatter, except that it passes env along to the to_json call.

module Acme
  module Api
    class RootEndpoint < Grape::API
      prefix 'api'
      format :json
      formatter :json, Grape::Formatter::Roar
    end
  end
end

Implement a presenter. It will typically have a number of :properties. Include Grape::Roar::Representer to use _present _in your API.

module Acme
  module Api
    module Presenters
      module SplinePresenter
        include Roar::Representer::JSON::HAL
        include Roar::Representer::Feature::Hypermedia
        include Grape::Roar::Representer

        property :uuid
        property :reticulated

        link :self do |opts|
          request = Grape::Request.new(opts[:env])
          "#{request.base_url}/api/splines/#{uuid}"
        end
      end
    end
  end
end

You can now present an entity in your API implementation.

module Acme
  module Api
    class SplinesEndpoint < Grape::API
      namespace :splines do
        desc 'Get a spline.'
        params do
          requires :id, type: String, desc: 'Spline id.'
        end

        get ':id' do
          spline = Acme::Models::Spline.find(params[:id])
          present spline, with: Acme::Api::Presenters::SplinePresenter
        end
      end
    end
  end
end

Representing collections is similar, check out https://github.com/dblock/grape-with-roar for a complete example with bonus pagination support.

I’d love it if someone could contribute a POST/PUT example.