This library provides a framework-agnostic interface for generating HAL+JSON representations of resources in Ruby.
Installation
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
Usage
Basic usage
Create a simple representer class and include Halogen:
class GoatRepresenter include Halogen property :name do 'Gideon' end link :self do '/goats/gideon' end end
Instantiate:
repr = GoatRepresenter.new
Then call repr.render:
{ name: 'Gideon', _links: { self: { href: '/goats/gideon' } } }
Or repr.to_json:
'{"name": "Gideon", "_links": {"self": {"href": "/goats/gideon"}}}'Representer types
1. Simple
Not associated with any particular resource or collection. For example, an API entry point:
class ApiRootRepresenter include Halogen link(:self) { '/api' } end
2. Resource
Represents a single item:
class GoatRepresenter include Halogen resource :goat end
When 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 default
3. Collection
Represents 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 end
Defining properties, links and embeds
Properties can be defined in several ways:
property(:age) { "#{goat.age} years old" }
property :age # => Goat#age, if resource is declared
property :age do goat.age.round end
property(:age) { calculate_age } def calculate_age ... end
Conditionals
The 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 end
With 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 ... end
Links
Simple 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] #nil
Embedded resources
Embedded 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 } })
Using with Rails
If Halogen is loaded in a Rails application, Rails url helpers will be available in representers:
link(:new) { new_goat_url }
More examples
What's with the goat?
It is majestic.
Contributing
- 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