Boxer is a template engine for creating nested and multi-view JSON objects from Ruby hashes.
Say you have a couple ActiveRecord models in your Rails app and you want to render an API response in JSON, but the view of each of those model objects may change based on the API action that's being requested.
- User
- Place
For instance, the API for GET /users/:id
should render a full representation
of the User object in question, including all relevant attributes.
But in your GET /places/:id/users
API call, you only need short-form
representations of the users at that place, without every single attribute
being included in the response.
Boxer allows you to define a box for each type of object you'd like to display (or for each amalgamation of objects you want to display—it's up to you).
Boxer.box(:user) do |box, user|
{
:name => user.name,
:age => user.age,
}
end
To display different views on the same object, you can use Boxer's views:
Boxer.box(:user) do |box, user|
box.view(:base) do
{
:name => user.name,
:age => user.age,
}
end
box.view(:full, :extends => :base) do
{
:email => user.email,
:is_private => user.private?,
}
end
end
As you might guess, the :full
view includes all attributes in the :base
view by virtue of the :extends
option.
Now, in order to render a User with the :base
view, simple call Boxer.ship
:
Boxer.ship(:user, User.first)
Boxer assumes that you want the :base
view if no view is specified to
ship
—it's the only specially-named view.
To render the full view for the same user:
Boxer.ship(:user, User.first, :view => :full)
Which will give you back a Ruby hash on which you can call #to_json
, to render
your JSON response1:
>> Boxer.ship(:user, User.first, :view => :full).to_json
=> "{"name": "Bo Jim", "age": 17, "email": "[email protected]", "is_private": false}"
Composing different boxes together is as simple as calling Boxer.ship
from
within a box—it's just Ruby:
Boxer.box(:place) do |box, place|
{
:name => place.name,
:address => place.address,
:top_user => Boxer.ship(:user, place.users.order(:visits).first),
}
end
Hash#to_json
requires a json library
See the wiki for more features of Boxer, including:
Install the boxer gem.
Boxer was inspired by RABL, by Nathan Esquenazi.