roar 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -6
  3. data/CHANGES.markdown +75 -58
  4. data/CONTRIBUTING.md +31 -0
  5. data/Gemfile +12 -2
  6. data/ISSUE_TEMPLATE.md +20 -0
  7. data/LICENSE +1 -1
  8. data/README.markdown +126 -250
  9. data/Rakefile +3 -1
  10. data/examples/example.rb +0 -0
  11. data/examples/example_server.rb +0 -0
  12. data/lib/roar.rb +3 -3
  13. data/lib/roar/client.rb +8 -3
  14. data/lib/roar/decorator.rb +2 -2
  15. data/lib/roar/http_verbs.rb +0 -16
  16. data/lib/roar/hypermedia.rb +30 -56
  17. data/lib/roar/json.rb +5 -5
  18. data/lib/roar/json/collection.rb +10 -2
  19. data/lib/roar/json/hal.rb +72 -82
  20. data/lib/roar/version.rb +1 -1
  21. data/lib/roar/xml.rb +1 -1
  22. data/roar.gemspec +6 -6
  23. data/test/client_test.rb +1 -1
  24. data/test/coercion_feature_test.rb +7 -2
  25. data/test/decorator_test.rb +17 -7
  26. data/test/hal_json_test.rb +98 -106
  27. data/test/hypermedia_feature_test.rb +13 -31
  28. data/test/hypermedia_test.rb +26 -92
  29. data/test/{decorator_client_test.rb → integration/decorator_client_test.rb} +5 -4
  30. data/test/{faraday_http_transport_test.rb → integration/faraday_http_transport_test.rb} +1 -0
  31. data/test/{http_verbs_test.rb → integration/http_verbs_test.rb} +3 -2
  32. data/test/integration/json_collection_test.rb +35 -0
  33. data/test/{net_http_transport_test.rb → integration/net_http_transport_test.rb} +1 -0
  34. data/test/integration/runner.rb +2 -3
  35. data/test/integration/server.rb +6 -0
  36. data/test/json_representer_test.rb +2 -29
  37. data/test/lonely_test.rb +1 -2
  38. data/test/ssl_client_certs_test.rb +1 -1
  39. data/test/test_helper.rb +21 -3
  40. data/test/xml_representer_test.rb +6 -5
  41. metadata +22 -36
  42. data/gemfiles/Gemfile.representable-1.7 +0 -6
  43. data/gemfiles/Gemfile.representable-1.8 +0 -6
  44. data/gemfiles/Gemfile.representable-2.0 +0 -5
  45. data/gemfiles/Gemfile.representable-2.1 +0 -5
  46. data/gemfiles/Gemfile.representable-head +0 -6
  47. data/lib/roar/json/collection_json.rb +0 -208
  48. data/lib/roar/json/json_api.rb +0 -233
  49. data/test/collection_json_test.rb +0 -132
  50. data/test/hal_links_test.rb +0 -31
  51. data/test/json_api_test.rb +0 -451
  52. data/test/lib/runner.rb +0 -134
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f01bf5404137ba89f28ddcdbeb0f2248933321dc
4
- data.tar.gz: 3ddf4943609d770657728bb85e213c66244b039e
3
+ metadata.gz: a9315b89b6aa93848741828ab6a94e338677e397
4
+ data.tar.gz: c373cdb3f85a40560502cd9ef09ad88363499394
5
5
  SHA512:
6
- metadata.gz: 232903cf0f2a85f71105a2342dad1d226524c4f31d1a724dd7aaa3ad46cbffe4632f78e0967f6e4defb47d1bd6c7175c99ff14e51d1baa023d02cd404dc6812b
7
- data.tar.gz: 52c7b7189448a074580cdd1a3f7ac0cb192ea6c3a19eed5c32ac55fb496206b3d8d8008a95600b9c409df77f4e52bb5c4c602aef53e34250915297647bac53c1
6
+ metadata.gz: 059ab5ab647e9ec273976d485715dfed04895dc1538e8331025cea005995a1b9cf9cdb16c7e0ed34441f338594976e09c9ba48ccd071a2846aed5697a81f742c
7
+ data.tar.gz: 93101c0816d59b8ffe8465eddb7d5882f132322b1c00f4e44dd960c4b840ac0ce52f4d647245ebdec52682fccfb88c0716ee1c1b4d998c46e5edc6d92753cd4a
@@ -1,9 +1,17 @@
1
+ sudo: false
1
2
  rvm:
2
- - 1.9
3
- - 2.0
3
+ - 1.9.3
4
4
  - 2.1
5
- - 2.2
6
- - rbx-2
5
+ - 2.2.6
6
+ - 2.3.1
7
+ - 2.4.0
8
+ - jruby-9.1.6.0
9
+ - ruby-head
7
10
  gemfile:
