Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
R

roar

> 编程语言
Open source

Parse and render REST API documents using representers.

1.8K stars0 likes1 views
WebsiteGitHub

About

Parse and render REST API documents using representers.

Roar

Resource-Oriented Architectures in Ruby.

Table of Contents

  • Introduction
  • Representable
  • Installation
    • Dependencies
  • Defining Representers
  • Rendering
  • Parsing
  • Module Representers
  • Collections
  • Nesting
  • Inline Representer
  • Syncing Objects
  • Coercion
  • More Features
  • Hypermedia
  • Passing Options
  • Specify Decorator
  • Consuming Hypermedia
  • Media Formats
  • HAL-JSON
    • Hypermedia
    • Nesting
  • JSON API
  • Client-Side Support
  • HTTP Support
    • HTTPS
    • Basic Authentication
    • Client SSL certificates
    • Request customization
    • Error handling
  • XML
  • Support
  • License

Introduction

Roar is a framework for parsing and rendering REST documents. Nothing more.

Representers let you define your API document structure and semantics. They allow both rendering representations from your models and parsing documents to update your Ruby objects. The bi-directional nature of representers make them interesting for both server and client usage.

Roar comes with built-in JSON, JSON-HAL and XML support. JSON API support is available via the JSON API gem. Its highly modular architecture provides features like coercion, hypermedia, HTTP transport, client caching and more.

Roar is completely framework-agnostic and loves being used in web kits like Rails, Hanami, Sinatra, Roda, etc. If you use Rails, consider roar-rails for an enjoyable integration.

Representable

Roar is just a thin layer on top of the representable gem. While Roar gives you a DSL and behaviour for creating hypermedia APIs, representable implements all the mapping functionality.

If in need for a feature, make sure to check the representable API docs first.

Installation

The roar gem runs with all Ruby versions >= 1.9.3.

ruby
gem 'roar'

To use roar with Ruby versions < 2.2.0, add a version pin to your Gemfile:

ruby
gem 'sinatra', '~> 1.4'

Dependencies

Roar does not bundle dependencies for JSON and XML.

If you want to use JSON, add the following to your Gemfile:

ruby
gem 'multi_json'

If you want to use XML, add the following to your Gemfile:

ruby
gem 'nokogiri'

Defining Representers

Let's see how representers work. They're fun to use.

ruby
require 'roar/decorator'
require 'roar/json'

class SongRepresenter < Roar::Decorator
  include Roar::JSON

  property :title
end

API documents are defined using a decorator class. You can define plain attributes using the ::property method.

Now let's assume we'd have Song which is an ActiveRecord class. Please note that Roar is not limited to ActiveRecord. In fact, it doesn't really care whether it's representing ActiveRecord, Sequel::Model or just an OpenStruct instance.

ruby
class Song < ActiveRecord::Base
end

Rendering

To render a document, you apply the representer to your model.

ruby
song = Song.new(title: "Medicine Balls")

SongRepresenter.new(song).to_json #=> {"title":"Medicine Balls"}

Here, the song objects gets wrapped (or "decorated") by the decorator. It is treated as immutable - Roar won't mix in any behaviour.

Parsing

The cool thing about representers is: they can be used for rendering and parsing. See how easy updating your model from a document is.

ruby
song = Song.new(title: "Medicine Balls")

SongRepresenter.new(song).from_json('{"title":"Linoleum"}')
song.title #=> Linoleum

Unknown attributes in the parsed document are simply ignored, making half-baked solutions like strong_parameters redundant.

Module Representers

Module Representers are deprecated in Roar 1.1 and will be removed in Roar 2.0.

In place of inheriting from Roar::Decorator, you can also extend a singleton object with a representer module. Decorators and module representers actually have identical features. You can parse, render, nest, go nuts with both of them.

ruby
song = Song.new(title: "Fate")
song.extend(SongRepresenter)

song.to_json #=> {"title":"Fate"}

Here, the representer is injected into the actual model and gives us a new #to_json method.

This also works both ways.

ruby
song = Song.new
song.extend(SongRepresenter)

song.from_json('{"title":"Fate"}')
song #=> {"title":"Fate"}

It's worth noting though that many people dislike #extend due to well-known performance issues and object pollution. As such this approach is no longer recommended. In this README we'll use decorators to illustrate this library.

Collections

Roar (or rather representable) also allows mapping collections in documents.

ruby
class SongRepresenter < Roar::Decorator
  include Roar::JSON

  property :title
  collection :composers
end

Where ::property knows how to handle plain attributes, ::collection does lists.

ruby
song = Song.new(title: "Roxanne", composers: ["Sting", "Stu Copeland"])

SongRepresenter.new(song).to_json #=> {"title":"Roxanne","composers":["Sting","Stu Copeland"]}

And, yes, this also works for parsing: from_json will create and populate the array of the composers attribute.

Nesting

Now what if we need to tackle with collections of Songs? We need to implement an Album class.

ruby
class Album < ActiveRecord::Base
  has_many :songs
