If you follow our series on building APIs with Grape and Rails, you already know how to create powerful versioned APIs in a simple and straightforward way as well as improve Grape’s abilities with a number of useful tricks.

Building an interface, however, is often just the first step. The real challenge begins when your application needs to rely on data from several different APIs. It’s particularly difficult when you build applications using the Service Oriented Architecture pattern, which demands a scalable way for the software to communicate between various components.

If you want to know how to solve this problem, then this post is for you.

Dictionary

We’ll mainly use two gems: her and faraday .

Faraday is an HTTP client lib that provides a common interface over many adapters.

her, on the other hand, is an ORM that maps REST resources to Ruby objects, designed to build applications powered by a RESTful API instead of a database. Simply put, her makes REST resources behave like Active Record models:

class User include Her :: Model end User . all # GET "https://api.example.com/users" and return an array of User objects @user = User . create ( fullname: "Tobias Fünke" ) # POST "https://api.example.com/users" with `fullname=Tobias+Fünke` and return the saved User object

Pretty cool, right? Now let’s get straight to the point.

Goal

Our objective is to make a Her-based wrapper with a configurable Faraday connection for a multi-host, token-authorized RESTful JSON API that supports HTTP headers cache. Easy-peasy, right? Right...? Well, it's not quite that simple.

Here at Monterail, however, we’ve written a number of Her-based wrappers and have found a nice, elastic pattern that we're eager to share with you.

Solution

First, let’s have a look at the model classes inside an imaginary monterail-api gem. The purpose of these classes is to map resources from other APIs to our own application.

Please note the uses_api method; it’s pretty important.

# lib/monterail-api/models.rb module MonterailApi module V1 class Hussar include Her :: Model uses_api MonterailApi :: V1 . api # Here attributes :name , :skills end class Wing include Her :: Model uses_api MonterailApi :: V1 . api # And here attributes :side end end end

uses_api enables our models to talk to different APIs. It changes which API they will use to make their HTTP requests.

The only remaining task is to configure our wrapper in the client application:

# lib/monterail-api.rb module MonterailApi module V1 class ClientNotConfigured < Exception ; end def self . configure ( host , api_key , & block ) @api = Her :: API . new @api . setup :url => "http:// #{ host } /api/v1" do | c | # we love JSON, we really do c . use FaradayMiddleware :: EncodeJson c . use Her :: Middleware :: AcceptJSON c . use Her :: Middleware :: FirstLevelParseJSON # simple header based authorizaiton c . authorization :token , api_key # allow for customizing faraday connection yield c if block_given? # inject default adapter unless in test mode c . adapter Faraday . default_adapter unless c . builder . handlers . include? ( Faraday :: Adapter :: Test ) end # This is very important. Due to way Her currently works # model files need to be required after configuring the API require "hussars/models" end def self . api # raise exception if somehow model classes gets required # before the API is configured raise ClientNotConfigured . new ( "Monterail" ) unless @api @api end end end

Faraday and middleware

The great thing about this type of module is that it can be easily integrated with any app. This adaptability doesn’t mean that we can’t improve upon it, though. What about caching? We surely don’t want to slow down the backend by making too many useless HTTP requests, right?

Let’s take advantage of the faraday-http-cache and faraday_middleware gems for some ActiveSupport::Instrumentation integration.

# config/initializers/monterail_api.rb MonterailApi :: V1 . configure ( "some.host.com" , "secret" ) do | c | # let the magic happen - this will make use of ETag to skip unneed API calls c . use :http_cache , Rails . cache , :logger => Rails . logger # Active Support instrumentation c . use :instrumentation , :name => "external.monterail.v1" end

Now we can simply use the code below to get the correct object without worrying about hitting the API too often:

MonterailApi :: V1 :: Hussar . find ( 123 ) # It’s all cached!

That’s it!

This article on building her models and caching them is our third in a series on building APIs. We’ve previously published an introduction to using grape , a great gem that allows you to build APIs with tremendous ease. We expanded on that topic in the subsequent post by outlining some useful tips and tricks for improving grape . So what’s next? Well, we promised to talk more about data representers, so you’ll just have to wait and see!

We’re always keen to know what you think about the solutions that we provide here on Codetunes. Did you find this introduction to Grape useful? Has it changed the way that you think about APIs in Rails applications? (If so, we’re extremely happy, because that’s why we’re publishing this series.) Or maybe you’re convinced that you can figure out a better solution than ours? If so, prove it!

We’d love to hear your feedback.