8
- - gemfiles/Gemfile.representable-2.0
9
- - gemfiles/Gemfile.representable-2.1
11
+ - Gemfile
12
+ # - gemfiles/Gemfile.representable-2.4
13
+ before_install:
14
+ - gem install bundler
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
@@ -1,6 +1,16 @@
1
+ # 1.1.0
2
+
3
+ * Require Representable 3.0.x
4
+ * Remove CollectionJSON support until we get more feedback.
5
+ * Move JSON API support (`Roar::JSON::JSONAPI`) to the separate [roar-jsonapi](https://github.com/trailblazer/roar-jsonapi) gem.
6
+ * When using `links[]`, you now need to provide the string name, as in `decorator.links["self"]`. Symbols are not supported, anymore.
7
+ * `::links` now accepts a String or Symbol as its first argument, enabling more straight-forward definition of CURIE links: e.g. `links 'doc:link_collection' do; end` (@edejong).
8
+ * Clients can now parse lonely collections. (@hilary)
9
+
10
+
1
11
  # 1.0.4
2
12
 
3
- * Representable < 2.4.
13
+ * Require Representable < 2.4.
4
14
 
5
15
  # 1.0.3
6
16
 
@@ -17,7 +27,7 @@
17
27
 
18
28
  # 1.0.1
19
29
 
20
- * Allow calling `::has_one`, `::links` and `::has_many` in any order in JSON-API. This requires representable >= 2.1.4.
30
+ * Allow calling `::has_one`, `::links` and `::has_many` in any order in JSON API. This requires Representable >= 2.1.4.
21
31
 
22
32
  # 1.0.0
23
33
 
@@ -31,25 +41,24 @@
31
41
 
32
42
  ## Added
33
43
 
34
- * `Roar::JSON::JSONAPI` supports JSON-API. A big thanks to @oliverbarnes for his continous help, support and research on how to implement this standard.
35
-
44
+ * `Roar::JSON::JSONAPI` supports JSON API. A big thanks to @oliverbarnes for his continuous help, support and research on how to implement this standard.
36
45
 
37
46
  ## Relevant
38
47
 
39
48
  * `Hyperlink#to_hash` now returns stringified keys.
40
49
  * Removed `Representer#before_serialize` hook. Override `#serialize` yourself.
41
- * Represented#links now returns `nil` when no parsing has happened.
50
+ * `Represented#links` now returns `nil` when no parsing has happened.
42
51
  * Removed class methods `::from_json`, `::from_hash`, `::from_xml` and `::deserialize`. Please build the instance yourself and use something along `Song.new.from_json`.
43
52
 
44
53
  ## Internals
45
54
 
46
- * Remove the concept of ´links_array`. `Hyperlink` instances for rendering or that have been parsed are always stored in a `LinkCollection` that is available via `#links`.
55
+ * Remove the concept of `links_array`. `Hyperlink` instances for rendering or that have been parsed are always stored in a `LinkCollection` that is available via `#links`.
47
56
  * `Hypermedia` is now 43% simpler.
48
57
  * `HyperlinkCollection#each` now has different semantics for 1- or 2-arity.
49
58
 
50
59
  # 0.12.8
51
60
 
52
- * Last release to support representable < 2.0.
61
+ * Last release to support Representable < 2.0.
53
62
 
54
63
  # 0.12.7
55
64
 
@@ -57,11 +66,11 @@
57
66
 
58
67
  # 0.12.6
59
68
 
60
- * Remove deprecations (most of 'em) from representable-1.8. Sorry for that.
69
+ * Remove deprecations (most of 'em) from Representable 1.8. Sorry for that.
61
70
 
62
71
  # 0.12.5
63
72
 
64
- * Roar runs with representable <= 1.8.
73
+ * Roar runs with Representable <= 1.8.
65
74
 
66
75
  # 0.12.4
67
76
 
@@ -79,23 +88,22 @@
79
88
  * They now yield the request object to add headers etc before request is sent.
80
89
  * They NO LONGER support positional arguments but one hash with `uri: "https://roar.de", body:, .. as: ..` and so on.
81
90
 
82
-
83
91
  # 0.12.2
84
92
 
85
93
  * Fix a bug where hyperlinks from nested objects weren't rendered in XML.
86
94
 
87
95
  # 0.12.1
88
96
 
89
- Allow representable >= 1.6.
97
+ Allow Representable >= 1.6.
90
98
 
91
99
  # 0.11.18
92
100
 
93
- * Updating to representable-1.5.2.
101
+ * Updating to Representable 1.5.2.
94
102
 
95
103
  # 0.11.17
96
104
 
97
105
  * Fixing HAL + Decorator.
98
- * Requiring representable-1.5.0.
106
+ * Requiring Representable 1.5.0.
99
107
 
100
108
  # 0.11.16
101
109
 
@@ -103,15 +111,15 @@ Allow representable >= 1.6.
103
111
 
104
112
  # 0.11.15
105
113
 
106
- * Fixing [#66](https://github.com/apotonick/roar/issues/66).
114
+ * Fixing [#66](https://github.com/trailblazer/roar/issues/66).
107
115
 
108
116
  # 0.11.14
109
117
 
110
- * Fixing Gemfile.
118
+ * Fixing `Gemfile`.
111
119
 
112
120
  # 0.11.13
113
121
 
114
- * Adding `Roar::Decorator`, see [representable docs](https://github.com/apotonick/representable#decorator-vs-extend) for now.
122
+ * Adding `Roar::Decorator`, see [Representable docs](https://github.com/apotonick/Representable#decorator-vs-extend) for now.
115
123
 
116
124
  # 0.11.12
117
125
 
@@ -121,104 +129,113 @@ Allow representable >= 1.6.
121
129
 
122
130
  * Allow use of `::link(string)`.
123
131
 
124
- ## 0.11.10
132
+ # 0.11.10
125
133
 
126
134
  * Fix a syntax error for Ruby 1.8.
127
- * Store link definitions in `representable_attrs(:links)` now and no longer in the `LinksDefinition` instance itself. removing `#links_definition` in favor of `#link_configs`.
135
+ * Store link definitions in `Representable_attrs(:links)` now and no longer in the `LinksDefinition` instance itself. removing `#links_definition` in favor of `#link_configs`.
128
136
 
129
- ## 0.11.9
137
+ # 0.11.9
130
138
 
131
139
  * When using `Feature::Client` hyperlinks are no longer rendered in POST and PUT since we pass `links: false`.
132
140
  * `Transport::NetHttp` now sets both `Accept:` and `Content-type:` header since Rails services seems to get confused.
133
141
 
134
- ## 0.11.8
142
+ # 0.11.8
135
143
 
136
144
  * Fixed `JSON::HAL::Links` so that it keys links with `links` and not `_links`. The latter is still done by `JSON::HAL`.
137
145
 
138
- ## 0.11.7
146
+ # 0.11.7
139
147
 
140
148
  * Maintenance release: Fixing the horrible bug fix from 0.11.6 and make it a bit less horrible.
141
149
 
142
- ## 0.11.6
150
+ # 0.11.6
143
151
 
144
152
  * "Fixing" a bug where `links_definition_option` was missing when no link was set in a representer. Note that this is a quick and horrible bugfix and will soon be cleaned up.
145
153
 
146
- ## 0.11.5
154
+ # 0.11.5
147
155
 
148
- * Introducing HAL::links method to map arrays of link objects in the HAL format. This completes the HAL/JSON specification.
156
+ * Introducing `HAL::links` method to map arrays of link objects in the HAL format. This completes the HAL/JSON specification.
149
157
 
150
- ## 0.11.4
158
+ # 0.11.4
151
159
 
152
160
  * Links can now return a hash of attributes as `link :self do {:href => fruit_path(self), :title => "Yummy stuff"} end`.
153
161
 
154
- ## 0.11.3
162
+ # 0.11.3
155
163
 
156
164
  * Fixed an installation issue under Windows.
157
165
 
158
- ## 0.11.2
166
+ # 0.11.2
159
167
 
160
168
  * The request body in POST, PUT and PATCH is now actually sent in HttpVerbs. Thanks to @nleguen for finding this embarrassing bug. That's what happens when you don't have proper tests, kids!
161
169
 
162
- ## 0.11.1
170
+ # 0.11.1
171
+
172
+ * Since some users don't have access to my local hard-drive we now really require Representable 1.2.2.
163
173
 
164
- * Since some users don't have access to my local hard-drive we now really require representable-1.2.2.
174
+ # 0.11.0
165
175
 
166
- ## 0.11.0
176
+ * Using Representable 1.2.2 now. Be warned that in 1.2 parsing and rendering slightly changed. When a property is not found in the incoming document, it is ignored and thus might not be initialised in your represented model (empty collections are still set to an empty array). Also, the way `false` and `nil` values are rendered changed.
167
177
 
168
- * Using representable-1.2.2 now. Be warned that in 1.2 parsing and rendering slightly changed. When a property is not found in the incoming document, it is ignored and thus might not be initialised in your represented model (empty collections are still set to an empty array). Also, the way `false` and `nil` values are rendered changed. Quoted from the representable CHANGES file:
169
- * A property with false value will now be included in the rendered representation. Same applies to parsing, false values will now be included. That particularly means properties that used to be unset (i.e. nil) after parsing might be false now.
170
- * You can include nil values now in your representations since #property respects :represent_nil => true.
178
+ Quoted from the Representable CHANGES file:
171
179
 
172
- * The `:except` option got deprecated in favor of `:exclude`.
173
- * Hyperlinks can now have arbitrary attributes. To render, just provide `#link` with the options
174
- <code>link :self, :title => "Mee!", "data-remote" => true</code>
175
- When parsing, the options are avaible via `OpenStruct` compliant readers.
176
- <code>link = Hyperlink.from_json({\"rel\":\"self\",\"data-url\":\"http://self\"} )
177
- link.rel #=> "self"
178
- link.send("data-url") #=> "http://self"
179
- </code>
180
+ * A property with false value will now be included in the rendered representation. Same applies to parsing, false values will now be included. That particularly means properties that used to be unset (i.e. nil) after parsing might be false now.
181
+ * You can include nil values now in your representations since #property respects `:represent_nil => true`.
180
182
 
181
- ## 0.10.2
183
+ * The `:except` option was deprecated in favor of `:exclude`.
184
+ * Hyperlinks can now have arbitrary attributes.
185
+ To render, just provide `#link` with the options
186
+
187
+ ```ruby
188
+ link :self, :title => "Mee!", "data-remote" => true
189
+ ```
190
+
191
+ When parsing, the options are available via `OpenStruct` compliant readers.
192
+
193
+ ```ruby
194
+ link = Hyperlink.from_json('{"rel":"self","data-url":"http://self"'})
195
+ link.rel #=> "self"
196
+ link.send("data-url") #=> "http://self"
197
+ ```
198
+
199
+ # 0.10.2
182
200
 
183
201
  * You can now pass values from outside to the render method (e.g. `#to_json`), they will be available as block parameters inside `#link`.
184
202
 
185
- ## 0.10.1
203
+ # 0.10.1
186
204
 
187
205
  * Adding the Coercion feature.
188
206
 
189
- ## 0.10.0
207
+ # 0.10.0
190
208
 
191
- * Requiring representable-0.1.3.
209
+ * Requiring Representable 0.1.3.
192
210
  * Added JSON-HAL support.
193
211
  * Links are no longer rendered when `href` is `nil` or `false`.
194
212
  * `Representer.link` class method now accepts either the `rel` value, only, or a hash of link attributes (defined in `Hypermedia::Hyperlink.params`), like `link :rel => :self, :title => "You're good" do..`
195
213
  * API CHANGE: `Representer#links` no longer returns the `href` value but the link object. Use it like `object.links[:self].href` to retrieve the URL.
196
214
  * `#from_json` won't throw an exception anymore when passed an empty json document.
197
215
 
198
- ## 0.9.2
216
+ # 0.9.2
199
217
 
200
- * Using representable-1.1.
218
+ * Using Representable 1.1.
201
219
 
202
- ## 0.9.1
220
+ # 0.9.1
203
221
 
204
- * Removed @Representer#to_attributes@ and @#from_attributes@.
205
- * Using representable-1.0.1 now.
222
+ * Removed `Representer#to_attributes` and `#from_attributes`.
223
+ * Using Representable 1.0.1 now.
206
224
 
207
- ## 0.9.0
225
+ # 0.9.0
208
226
 
209
- * Using representable-0.12.x.
227
+ * Using Representable 0.12.x.
210
228
  * `Representer::Base` is now simply `Representer`.
211
229
  * Removed all the class methods from `HttpVerbs` except for `get`.
212
230
 
231
+ # 0.8.3
213
232
 
214
- ## 0.8.3
215
-
216
- * Maintenance release for representable compat.
233
+ * Maintenance release for Representable compat.
217
234
 
218
- ## 0.8.2
235
+ # 0.8.2
219
236
 
220
237
  * Removing `restfulie` dependency - we now use `Net::HTTP`.
221
238
 
222
- ## 0.8.1
239
+ # 0.8.1
223
240
 
224
- * Added the :except and :include options to `#from_*`.
241
+ * Added the `:except` and `:include` options to `#from_*`.
@@ -0,0 +1,31 @@
1
+ ## How to contribute to Roar
2
+
3
+ #### **Did you find a bug?**
4
+
5
+ * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/trailblazer/roar/issues).
6
+
7
+ * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/trailblazer/roar/issues/new). Be sure to follow the issue template.
8
+
9
+ #### **Did you write a patch that fixes a bug?**
10
+
11
+ * Open a new GitHub pull request with the patch.
12
+
13
+ * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
14
+
15
+ * All code in pull requests is assumed to be MIT licensed. Do not submit a pull request if that isn't the case.
16
+
17
+ #### **Do you intend to add a new feature or change an existing one?**
18
+
19
+ * Suggest your change in the [Trailblazer Gitter Room](https://gitter.im/trailblazer/chat) and start writing code.
20
+
21
+ * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
22
+
23
+ #### **Do you have questions using Roar?**
24
+
25
+ * Ask any questions about how to use Roar in the [Trailblazer Gitter Room](https://gitter.im/trailblazer/chat). Github issues are restricted to bug reports and fixes.
26
+
27
+ * GitHub Issues should not be used as a help forum and any such issues will be closed.
28
+
29
+ #### **Do you want to contribute to the Roar documentation?**
30
+
31
+ * Roar documentation is provided via the [Trailblazer site](http://trailblazer.to/gems/roar/) and not the repository readme. Please add your contributions to the [Trailblazer site repository](https://github.com/trailblazer/trailblazer.github.io)
data/Gemfile CHANGED
@@ -3,5 +3,15 @@ source "http://rubygems.org"
3
3
  # Specify your gem's dependencies in roar.gemspec
4
4
  gemspec
5
5
 
6
- # as long as this is not merged, i'll vendor the runner file.
7
- # gem "sinatra-contrib", :git => "git@github.com:apotonick/sinatra-contrib.git", :branch => "runner"
6
+ install_if -> { RUBY_VERSION > '2.2.2' } do
7
+ gem 'sinatra', '~> 2.0.0.beta2'
8
+ gem 'sinatra-contrib', github: 'sinatra/sinatra'
9
+ end
10
+
11
+ gem 'nokogiri', '~> 1.6.8'
12
+
13
+ # gem "representable", path: "../representable"
14
+ # gem "representable", github: "apotonick/representable"
15
+ # gem "declarative", path: "../declarative"
16
+ gem "minitest-line"
17
+ gem "pry"
@@ -0,0 +1,20 @@
1
+ Note: If you have a question about Roar, would like help using
2
+ Roar, want to request a feature, or do anything else other than
3
+ submit a bug report, please use the Trailblazer gitter channel.
4
+
5
+ ### Complete Description of Issue
6
+
7
+
8
+ ### Steps to reproduce
9
+
10
+
11
+ ### Expected behavior
12
+ Tell us what should happen
13
+
14
+ ### Actual behavior
15
+ Tell us what happens instead
16
+
17
+ ### System configuration
18
+ **Roar version**:
19
+
20
+ ### Full Backtrace of Exception (if any)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 - 2013 Nick Sutterer and the roar contributors
1
+ Copyright (c) 2011 - 2017 Nick Sutterer and the roar contributors
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,10 +1,47 @@
1
- # ROAR
1
+ # Roar
2
2
 
3
3
  _Resource-Oriented Architectures in Ruby._
4
4
 
5
- [![Build Status](https://travis-ci.org/apotonick/roar.svg?branch=master)](https://travis-ci.org/apotonick/roar)
6
- [![Gem Version](https://badge.fury.io/rb/roar.svg)](http://badge.fury.io/rb/roar)
7
5
  [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat)
6
+ [![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/)
7
+ [![Build Status](https://travis-ci.org/trailblazer/roar.svg?branch=master)](https://travis-ci.org/trailblazer/roar)
8
+ [![Gem Version](https://badge.fury.io/rb/roar.svg)](http://badge.fury.io/rb/roar)
9
+
10
+ ## Table of Contents
11
+
12
+ * [Introduction](#introduction)
13
+ * [Representable](#representable)
14
+ * [Installation](#installation)
15
+ * [Dependencies](#dependencies)
16
+ * [Defining Representers](#defining-representers)
17
+ * [Rendering](#rendering)
18
+ * [Parsing](#parsing)
19
+ * [Module Representers](#module-representers)
20
+ * [Collections](#collections)
21
+ * [Nesting](#nesting)
22
+ * [Inline Representer](#inline-representer)
23
+ * [Syncing Objects](#syncing-objects)
24
+ * [Coercion](#coercion)
25
+ * [More Features](#more-features)
26
+ * [Hypermedia](#hypermedia)
27
+ * [Passing Options](#passing-options)
28
+ * [Specify Decorator](#specify-decorator)
29
+ * [Consuming Hypermedia](#consuming-hypermedia)
30
+ * [Media Formats](#media-formats)
31
+ * [HAL\-JSON](#hal-json)
32
+ * [Hypermedia](#hypermedia-1)
33
+ * [Nesting](#nesting-1)
34
+ * [JSON API](#json-api)
35
+ * [Client\-Side Support](#client-side-support)
36
+ * [HTTP Support](#http-support)
37
+ * [HTTPS](#https)
38
+ * [Basic Authentication](#basic-authentication)
39
+ * [Client SSL certificates](#client-ssl-certificates)
40
+ * [Request customization](#request-customization)
41
+ * [Error handling](#error-handling)
42
+ * [XML](#xml)
43
+ * [Support](#support)
44
+ * [License](#license)
8
45
 
9
46
  ## Introduction
10
47
 
@@ -12,15 +49,15 @@ Roar is a framework for parsing and rendering REST documents. Nothing more.
12
49
 
13
50
  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.
14
51
 
15
- Roar comes with built-in JSON, JSON-HAL, JSON-API and XML support. Its highly modular architecture provides features like coercion, hypermedia, HTTP transport, client caching and more.
52
+ Roar comes with built-in JSON, JSON-HAL and XML support. JSON API support is available via the [JSON API](https://github.com/trailblazer/roar-jsonapi) gem. Its highly modular architecture provides features like coercion, hypermedia, HTTP transport, client caching and more.
16
53
 
17
- Roar is completely framework-agnostic and loves being used in web kits like Rails, Webmachine, Sinatra, Padrino, etc. If you use Rails, consider [roar-rails](https://github.com/apotonick/roar-rails) for an enjoyable integration.
54
+ 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](https://github.com/apotonick/roar-rails) for an enjoyable integration.
18
55
 
19
56
  ## Representable
20
57
 
21
- Roar is just a thin layer on top of the [representable](https://github.com/apotonick/representable) gem. While Roar gives you a DSL and behaviour for creating hypermedia APIs, representable implements all the mapping functionality.
58
+ Roar is just a thin layer on top of the [representable](https://github.com/trailblazer/representable) gem. While Roar gives you a DSL and behaviour for creating hypermedia APIs, representable implements all the mapping functionality.
22
59
 
23
- If in need for a feature, make sure to check the [representable API docs](https://github.com/apotonick/representable) first.
60
+ If in need for a feature, make sure to check the [representable API docs](https://github.com/trailblazer/representable) first.
24
61
 
25
62
  ## Installation
26
63
 
@@ -34,13 +71,13 @@ gem 'roar'
34
71
 
35
72
  Roar does not bundle dependencies for JSON and XML.
36
73
 
37
- If you want to use JSON, add the following to your Gemfile:
74
+ If you want to use JSON, add the following to your `Gemfile`:
38
75
 
39
76
  ```ruby
40
77
  gem 'multi_json'
41
78
  ```
42
79
 
43
- If you want to use XML, add the following to your Gemfile:
80
+ If you want to use XML, add the following to your `Gemfile`:
44
81
 
45
82
  ```ruby
46
83
  gem 'nokogiri'
@@ -52,21 +89,22 @@ gem 'nokogiri'
52
89
  Let's see how representers work. They're fun to use.
53
90
 
54
91
  ```ruby
92
+ require 'roar/decorator'
55
93
  require 'roar/json'
56
94
 
57
- module SongRepresenter
95
+ class SongRepresenter < Roar::Decorator
58
96
  include Roar::JSON
59
97
 
60
98
  property :title
61
99
  end
62
100
  ```
63
101
 
64
- API documents are defined using a representer module or decorator class. You can define plain attributes using the `::property` method.
102
+ API documents are defined using a decorator class. You can define plain attributes using the `::property` method.
65
103
 
66
- 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, Datamapper or just an OpenStruct instance.
104
+ 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.
67
105
 
68
106
  ```ruby
69
- class Song < ActiveRecord
107
+ class Song < ActiveRecord::Base
70
108
  end
71
109
  ```
72
110
 
@@ -75,66 +113,62 @@ end
75
113
  To render a document, you apply the representer to your model.
76
114
 
77
115
  ```ruby
78
- song = Song.new(title: "Fate")
79
- song.extend(SongRepresenter)
116
+ song = Song.new(title: "Medicine Balls")
80
117
 
81
- song.to_json #=> {"title":"Fate"}
118
+ SongRepresenter.new(song).to_json #=> {"title":"Medicine Balls"}
82
119
  ```
83
120
 
84
- Here, the representer is injected into the actual model and gives us a new `#to_json` method.
121
+ Here, the `song` objects gets wrapped (or "decorated") by the decorator. It is treated as immutable - Roar won't mix in any behaviour.
85
122
 
86
123
  ## Parsing
87
124
 
88
125
  The cool thing about representers is: they can be used for rendering and parsing. See how easy updating your model from a document is.
89
126
 
90
127
  ```ruby
91
- song = Song.new
92
- song.extend(SongRepresenter)
93
-
94
- song.from_json('{"title":"Linoleum"}')
128
+ song = Song.new(title: "Medicine Balls")
95
129
 
130
+ SongRepresenter.new(song).from_json('{"title":"Linoleum"}')
96
131
  song.title #=> Linoleum
97
132
  ```
98
133
 
99
- Again, `#from_json` comes from the representer and just updates the known properties.
100
-
101
134
  Unknown attributes in the parsed document are simply ignored, making half-baked solutions like `strong_parameters` redundant.
102
135
 
103
136
 
104
- ## Decorator
105
-
106
- Many people dislike `#extend` due to eventual performance issue or object pollution. If you're one of those, just go with a decorator representer. They almost work identical to the module approach we just discovered.
137
+ ## Module Representers
107
138
 
108
- ```ruby
109
- require 'roar/decorator'
139
+ **Module Representers are deprecated in Roar 1.1 and will be removed in Roar 2.0.**
110
140
 
111
- class SongRepresenter < Roar::Decorator
112
- include Roar::JSON
141
+ 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.
113
142
 
114
- property :title
115
- end
116
- ```
117
- In place of a module you use a class, the DSL inside is the same you already know.
118
143
 
119
144
  ```ruby
120
- song = Song.new(title: "Medicine Balls")
145
+ song = Song.new(title: "Fate")
146
+ song.extend(SongRepresenter)
121
147
 
122
- SongRepresenter.new(song).to_json #=> {"title":"Medicine Balls"}
148
+ song.to_json #=> {"title":"Fate"}
123
149
  ```
124
150
 
125
- Here, the `song` objects gets wrapped (or "decorated") by the decorator. It is treated as immutuable - Roar won't mix in any behaviour.
151
+ Here, the representer is injected into the actual model and gives us a new `#to_json` method.
126
152
 
127
- Note that decorators and representer modules have identical features. You can parse, render, nest, go nuts with both of them.
153
+ This also works both ways.
128
154
 
129
- However, in this README we'll use modules to illustrate this framework.
155
+ ```ruby
156
+ song = Song.new
157
+ song.extend(SongRepresenter)
158
+
159
+ song.from_json('{"title":"Fate"}')
160
+ song #=> {"title":"Fate"}
161
+ ```
162
+
163
+ 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.
130
164
 
131
165
 
132
166
  ## Collections
133
167
 
134
- Roar (or rather representable) also allows to map collections in documents.
168
+ Roar (or rather representable) also allows mapping collections in documents.
135
169
 
136
170
  ```ruby
137
- module SongRepresenter
171
+ class SongRepresenter < Roar::Decorator
138
172
  include Roar::JSON
139
173
 
140
174
  property :title
@@ -146,9 +180,8 @@ Where `::property` knows how to handle plain attributes, `::collection` does lis
146
180
 
147
181
  ```ruby
148
182
  song = Song.new(title: "Roxanne", composers: ["Sting", "Stu Copeland"])
149
- song.extend(SongRepresenter)
150
183
 
151
- song.to_json #=> {"title":"Roxanne","composers":["Sting","Stu Copeland"]}
184
+ SongRepresenter.new(song).to_json #=> {"title":"Roxanne","composers":["Sting","Stu Copeland"]}
152
185
  ```
153
186
 
154
187
  And, yes, this also works for parsing: `from_json` will create and populate the array of the `composers` attribute.
@@ -159,7 +192,7 @@ And, yes, this also works for parsing: `from_json` will create and populate the
159
192
  Now what if we need to tackle with collections of `Song`s? We need to implement an `Album` class.
160
193
 
161
194
  ```ruby
162
- class Album < ActiveRecord
195
+ class Album < ActiveRecord::Base
163
196
  has_many :songs
164
197
  end
165
198
  ```
@@ -167,7 +200,7 @@ end
167
200
  Another representer to represent.
168
201
 
169
202
  ```ruby
170
- module AlbumRepresenter
203
+ class AlbumRepresenter < Roar::Decorator
171
204
  include Roar::JSON
172
205
 
173
206
  property :title
@@ -184,38 +217,35 @@ Consider the following object setup.
184
217
  ```ruby
185
218
  album = Album.new(title: "True North")
186
219
  album.songs << Song.new(title: "The Island")
187
- album.songs << Song.new(:title => "Changing Tide")
220
+ album.songs << Song.new(title: "Changing Tide")
188
221
  ```
189
222
 
190
223
  You apply the `AlbumRepresenter` and you get a nested document.
191
224
 
192
225
  ```ruby
193
- album.extend(AlbumRepresenter)
194
-
195
- album.to_json #=> {"title":"True North","songs":[{"title":"The Island"},{"title":"Changing Tide"}]}
226
+ AlbumRepresenter.new(album).to_json #=> {"title":"True North","songs":[{"title":"The Island"},{"title":"Changing Tide"}]}
196
227
  ```
197
228
 
198
229
  This works vice-versa.
199
230
 
200
231
  ```ruby
201
232
  album = Album.new
202
- album.extend(AlbumRepresenter)
203
233
 
204
- album.from_json('{"title":"Indestructible","songs":[{"title":"Tropical London"},{"title":"Roadblock"}]}')
234
+ AlbumRepresenter.new(album).from_json('{"title":"Indestructible","songs":[{"title":"Tropical London"},{"title":"Roadblock"}]}')
205
235
 
206
236
  puts album.songs[1] #=> #<Song title="Roadblock">
207
237
  ```
208
238
 
209
239
  The nesting of two representers can map composed object as you find them in many many APIs.
210
240
 
211
- 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](https://github.com/apotonick/representable#document-nesting).
241
+ 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](https://github.com/trailblazer/representable#document-nesting).
212
242
 
213
243
  ## Inline Representer
214
244
 
215
245
  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.
216
246
 
217
247
  ```ruby
218
- module AlbumRepresenter
248
+ class AlbumRepresenter < Roar::Decorator
219
249
  include Roar::JSON
220
250
 
221
251
  property :title
@@ -234,7 +264,7 @@ This will give you the same rendering and parsing behaviour as in the previous e
234
264
  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:`.
235
265
 
236
266
  ```ruby
237
- module AlbumRepresenter
267
+ class AlbumRepresenter < Roar::Decorator
238
268
  include Roar::JSON
239
269
 
240
270
  property :title
@@ -248,14 +278,14 @@ This will advise Roar to update existing `songs`.
248
278
  ```ruby
249
279
  album.songs[0].object_id #=> 81431220
250
280
 
251
- album.from_json('{"title":"True North","songs":[{"title":"Secret Society"},{"title":"Changing Tide"}]}')
281
+ AlbumRepresenter.new(album).from_json('{"title":"True North","songs":[{"title":"Secret Society"},{"title":"Changing Tide"}]}')
252
282
 
253
283
  album.songs[0].title #=> Secret Society
254
284
  album.songs[0].object_id #=> 81431220
255
285
  ```
256
286
  Roar didn't create a new `Song` instance but updated its attributes, only.
257
287
 
258
- We're currently [working on](https://github.com/apotonick/roar/issues/85) better strategies to easily implement `POST` and `PUT` semantics in your APIs without having to worry about the nitty-gritties.
288
+ We're currently [working on](https://github.com/trailblazer/roar/issues/85) better strategies to easily implement `POST` and `PUT` semantics in your APIs without having to worry about the nitty-gritties.
259
289
 
260
290
 
261
291
  ## Coercion
@@ -264,8 +294,9 @@ Roar provides coercion with the [virtus](https://github.com/solnic/virtus) gem.
264
294
 
265
295
  ```ruby
266
296
  require 'roar/coercion'
297
+ require 'roar/json'
267
298
 
268
- module SongRepresenter
299
+ class SongRepresenter < Roar::Decorator
269
300
  include Roar::JSON
270
301
  include Roar::Coercion
271
302
 
@@ -278,9 +309,8 @@ The `:type` option allows to set a virtus-compatible type.
278
309
 
279
310
  ```ruby
280
311
  song = Song.new
281
- song.extend(SongRepresenter)
282
312
 
283
- song.from_json('{"released_at":"1981/03/31"}')
313
+ SongRepresenter.new(song).from_json('{"released_at":"1981/03/31"}')
284
314
 
285
315
  song.released_at #=> 1981-03-31T00:00:00+00:00
286
316
  ```
@@ -288,7 +318,7 @@ song.released_at #=> 1981-03-31T00:00:00+00:00
288
318
 
289
319
  ## More Features
290
320
 
291
- Roar/representable gives you many more mapping features like [renaming attributes](https://github.com/apotonick/representable/#aliasing), [wrapping](https://github.com/apotonick/representable/#wrapping), [passing options](https://github.com/apotonick/representable/#passing-options), etc.
321
+ Roar/representable gives you many more mapping features like renaming attributes, wrapping, passing options, etc. See the [representable documentation](http://trailblazer.to/gems/representable/3.0/api.html) for a detailed explanation.
292
322
 
293
323
 
294
324
  ## Hypermedia
@@ -296,7 +326,7 @@ Roar/representable gives you many more mapping features like [renaming attribute
296
326
  Roar comes with built-in support for embedding and processing hypermedia in your documents.
297
327
 
298
328
  ```ruby
299
- module SongRepresenter
329
+ class SongRepresenter < Roar::Decorator
300
330
  include Roar::JSON
301
331
  include Roar::Hypermedia
302
332
 
@@ -324,8 +354,7 @@ end
324
354
  This will render links into your representation.
325
355
 
326
356
  ```ruby
327
- song.extend(SongRepresenter)
328
- song.to_json #=> {"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}
357
+ SongRepresenter.new(song).to_json #=> {"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}
329
358
  ```
330
359
 
331
360
  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`).
@@ -338,7 +367,7 @@ Also, note that [roar-rails](https://github.com/apotonick/roar-rails) allows usi
338
367
  Sometimes you need more data in the link block. Data that's not available from the represented model.
339
368
 
340
369
  ```ruby
341
- module SongRepresenter
370
+ class SongRepresenter < Roar::Decorator
342
371
  include Roar::JSON
343
372
 
344
373
  property :title
@@ -352,20 +381,36 @@ end
352
381
  Pass this data to the rendering method.
353
382
 
354
383
  ```ruby
355
- song.to_json(base_url: "localhost:3001/")
384
+ representer = SongRepresenter.new(song)
385
+ representer.to_json(base_url: "localhost:3001/")
356
386
  ```
357
387
 
358
388
  Any options passed to `#to_json` will be available as block arguments in the link blocks.
359
389
 
360
390
 
391
+ ## Specify Decorator
392
+
393
+ 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.
394
+
395
+ ```ruby
396
+ class ArtistRepresenter < Roar::Decorator
397
+ property :name
398
+ end
399
+
400
+ class AlbumRepresenter < Roar::Decorator
401
+ # ..
402
+ property :artist, decorator: ArtistRepresenter
403
+ end
404
+ ```
405
+
361
406
  ## Consuming Hypermedia
362
407
 
363
408
  Since we defined hypermedia attributes in the representer we can also consume this hypermedia when we parse documents.
364
409
 
365
410
  ```ruby
366
- song.from_json('{"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}')
411
+ representer.from_json('{"title":"Roxanne","links":[{"rel":"self","href":"http://songs/Roxanne"}]}')
367
412
 
368
- song.links[:self].href #=> "http://songs/Roxanne"
413
+ representer.links[:self].href #=> "http://songs/Roxanne"
369
414
  ```
370
415
 
371
416
  Reading link attributes works by using `#links[]` on the consuming instance.
@@ -375,7 +420,7 @@ This allows an easy way to discover hypermedia and build navigational logic on t
375
420
 
376
421
  ## Media Formats
377
422
 
378
- While Roar comes with a built-in hypermedia format, there's official media types that are widely recognized. Roar currently supports HAL and Collection+JSON. Support for Siren and JSON-API is planned when there's sponsors.
423
+ While Roar comes with a built-in hypermedia format, there's official media types that are widely recognized. Roar currently supports HAL and JSON API.
379
424
 
380
425
  Simply by including a module you make your representer understand the media type. This makes it easy to change formats during evaluation.
381
426
 
@@ -386,7 +431,7 @@ The [HAL](http://stateless.co/hal_specification.html) format is a simple media t
386
431
  ```ruby
387
432
  require 'roar/json/hal'
388
433
 
389
- module SongRepresenter
434
+ class SongRepresenter < Roar::Decorator
390
435
  include Roar::JSON::HAL
391
436
 
392
437
  property :title
@@ -397,7 +442,7 @@ module SongRepresenter
397
442
  end
398
443
  ```
399
444
 
400
- Documentation for HAL can be found in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/JSON/HAL).
445
+ Documentation for HAL can be found in the [API docs](http://rdoc.info/github/trailblazer/roar/Roar/JSON/HAL).
401
446
 
402
447
  Make sure you [understand the different contexts](#hypermedia) for links when using decorators.
403
448
 
@@ -406,7 +451,7 @@ Make sure you [understand the different contexts](#hypermedia) for links when us
406
451
  Including the `Roar::JSON::HAL` module adds some more DSL methods to your module. It still allows using `::link` but treats them slightly different.
407
452
 
408
453
  ```ruby
409
- song.to_json
454
+ representer.to_json
410
455
  #=> {"title":"Roxanne","_links":{"self":{"href":"http://songs/Roxanne"}}}
411
456
  ```
412
457
 
@@ -419,7 +464,7 @@ Parsing works like-wise: Roar will use the same setters as before but it knows h
419
464
  Nested, or embedded, resources can be defined using the `:embedded` option.
420
465
 
421
466
  ```ruby
422
- module AlbumRepresenter
467
+ class AlbumRepresenter < Roar::Decorator
423
468
  include Roar::JSON::HAL
424
469
 
425
470
  property :title
@@ -433,187 +478,18 @@ end
433
478
  To embed a resource, you can use an inline representer or use `:extend` to specify the representer name.
434
479
 
435
480
  ```ruby
436
- album.to_json
481
+ AlbumRepresenter.new(album).to_json
437
482
 
438
483
  #=> {"title":"True North","_embedded":{"songs":[{"title":"The Island"},{"title":"Changing Tide"}]}}
439
484
  ```
440
485
 
441
486
  HAL keys nested resources under the `_embedded` key and then by their type.
442
487
 
443
- All HAL features in Roar are discussed in the [API docs](http://rdoc.info/github/apotonick/roar/Roar/JSON/HAL), including [array links](https://github.com/apotonick/roar/blob/master/lib/roar/json/hal.rb#L196).
444
-
445
-
446
- ## JSON-API
447
-
448
- Roar also supports [JSON-API](http://jsonapi.org/) - yay! It can render _and_ parse singular and collection documents.
449
-
450
- Note that you need representable >= 2.1.4 in your `Gemfile`.
451
-
452
- ### Resource
453
-
454
- A minimal representation can be defined as follows.
455
-
456
- ```ruby
457
- require 'roar/json/json_api'
458
-
459
- module SongsRepresenter
460
- include Roar::JSON::JSONAPI
461
- type :songs
462
-
463
- property :id
464
- property :title
465
- end
466
- ```
467
-
468
- Properties of the represented model are defined in the root level.
469
-
470
- ### Hypermedia
471
-
472
- You can add links to `linked` models within the resource section.
473
-
474
- ```ruby
475
- module SongsRepresenter
476
- # ...
477
-
478
- has_one :composer
479
- has_many :listeners
480
- end
481
- ```
482
-
483
- Global `links` can be added using the familiar `::link` method (this is still WIP as the DSL is not final).
484
-
485
- ```ruby
486
- module SongsRepresenter
487
- # ...
488
-
489
- link "songs.album" do
490
- {
491
- type: "album",
492
- href: "http://example.com/albums/{songs.album}"
493
- }
494
- end
495
- end
496
- ```
497
-
498
- ### Compounds
499
-
500
- To add compound models into the document, use `::compound`.
501
-
502
- ```ruby
503
- module SongsRepresenter
504
- # ...
505
-
506
- compound do
507
- property :album do
508
- property :id
509
- property :title
510
- end
511
-
512
- collection :musicians do
513
- property :name
514
- end
515
- end
516
- ```
517
-
518
- ### Meta Data
519
-
520
- Meta data can be included into the rendered collection document in two ways. Please note that parsing the `meta` field is not implemented, yet, as I wasn't sure if people need it.
521
-
522
- You can define meta data on your collection object and then let Roar compile it.
488
+ All HAL features in Roar are discussed in the [API docs](http://rdoc.info/github/trailblazer/roar/Roar/JSON/HAL), including [array links](https://github.com/trailblazer/roar/blob/master/lib/roar/json/hal.rb#L196).
523
489
 
524
- ```ruby
525
- module SongsRepresenter
526
- # ..
527
-
528
- meta do
529
- property :page
530
- property :total
531
- end
532
- ```
533
-
534
- Your collection object has to expose those methods.
535
-
536
- ```ruby
537
- collection.page #=> 1
538
- collection.total #=> 12
539
- ```
540
-
541
- This will render the `{"meta": {"page": 1, "total": 12}}` hash into the JSON-API document.
542
-
543
- Another way is to provide the _complete_ meta data hash when rendering. You must not define any `meta` properties in the representer when using this approach.
544
-
545
- ```ruby
546
- collection.to_json("meta" => {page: params["page"], total: collection.size})
547
- ```
548
-
549
- If you need more functionality (and parsing), please let us know.
550
-
551
- ### Usage
552
-
553
- As JSON-API per definition can represent singular models and collections you have two entry points.
554
-
555
- ```ruby
556
- SongsRepresenter.prepare(Song.find(1)).to_json
557
- SongsRepresenter.prepare(Song.new).from_json("..")
558
- ```
559
-
560
- Singular models can use the representer module directly.
561
-
562
- ```ruby
563
- SongsRepresenter.for_collection.prepare([Song.find(1), Song.find(2)]).to_json
564
- SongsRepresenter.for_collection.prepare([Song.new, Song.new]).from_json("..")
565
- ```
566
-
567
-
568
- Parsing currently works great with singular documents - for collections, we are still working out how to encode the application semantics. Feel free to help.
569
-
570
-
571
- ## Collection+JSON
572
-
573
- The [Collection+JSON media format](http://amundsen.com/media-types/collection/) defines document format and semantics for requests. It is currently experimental as we're still exploring how we optimize the support with Roar. Let us know if you're using it.
574
-
575
- ```ruby
576
- module SongRepresenter
577
- include Roar::JSON::CollectionJSON
578
- version "1.0"
579
- href { "http://localhost/songs/" }
580
-
581
- property :title
582
-
583
- items(:class => Song) do
584
- href { "//songs/#{title}" }
585
-
586
- property :title, :prompt => "Song title"
587
-
588
- link(:download) { "//songs/#{title}.mp3" }
589
- end
590
-
591
- template do
592
- property :title, :prompt => "Song title"
593
- end
594
-
595
- queries do
596
- link :search do
597
- {:href => "//search", :data => [{:name => "q", :value => ""}]}
598
- end
599
- end
600
- end
601
- ```
602
-
603
- It renders a document following the Collection+JSON specs.
604
-
605
- ```
606
- #=> {"collection":{
607
- "template":{"data":[{"name":"title","value":null}]},
608
- "queries":[{"rel":"search","href":"//search","data":[{"name":"q","value":""}]}],
609
- "version":"1.0",
610
- "href":"http://localhost/songs/",
611
- "title":"Roxanne",
612
- "items":null}}
613
- ```
614
-
615
- We have big plans with this media format, as the object model in Roar plays nicely with Collection+JSON's API semantics.
490
+ ## JSON API
616
491
 
492
+ Roar also supports [JSON API](http://jsonapi.org/) via the [Roar JSON API gem](https://github.com/trailblazer/roar-jsonapi).
617
493
 
618
494
  ## Client-Side Support
619
495
 
@@ -622,7 +498,7 @@ Being a bi-directional mapper that does rendering _and_ parsing, Roar represente
622
498
  Consider the following shared representer.
623
499
 
624
500
  ```ruby
625
- module SongRepresenter
501
+ class SongRepresenter < Roar::Decorator
626
502
  include Roar::JSON
627
503
  include Roar::Hypermedia
628
504
 
@@ -639,6 +515,7 @@ In a client where you don't have access to the database it is common to use `Ope
639
515
 
640
516
  ```ruby
641
517
  require 'roar/client'
518
+ require 'roar/json'
642
519
 
643
520
  class Song < OpenStruct
644
521
  include Roar::JSON
@@ -734,7 +611,7 @@ rescue Roar::Transport::Error => exception
734
611
  Roar also comes with XML support.
735
612
 
736
613
  ```ruby
737
- module SongRepresenter
614
+ class SongRepresenter < Roar::Decorator
738
615
  include Roar::XML
739
616
  include Roar::Hypermedia
740
617
 
@@ -751,9 +628,8 @@ Include the `Roar::XML` engine and get bi-directional XML for your objects.
751
628
 
752
629
  ```ruby
753
630
  song = Song.new(title: "Roxanne", id: 42)
754
- song.extend(XML::SongRepresenter)
755
631
 
756
- song.to_xml
632
+ SongRepresenter.new(song).to_xml
757
633
  ```
758
634
 
759
635
  Note that you now use `#to_xml` and `#from_xml`.
@@ -766,7 +642,7 @@ Note that you now use `#to_xml` and `#from_xml`.
766
642
  </song>
767
643
  ```
768
644
 
769
- Please consult the [representable XML documentation](https://github.com/apotonick/representable/#more-on-xml) for all its great features.
645
+ Please consult the [representable XML documentation](https://github.com/trailblazer/representable/#more-on-xml) for all its great features.
770
646
 
771
647
 
772
648
  ## Support