You can look into the her-example repository for a sample application using Her.

Middleware

Since Her relies on Faraday to send HTTP requests, you can choose the middleware used to handle requests and responses. Using the block in the setup call, you have access to Faraday’s connection object and are able to customize the middleware stack used on each request and response.

Authentication

Her doesn’t support authentication by default. However, it’s easy to implement one with request middleware. Using the setup block, we can add it to the middleware stack.

For example, to add a token header to your API requests in a Rails application, you could use the excellent request_store gem like this:

However, if you want Her to be able to parse the data from a single root element (usually based on the model name), you’ll have to use the parse_root_in_json method (See the JSON attributes-wrapping section).

Also, you can define your own parsing method using a response middleware. The middleware should set env[:body] to a hash with three symbol keys: :data, :errors and :metadata. The following code uses a custom middleware to parse the JSON data:

Validations

Her includes ActiveModel::Validations so you can declare validations the same way you do in Rails.

However, validations must be triggered manually — they are not run, for example, when calling #save on an object, or #create on a model class.

classUserincludeHer::Modelattributes:fullname,:emailvalidates:fullname,presence:truevalidates:email,presence:trueend@user=User.new(fullname:"Tobias Fünke")@user.valid?# => false
@user.save# POST "/users" with `fullname=Tobias+Fünke` will still be called, even if the user is not valid

Dirty attributes

Her includes ActiveModel::Dirty so you can keep track of the attributes that have changed in an object.

Inheritance

If all your models share the same settings, you might want to make them children of a class and only include Her::Model in that class. However, there are a few settings that don’t get passed to the children classes:

root_element

collection_path and resource_path

Those settings are based on the class name, so you don’t have to redefine them each time you create a new children class (but you still can). Every other setting is inherited from the parent (associations, scopes, JSON settings, etc.).

moduleMyAPIclassModelincludeHer::Modelparse_root_in_jsontrueinclude_root_in_jsontrueendendclassUser<MyAPI::ModelendUser.find(1)# GET "/users/1"

Scopes

Just like with ActiveRecord, you can define named scopes for your models. Scopes are chainable and can be used within other scopes.

classUserincludeHer::Modelscope:by_role,->(role){where(role:role)}scope:admins,->{by_role('admin')}scope:active,->{where(active:1)}end@admins=User.admins# GET "/users?role=admin"
@moderators=User.by_role('moderator')# GET "/users?role=moderator"
@active_admins=User.active.admins# @admins.active would have worked here too
# GET "/users?role=admin&active=1"

Testing

In order to test them, we’ll have to stub the remote API requests. With RSpec, we can do this like so:

# spec/spec_helper.rb
RSpec.configuredo|config|config.include(Module.newdodefstub_api_for(klass)klass.use_api(api=Her::API.new)# Here, you would customize this for your own API (URL, middleware, etc)
# like you have done in your application’s initializer
api.setupurl:"http://api.example.com"do|c|c.useHer::Middleware::FirstLevelParseJSONc.adapter(:test){|s|yield(s)}endendend)end

Then, in your tests, we can specify what (fake) HTTP requests will return:

Her IRL

History

I told myself a few months ago that it would be great to build a gem to replace Rails’ ActiveResource since it was barely maintained (and now removed from Rails 4.0), lacking features and hard to extend/customize. I had built a few of these REST-powered ORMs for client projects before but I decided I wanted to write one for myself that I could release as an open-source project.

Most of Her’s core concepts were written on a Saturday morning of April 2012 (first commit at 7am!).

Maintainers

Contribute

Yes please! Feel free to contribute and submit issues/pull requests on GitHub. There’s no such thing as a bad pull request — even if it’s for a typo, a small improvement to the code or the documentation!