end

Another representer to represent.

ruby
class AlbumRepresenter < Roar::Decorator
  include Roar::JSON

  property :title
  collection :songs, extend: SongRepresenter, class: Song
end

Both ::property and ::collection accept options for nesting representers into representers.

The extend: option tells Roar which representer to use for the nested objects (here, the array items of the album.songs field). When parsing a document class: defines the nested object type.

Consider the following object setup.

ruby
album = Album.new(title: "True North")
album.songs << Song.new(title: "The Island")
album.songs << Song.new(title: "Changing Tide")

You apply the AlbumRepresenter and you get a nested document.

ruby
AlbumRepresenter.new(album).to_json #=> {"title":"True North","songs":[{"title":"The Island"},{"title":"Changing Tide"}]}

This works vice-versa.

ruby
album = Album.new

AlbumRepresenter.new(album).from_json('{"title":"Indestructible","songs":[{"title":"Tropical London"},{"title":"Roadblock"}]}')

puts album.songs[1] #=> #<Song title="Roadblock">

The nesting of two representers can map composed object as you find them in many many APIs.

In case you're after virtual nesting, where a nested block in your document still maps to the same outer object, check out the ::nested method.

Inline Representer

Sometimes you don't wanna create two separate representers - although it makes them reusable across your app. Use inline representers if you're not intending this.

ruby
class AlbumRepresenter < Roar::Decorator
  include Roar::JSON

  property :title

  collection :songs, class: Song do
    property :title
  end
end

This will give you the same rendering and parsing behaviour as in the previous example with just one module.

Syncing Objects

Usually, when parsing, nested objects are created from scratch. If you want nested objects to be updated instead of being newly created, use parse_strategy:.

ruby
class AlbumRepresenter < Roar::Decorator
  include Roar::JSON

  property :title

  collection :songs, extend: SongRepresenter, parse_strategy: :sync
end

This will advise Roar to update existing songs.

ruby
album.songs[0].object_id #=> 81431220

AlbumRepresenter.new(album).from_json('{"title":"True North","songs":[{"title":"Secret Society"},{"title":"Changing Tide"}]}')

album.songs[0].title #=> Secret Society
album.songs[0].object_id #=> 81431220

Roar didn't create a new Song instance but updated its attributes, only.

We're currently working on better strategies to easily implement POST and PUT semantics in your APIs without having to worry about the nitty-gritties.

Coercion

Roar provides coercion with the dry-types gem.

ruby
require 'roar/coercion'
require 'roar/json'

class SongRepresenter < Roar::Decorator
  include Roar::JSON
  include Roar::Coercion

  property :title
  property :released_at, type: Types::DateTime
end

The :type option allows to set a dry-types-compatible type.

ruby
song = Song.new

SongRepresenter.new(song).from_json('{"released_at":"1981/03/31"}')

song.released_at #=> 1981-03-31T00:00:00+00:00

More Features

Roar/representable gives you many more mapping features like renaming attributes, wrapping, passing options, etc. See the representable documentation for a detailed explanation.

Hypermedia

Roar comes with built-in support for embedding and processing hypermedia in your documents.

ruby
class SongRepresenter < Roar::Decorator
  include Roar::JSON
  include Roar::Hypermedia

  property :title

  link :self do
    "http://songs/#{title}"
  end
end

The Hypermedia feature allows declaring links using the ::link method. In the block, you have access to the represented model. When using representer modules, the block is executed in the model's context.

However, when using decorators, the context is the decorator instance, allowing you to access additional data. Use represented to retrieve model data.

ruby
class SongRepresenter < Roar::Decorator
  # ..
  link :self do
    "http://songs/#{represented.title}"
  end
end

This will render links into your representation.

ruby
SongRepresenter.new(song).to_json #=> {"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}

Per default, links are pushed into the hash using the links key. Link blocks are executed in represented context, allowing you to call any instance method of your model (here, we call #title).

Also, note that roar-rails allows using URL helpers in link blocks.

Passing Options

Sometimes you need more data in the link block. Data that's not available from the represented model.

ruby
class SongRepresenter < Roar::Decorator
  include Roar::JSON

  property :title

  link :self do |opts|
    "http://#{opts[:base_url]}songs/#{title}"
  end
end

Pass this data to the rendering method.

ruby
representer = SongRepresenter.new(song)
representer.to_json(base_url: "localhost:3001/")

Any options passed to #to_json will be available as block arguments in the link blocks.

Specify Decorator

If you have a property that is a separate class or model, you can specify a decorator for that property. Suppose there is a separate Artist model for an album. When the album is eagerly loaded, the artist model could be represented along with it.

ruby
class ArtistRepresenter < Roar::Decorator
  property :name
end

class AlbumRepresenter < Roar::Decorator
  # ..
  property :artist, decorator: ArtistRepresenter
end

Consuming Hypermedia

Since we defined hypermedia attributes in the representer we can also consume this hypermedia wh

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Ruby

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言