This post will outline the process of building a backend Ruby API wrapper using Typhoeus and Virtus.
Virtus is a gem that was extracted from the DataMapper gem. It provides the ability to define attributes and their type on a class. Instantiating a new object will cause it’s attributes to be automatically coerced into your definition. You can define your attributes as simple types such as Strings and Integers, or even more complex object types such as Arrays which contain a specific type of object.
The User object above contains an array of Address objects. Passing in a hash of data to the constructor will build out the object automatically.
Building the API
Now that you have your client objects build out, how do you build out the data from your API? I prefer to use ActiveModel::Serializers to build out the structure. The DSL provided by the gem is very similar to ActiveRecord. You just define what attributes you want to be returned when a model is serialized. When you include an association it’s own serializer is automatically brought in to build out the JSON.
The serializers defined above are used to build out the same structure our Virtus objects need. If the API sends additional attributes they are simply ignored by Virtus. The respond_with method will lookup the serializer to use based off the type of object being returned, overriding it isn’t difficult to do. If you aren’t a fan of ActiveModel Serializers you can take a look at Jbuilder. It provides an alternative syntax for building out JSON responses.</div>
Getting data from the API
Now that the API is setup and is returning data how do we get it? There are a number of HTTP client gems out there such as Typhoeus, Faraday and httparty. The Ruby Standard Library also includes Net::HTTP, however it isn’t very straightforward to use. I prefer Typhoeus, it is easy to use, has a great interface and is quite flexible. All HTTP verbs work in the same manner with some minor tweaks. Getting data from the API endpoint defined above (users#show) can be done with 1 line.
We can now feed the data from the response into a new Virtus object and read attributes from it like a standard ActiveRecord model.
Basic CRUD Wrapper
Reading your data is great, however to be really useful to be able to make updates in addition to creating new records and removing old records. Typhoeus works with POST requests almost exactly the same as GET requests. Consistency is one the things I like about it.
After parsing the response and passing it into a new object we can see that the database successfully created a new record.
To make things a bit more “Rails” like we can create add a few class methods to the User class.
The methods aren’t a 100% match to Rails update_attributes and destroy however it is still an external call, so we want to minimize the number of requests. Instead of finding the user, then updating it we are doing it in one call.</div>
Now that we have a User class that handles all the basic CRUD operations we can toss in a bit of ActiveModel to make it work with standard Rails forms. The respond_with method that returns JSON from the API will also return any validation errors. By mixing in ActiveModel::Validations we get access to the errors object. If the response status is 422 we can take it and build out the errors on our local object.
Since we are using the same interface ActiveRecord uses, our forms will behave just like everything was connected directly to our database.</div>
Abstracting for Reuse
So now we have a user class that works like ActiveRecord, but goes through a REST API instead. If your application has a bunch of classes that connect to the same API things are going to get very repetitive. You can create a mixin to include on all your objects. The one below has everything used in this post, plus basic search and listing (where / all).
The User class now has the all functionality it had before, yet the mixin can be added to make any other class just as functional.
Using Hashie as an alternative
If you don’t need full CRUD or a lot of complexity you can also just use Hashie. It will take a hash and construct a simple object with accessors.