RABL: Ruby API Templates for JSON, XML and MessagePack
General ruby templating with json, bson, xml, plist and msgpack support
At a glance
- What is it?
- RABL moves API response building out of ActiveRecord's to_json and into the view layer, using a small Ruby DSL. It fits Rails and Padrino projects that need node names, conditional children and multi-format output, and it costs a template engine to learn.
- Who is it for?
- RABL can be useful when a Ruby application needs view templates for structured API responses. Check compatibility with your current Ruby, framework and gem versions, test the rendered response shape, and review upgrade notes for changes to inferred node names.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- nesquena/rabl3,624 ★ · -3
| Repository | 2026-09-24 | 2026-11-14 |
|---|---|---|
| nesquena/rabl | 3.6k | 3.6k |
-3 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The to_json ceiling RABL was written to break
ActiveRecord's to_json gives you the columns, plus whatever you can bend into as_json. RABL starts from the complaint that this is restrictive when the JSON does not match the database schema. The README lists the specific things it wants to be easy: nodes named by combining data in an object, arguments passed to methods with the result stored as a child node, partial templates with inheritance to cut duplication, attribute aliases, attributes appended from a child into a parent, and nodes included only when a condition holds. Those six items are the product definition. If your payload needs none of them, RABL is overhead.
The intended audience is a Rails or Padrino application that serves an API and wants the representation to live in the view layer. The README states this as an MVC argument: API data representations belong to the view. That is a design position, not a neutral one. It means your response shape is described in a .rabl file next to your other templates, and it means anyone reading the controller sees a render call rather than a serialized hash. Teams that prefer serializers living beside models will find this backwards.
RABL is ORM-agnostic. The data typically comes from models, but the template only needs a Ruby object. The project documents output engines for JSON, XML, MessagePack, PList and BSON; required dependencies and compatibility vary by format.
How a .rabl template turns objects into output
A template is a Ruby DSL evaluated against the objects you assign in the controller. The README's Padrino example assigns @posts and @user, then renders posts/index. The template declares a collection, lists attributes, nests a child block and adds a computed node:
# app/views/posts/index.rabl
collection @posts
attributes :id, :title, :subject
child(:user) { attributes :full_name }
node(:read) { |post| post.read_by?(@user) }The block form of node receives each object, so read is computed per post rather than stored. child(:user) opens a nested object and renders only full_name from it. The README shows the resulting JSON with a post root wrapping the fields, a user object nested inside, and read as a boolean.
The engine selection is configuration. Rabl.configure exposes json_engine, msgpack_engine, bson_engine and plist_engine, each a class with a dump class method. The README notes that if you use oj, Rabl sets the mode to :compat. Root inclusion is separate per format: include_json_root, include_msgpack_root, include_bson_root and include_plist_root all default to true in the commented defaults, while include_xml_root defaults to false. include_child_root controls whether nested objects carry their own root. That split is the part people get wrong first, because a JSON client and an XML client can receive differently shaped documents from the same template.
Installing RABL and rendering a first collection
The gem installs from RubyGems. The README gives both forms:
gem install rablIn a Bundler project, add the gem and a JSON parser. The README recommends either oj or yajl-ruby:
# Gemfile
gem 'rabl'
# Also add either `oj` or `yajl-ruby` as the JSON parser
# If using `oj`, Rabl will set the mode to :compat
gem 'oj'Run bundle install afterward. The README describes configuration-free setup for Rails 2.3.8 and later, Rails 3.x and Padrino, but those historical statements do not prove compatibility with every current framework release. Check the versions in your application. Padrino has one ordering rule: the rabl gem must be listed after the padrino gem in the Gemfile, otherwise Rabl does not register as a template engine. That is a silent failure if you miss it, so check the order before debugging anything else.
For Sinatra or another tilt-based framework, registration is explicit:
Rabl.register!After registration, write a template and render it from the route. The README's Padrino route declares both formats and renders the template:
get "/posts", :provides => [:json, :xml] do
@user = current_user
@posts = Post.order("id DESC")
render "posts/index"
endVisiting the .json path returns the array shown in the README, with each element wrapped in a post root. The examples directory in the repository contains base.json.rabl, demo.json.rabl and inherited.json.rabl, which are the smallest working templates to compare against once your own output looks wrong.
Where RABL gets in the way
The breaking changes list is the honest limitation section. v0.9.0 changed the default node name for certain associations, especially around STI models, and the README tells you to verify for breakages and to be explicit with an alias such as @users => :users. A template engine that infers names will infer them differently across versions. If you rely on inference, an upgrade is a payload change.
Testing is the second trap. The README notes that RSpec controller specs need `render_views` to exercise templates when view rendering is stubbed. Other spec types can test rendered output through their own mechanisms. A test suite that appears to cover your API can therefore assert nothing about the template output. That is a real failure mode, and it is not obvious from the passing suite.
Configuration defaults cut both ways. raise_on_missing_attribute defaults to false, so a missing attribute is omitted rather than raising; verify the response shape in tests. replace_nil_values_with_empty_strings, exclude_nil_values and exclude_empty_values_in_collections are all off by default, which means null handling is your decision rather than the gem's. The README does not document rollback or migration steps for the v0.9.0 node name change beyond verifying and being explicit.
Performance is not something this material quantifies. Caching exists as configuration (cache_all_output, cache_sources, cache_engine, perform_caching), but the README does not state what any of them cost or save. Treat caching as a switch to test in your own environment, not as a documented win.
RABL against ActiveModel::Serializers and jbuilder
The closest comparison in the Rails world is ActiveModel::Serializers, which puts the representation in a serializer class tied to a model and renders through the controller's render :json path. RABL puts it in a template file and renders through the view layer, which is the MVC argument the README makes. If your team already thinks in serializers, RABL adds a second mental model for the same job.
jbuilder is also a view-layer builder, so it shares RABL's placement but not its shape. jbuilder templates are Ruby blocks that build a JSON structure directly; RABL templates declare attributes, collections and children against objects, with format engines selected by configuration. That difference matters for multi-format output: RABL's engine settings let the same template target JSON, XML, MessagePack, PList and BSON, while a builder that emits one structure is tied to that structure. If you only ever serve JSON, the multi-format machinery is weight you carry for nothing.
The third option is doing nothing and shaping to_json with as_json. That is the baseline RABL was written against, and for a payload with no computed nodes, no conditional children and no aliases, it remains the smaller solution.
Maintenance, licence and the cost of upgrading
Check RubyGems and the project changelog for the current release and compatibility before upgrading. The README documents historical changes to inferred node names, JSON dependencies and controller-spec view rendering; test representative responses and explicit aliases when changing versions.
The repository identifies its license as MIT. Review the license file and the terms of any dependencies you distribute.
Editorial conclusion
RABL can be useful when a Ruby application needs view templates for structured API responses. Check compatibility with your current Ruby, framework and gem versions, test the rendered response shape, and review upgrade notes for changes to inferred node names. In RSpec controller specs, enable view rendering when testing the template itself.
Frequently asked questions
How do I install RABL in a Rails or Padrino app?
The README documents `gem install rabl` or adding `rabl` to a Gemfile; it also suggests Oj or yajl-ruby. Its framework examples include older Rails versions and Padrino, so check the gem and framework versions you use. For Padrino, the README says to list rabl after padrino in the Gemfile.
Why does my RSpec suite pass while the RABL template output is wrong?
In an RSpec controller spec that stubs view rendering, a passing controller test does not exercise the template. The project recommends `render_views` for that case; request or view specs can also verify rendered output depending on your test setup.
Which output formats does RABL support?
The README lists JSON, XML, MessagePack, PList and BSON. Each format has its own engine setting (json_engine, msgpack_engine, bson_engine, plist_engine) and its own root inclusion flag, and include_xml_root defaults to false while the JSON, MessagePack, BSON and PList root flags default to true.
Does RABL work with Sinatra?
Yes, through tilt. The README says to call Rabl.register! to initialize it, and points to the Sinatra Usage guide in the project wiki for setup details.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nesquena-rabl)Star history chart for your README
[](https://hysenlabs.com/projects/nesquena-rabl)Was this useful?