This library provides a framework-agnostic interface for generating HAL+JSON representations of resources in Ruby.
Add this line to your application's Gemfile:
gem 'halogen'And then execute:
$ bundle
Or install it yourself as:
$ gem install halogen
Create a simple representer class and include Halogen:
class GoatRepresenter
include Halogen
property :name do
'Gideon'
end
link :self do
'/goats/gideon'
end
endInstantiate:
repr = GoatRepresenter.newThen call repr.render:
{
name: 'Gideon',
_links: {
self: { href: '/goats/gideon' }
}
}Or repr.to_json:
'{"name": "Gideon", "_links": {"self": {"href": "/goats/gideon"}}}'Not associated with any particular resource or collection. For example, an API entry point:
class ApiRootRepresenter
include Halogen
link(:self) { '/api' }
endRepresents a single item:
class GoatRepresenter
include Halogen
resource :goat
endWhen a resource is declared, #initialize expects the resource as the first argument:
repr = GoatRepresenter.new(Goat.new, ...)This makes property definitions cleaner:
property :name # now calls Goat#name by defaultRepresents a collection of items. When a collection is declared, the embedded resource with the same name will always be embedded, whether it is requested via standard embed options or not.
class GoatKidsRepresenter
include Halogen
collection :kids
embed(:kids) { ... } # always embedded
endProperties can be defined in several ways:
property(:age) { "#{goat.age} years old" }property :age # => Goat#age, if resource is declaredproperty :age do
goat.age.round
endproperty(:age) { calculate_age }
def calculate_age
...
endThe inclusion of properties can be determined by conditionals using if and
unless options. For example, with a method name:
property :age, if: :include_age?
def include_age?
goat.age < 10
endWith a proc:
property :age, unless: proc { goat.age.nil? }, value: ...For links and embeds:
link :kids, :templated, unless: :exclude_kids_link?, value: ...embed :kids, if: proc { goat.kids.size > 0 } do
...
endSimple link:
link(:root) { '/' }
# => { _links: { root: { href: '/' } } ... }Templated link:
link(:find, :templated) { '/goats/{?id}' }
# => { _links: { find: { href: '/goats/{?id}', templated: true } } ... }Optional links:
representer = MyRepresenterWithManyLinks.new(include_links: false)
representation = representer.render
representation[:_links] #nilEmbedded resources are not rendered by default. They will be included if both of the following conditions are met:
- The proc returns either a Halogen instance or an array of Halogen instances
- The embed is requested via the parent representer's options, e.g.:
GoatRepresenter.new(embed: { kids: true, parents: false })Embedded resources can be nested to any depth, e.g.:
GoatRepresenter.new(embed: {
kids: {
foods: {
ingredients: true
},
pasture: true
}
})If Halogen is loaded in a Rails application, Rails url helpers will be available in representers:
link(:new) { new_goat_url }It is majestic.
- Fork it ( https://github.com/mode/halogen/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request