subjoin 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +23 -0
- data/.yardops +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +431 -0
- data/Rakefile +11 -0
- data/lib/subjoin.rb +85 -0
- data/lib/subjoin/attributable.rb +28 -0
- data/lib/subjoin/document.rb +136 -0
- data/lib/subjoin/errors.rb +15 -0
- data/lib/subjoin/identifier.rb +23 -0
- data/lib/subjoin/inclusions.rb +39 -0
- data/lib/subjoin/inheritable.rb +80 -0
- data/lib/subjoin/jsonapi.rb +13 -0
- data/lib/subjoin/link.rb +30 -0
- data/lib/subjoin/linkable.rb +18 -0
- data/lib/subjoin/meta.rb +10 -0
- data/lib/subjoin/metable.rb +21 -0
- data/lib/subjoin/relationship.rb +32 -0
- data/lib/subjoin/resource.rb +93 -0
- data/lib/subjoin/version.rb +4 -0
- data/spec/document_spec.rb +210 -0
- data/spec/identifier_spec.rb +33 -0
- data/spec/inclusions_spec.rb +69 -0
- data/spec/inheritable_resource_spec.rb +89 -0
- data/spec/link_spec.rb +60 -0
- data/spec/meta_spec.rb +11 -0
- data/spec/relationship_spec.rb +64 -0
- data/spec/resource_spec.rb +139 -0
- data/spec/responses/404.json +8 -0
- data/spec/responses/article_example.json +37 -0
- data/spec/responses/compound_example.json +73 -0
- data/spec/responses/links.json +9 -0
- data/spec/responses/meta.json +13 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/subjoin_spec.rb +99 -0
- data/subjoin.gemspec +27 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c16909a79d122afbd6289561e3f503e179d44734
|
4
|
+
data.tar.gz: 1b036b2b58b8a7c6726e8d249519c8edbafa9c32
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6255701286835abd2de5b460ecbac170d97c4aa696762b5f48b5922e34655608fec42d1d3752015a5e2f1b8a9d725c7f2199bd6b06ea5b97cb643aaeb8660ef4
|
7
|
+
data.tar.gz: 389a8f8796ef43e13ef4abc58cbfb0e4cc82156c148301ff4485fe6e19dac966205019efd3f094f9d27bab5842ba1483cd18103cb17c617d83bb87c7657d403a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- ruby-head
|
4
|
+
- jruby-head
|
5
|
+
- 2.1.1
|
6
|
+
- 2.0.0
|
7
|
+
- 1.9.3
|
8
|
+
- 1.9.2
|
9
|
+
- jruby-19mode
|
10
|
+
- jruby-18mode
|
11
|
+
- rbx-2.1.1
|
12
|
+
- rbx-2.0.0
|
13
|
+
- 1.8.7
|
14
|
+
matrix:
|
15
|
+
allow_failures:
|
16
|
+
- rvm: rbx-2.1.1
|
17
|
+
- rvm: rbx-2.0.0
|
18
|
+
- rvm: 1.8.7
|
19
|
+
- rvm: jruby-head
|
20
|
+
- rvm: jruby-18mode
|
21
|
+
addons:
|
22
|
+
code_climate:
|
23
|
+
repo_token: 56b7b3204fa5160be4b85c3777da27214d517c3874ca238a473f76f0b83f3f69
|
data/.yardops
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-m markdown
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Sean Redmond
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,431 @@
|
|
1
|
+
# Subjoin
|
2
|
+
|
3
|
+
A practical wrapper for [JSON-API](http://jsonapi.org) interactions.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'subjoin'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install subjoin
|
20
|
+
|
21
|
+
## Documentation
|
22
|
+
|
23
|
+
For full documentation run
|
24
|
+
|
25
|
+
$ yardoc
|
26
|
+
$ yard server
|
27
|
+
|
28
|
+
Then load http://localhost:8808 in your browser
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
### Document
|
33
|
+
|
34
|
+
Everything starts with a document, specifically a `Subjoin::Document` -- the equivalent of a [JSON-API document](http://jsonapi.org/format/) which you
|
35
|
+
can create with a URI:
|
36
|
+
|
37
|
+
require "subjoin"
|
38
|
+
doc = Subjoin::Document.new(URI("http://example.com/articles"))
|
39
|
+
|
40
|
+
(all examples here based on examples in the
|
41
|
+
[JSON-API documentation](http://jsonapi.org/format/))
|
42
|
+
|
43
|
+
Note that you must pass a
|
44
|
+
[URI object](http://ruby-doc.org/stdlib-2.2.2/libdoc/uri/rdoc/URI.html). A
|
45
|
+
string would be interpreted as a JSON-API `type`.
|
46
|
+
|
47
|
+
A `Subjoin::Document` probably has "primary data" which, if present is an Array
|
48
|
+
of `Subjoin::Resource` objects:
|
49
|
+
|
50
|
+
doc.has_data? # true if there is primary data
|
51
|
+
=> true
|
52
|
+
doc.data # Array of Subjoin::Resource objects
|
53
|
+
doc.data.first # One resource
|
54
|
+
|
55
|
+
The `data` member of a JSON-API document can be either a single resource object
|
56
|
+
or an array of resource objects. `Subjoin::Document#data` always returns an
|
57
|
+
Array. In a document with a single resource object, the Array will have one
|
58
|
+
element.
|
59
|
+
|
60
|
+
You can access all the other members of the [top-level document](http://jsonapi.org/format/#document-top-level) (all the objects returned are covered below):
|
61
|
+
|
62
|
+
doc.links # Hash of Link objects
|
63
|
+
doc.included # Inclusions object
|
64
|
+
doc.meta # Meta object
|
65
|
+
doc.jsonapi # JsonApi object
|
66
|
+
|
67
|
+
There are, in addition, methods to test whether any of the above members are
|
68
|
+
present:
|
69
|
+
|
70
|
+
doc.has_data?
|
71
|
+
doc.has_links?
|
72
|
+
doc.has_included?
|
73
|
+
doc.has_meta?
|
74
|
+
doc.has_jsonapi?
|
75
|
+
|
76
|
+
### Resources
|
77
|
+
|
78
|
+
Every `Subjoin::Resource` has a `type` and `id`. The JSON response:
|
79
|
+
|
80
|
+
{
|
81
|
+
"data": {
|
82
|
+
"type": "articles",
|
83
|
+
"id": "1",
|
84
|
+
"attributes": {
|
85
|
+
"title": "JSON API paints my bikeshed!"
|
86
|
+
},
|
87
|
+
...
|
88
|
+
}
|
89
|
+
|
90
|
+
would correspond to:
|
91
|
+
|
92
|
+
article = doc.data.first
|
93
|
+
article.type
|
94
|
+
=> "articles"
|
95
|
+
article.id
|
96
|
+
=> "1"
|
97
|
+
|
98
|
+
The attributes of a `Subjoin::Resource` object, or any object that
|
99
|
+
includes `Subjoin::Attributable`, can be accessed like hash on the
|
100
|
+
object itself:
|
101
|
+
|
102
|
+
article["title"]
|
103
|
+
=> "JSON API paints my bikeshed!"
|
104
|
+
|
105
|
+
You can also get the entire attributes Hash as
|
106
|
+
`Subjoin::Attributable#attributes`:
|
107
|
+
|
108
|
+
article.attributes # Hash
|
109
|
+
article.attributes.keys
|
110
|
+
=> ["title"]
|
111
|
+
article.attributes["title"]
|
112
|
+
=> "JSON API paints my bikeshed!"
|
113
|
+
|
114
|
+
The other expected members of a
|
115
|
+
[resource object](http://jsonapi.org/format/#document-resource-objects) are
|
116
|
+
available. The objects returned by these methods are all explained below:
|
117
|
+
|
118
|
+
article.links # Hash of Link objects
|
119
|
+
article.relationships # Array of Relationship objects
|
120
|
+
article.meta # Meta object
|
121
|
+
|
122
|
+
As with `Subjoin::Document`, there are methods to see if any of the above are available
|
123
|
+
|
124
|
+
article.has_links?
|
125
|
+
article.has_meta?
|
126
|
+
|
127
|
+
### Links
|
128
|
+
|
129
|
+
`Subjoin::Document`, `Subjoin::Resource`, and `Subjoin::Relationship` can all
|
130
|
+
have [links](http://jsonapi.org/format/#document-links). They all have
|
131
|
+
the `Subjoin::Linkable#links` method which returns a Hash of `Subjoin::Link`
|
132
|
+
objects:
|
133
|
+
|
134
|
+
article.links.keys
|
135
|
+
=> ["self"]
|
136
|
+
article.links["self"].href.to_s
|
137
|
+
=> "http://example.com/articles/1"
|
138
|
+
|
139
|
+
JSON-API allows for two link object formats. One simply has a link
|
140
|
+
|
141
|
+
"links": {
|
142
|
+
"self": "http://example.com/articles/1"
|
143
|
+
}
|
144
|
+
|
145
|
+
and one has an `href` attribute and `meta` object:
|
146
|
+
|
147
|
+
"links": {
|
148
|
+
"related": {
|
149
|
+
"href": "http://example.com/articles/1/comments",
|
150
|
+
"meta": {
|
151
|
+
"count": 10
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
Subjoin treats either variation like the latter:
|
157
|
+
|
158
|
+
article.links["self"].href.to_s
|
159
|
+
=> "http://example.com/articles/1"
|
160
|
+
article.links["self"].has_meta?
|
161
|
+
=> false
|
162
|
+
article.links["self"].meta?
|
163
|
+
=> nil
|
164
|
+
|
165
|
+
article.links["related"].href.to_s
|
166
|
+
=> "http://example.com/articles/1/comments"
|
167
|
+
article.links["related"].has_meta?
|
168
|
+
=> true
|
169
|
+
article.links["related"].meta["count"]
|
170
|
+
=> 10
|
171
|
+
|
172
|
+
Note that the `href` is always returned as a `URI` object. If you have a `Subjoin::Link` you can get the corresponding `Subjoin::Document`:
|
173
|
+
|
174
|
+
article.links["related"].get # Same thing as Subjoin::Document.new
|
175
|
+
# with the URL
|
176
|
+
|
177
|
+
### Resource Identifiers
|
178
|
+
|
179
|
+
Before getting to relationships, we should take a minute to look at
|
180
|
+
[resource identifiers](http://jsonapi.org/format/#document-resource-identifier-objects). Above,
|
181
|
+
we saw that every `Subjoin::Resource` has a `type` and `id`.
|
182
|
+
|
183
|
+
article.type # "articles"
|
184
|
+
article.id # "1"
|
185
|
+
|
186
|
+
Though the above attributes exist individually, these two attributes
|
187
|
+
work together as a compound key and are, in fact put together in
|
188
|
+
Subjoin as a `Subjoin::Identifier` object:
|
189
|
+
|
190
|
+
article.identifier # Identifier object
|
191
|
+
article.identifier.type # "articles"
|
192
|
+
article.identifier.id # "1"
|
193
|
+
|
194
|
+
`Subjoin::Identifier` objects are used for equality: two
|
195
|
+
`Subjoin::Resource` objects are considered equal if they have equal
|
196
|
+
`Identifer`s:
|
197
|
+
|
198
|
+
article1 == article2 # Really tests...
|
199
|
+
article1.identifier == article2.identifier # Really tests...
|
200
|
+
article1.identifier.type == article2.identifier.type &&
|
201
|
+
article1.identifer.id == article2.identifier.id
|
202
|
+
|
203
|
+
More importantly, identifiers occur in Relationship objects as
|
204
|
+
pointers to other resources. These pointers are called
|
205
|
+
[linkages](http://jsonapi.org/format/#document-resource-object-linkage):
|
206
|
+
|
207
|
+
article.relationships.author.linkages # Array of Identifier objects
|
208
|
+
|
209
|
+
They may have, optionally, a `meta` attribute as well, and `meta`
|
210
|
+
attributes are ignored in tests for equality.
|
211
|
+
|
212
|
+
### Relationships, Linkages, Included Resources
|
213
|
+
|
214
|
+
Okay, now we can get to how you'll really use JSON-API resources and why you would JSON-API over other options: resource linking and included resources.
|
215
|
+
|
216
|
+
In many RESTful APIs, resources have embedded child resources which
|
217
|
+
is, in my experience, a principle source of the bikeshedding arguments
|
218
|
+
that JSON-API tries to avoid ("should X be a child of Y, or Y a child
|
219
|
+
of X?" "How should the X response be different when it is achild of
|
220
|
+
another resource?"). Instead of nesting and embedding, in JSON-API
|
221
|
+
resources may have
|
222
|
+
[relationships](http://jsonapi.org/format/#document-resource-object-relationships)
|
223
|
+
to other resources.
|
224
|
+
|
225
|
+
article.relationships # A Hash of Subjoin::Relationship objects
|
226
|
+
article.relationships.keys
|
227
|
+
=> ["author", "comments"]
|
228
|
+
|
229
|
+
This much tells you that an "article" can have an "author" and
|
230
|
+
"comments". In Subjoin, relationships are instantiated as
|
231
|
+
`Subjoin::Relationship` objects whose two important properties are
|
232
|
+
`links` and `linkages`. `Subjoin::Relationship` are
|
233
|
+
`Subjoin::Linkable` so `links` works as it does in other objects.
|
234
|
+
|
235
|
+
author = article.relationships["author"] # Relationship object
|
236
|
+
author.links.keys
|
237
|
+
=> ["self", "related"]
|
238
|
+
author.links["related"].to_s
|
239
|
+
=> "http://example.com/articles/1/author"
|
240
|
+
author.links["related"].get # Get a new Document
|
241
|
+
|
242
|
+
Alongside `links`, `linkages` give you resource identifiers for the
|
243
|
+
related resources. while the "comments" `link` tells us how to get a
|
244
|
+
document with all the related comments:
|
245
|
+
|
246
|
+
comments.links["self"].to_s
|
247
|
+
=> "http://example.com/articles/1/relationships/comments"
|
248
|
+
|
249
|
+
The corresponding `linkages` returns an Array of
|
250
|
+
`Subjoin::Identifier` that are pointers to specific resources:
|
251
|
+
|
252
|
+
comments = article.relationships["comments"]
|
253
|
+
comments.linkages.count
|
254
|
+
=> 2
|
255
|
+
|
256
|
+
This tells us that there are two related comments. If we look at one,
|
257
|
+
we can get the type and id:
|
258
|
+
|
259
|
+
comments.linkages[0].type
|
260
|
+
=> "comments"
|
261
|
+
comments.linkages[0].id
|
262
|
+
=> "5"
|
263
|
+
|
264
|
+
So far so good, but now what? [Inclusion](http://jsonapi.org/format/#fetching-includes)
|
265
|
+
|
266
|
+
With Subjoin, you can request that these related resources be included
|
267
|
+
in the document, one of three ways:
|
268
|
+
|
269
|
+
# URI parameters
|
270
|
+
doc = Subjoin::Document.new(URI("http://example.com/articles/1?include=author,comments"))
|
271
|
+
|
272
|
+
# Parameters Hash with a string
|
273
|
+
doc = Subjoin::Document.new(URI("http://example.com/article/1s", {"include" => "author,comments"}))
|
274
|
+
|
275
|
+
# Parameters Hash with an array of strings
|
276
|
+
doc = Subjoin::Document.new(URI("http://example.com/articles/1", {"include" => ["author" ,"comments"]}))
|
277
|
+
|
278
|
+
All three are equivalent. The array of strings version works especially well with relationship keys
|
279
|
+
|
280
|
+
doc2 = Subjoin::Document.new(URI("http://example.com/articles/1", {"include" => articles.relationships.keys}))
|
281
|
+
|
282
|
+
When a document is requested with included resources, they can be accessed via `included`
|
283
|
+
|
284
|
+
# Get the document
|
285
|
+
doc = Subjoin::Document.new(URI("http://example.com/articles/1", {"include" => ["author" ,"comments"]}))
|
286
|
+
|
287
|
+
# Get the article
|
288
|
+
article = doc.data.first
|
289
|
+
|
290
|
+
# Get the realted author identifier
|
291
|
+
auth_identifier = article.related["author"].linkages.first
|
292
|
+
auth_identifier.type
|
293
|
+
=> "people"
|
294
|
+
auth_identifier.id
|
295
|
+
=> "9"
|
296
|
+
|
297
|
+
# Get the embedded resource
|
298
|
+
doc.has_included?
|
299
|
+
=> true
|
300
|
+
|
301
|
+
# Look up included resource by identifier
|
302
|
+
author = doc.included[auth_identifier]
|
303
|
+
|
304
|
+
# Now we have access to the whole author resource
|
305
|
+
author.type
|
306
|
+
=> "people"
|
307
|
+
author.id
|
308
|
+
=> "9"
|
309
|
+
author["twitter"]
|
310
|
+
=> "dgeb"
|
311
|
+
|
312
|
+
If that sounds kind of complicated, it is. But you can...
|
313
|
+
|
314
|
+
### Let Subjoin resolve the linkages for you
|
315
|
+
|
316
|
+
To make all this easier, `Subjoin::Resource` provides a `rels` method that does all this under the hood:
|
317
|
+
|
318
|
+
article.rels.keys
|
319
|
+
=> ["author", "comments"]
|
320
|
+
author = article.rels["author"] # Returns the author Resource
|
321
|
+
author["twitter"]
|
322
|
+
=> "dgeb"
|
323
|
+
|
324
|
+
### Meta Information
|
325
|
+
|
326
|
+
[Meta information](http://jsonapi.org/format/#document-meta) is represented by
|
327
|
+
```Subjoin::Meta``` objects. Any object that might have meta information will
|
328
|
+
have a ```#meta``` attribute. ```Meta``` object attributes are accessible by
|
329
|
+
name like other attributes.
|
330
|
+
|
331
|
+
Given this JSON:
|
332
|
+
|
333
|
+
{
|
334
|
+
"meta": {
|
335
|
+
"copyright": "Copyright 2015 Example Corp.",
|
336
|
+
"authors": [
|
337
|
+
"Yehuda Katz",
|
338
|
+
"Steve Klabnik",
|
339
|
+
"Dan Gebhardt",
|
340
|
+
"Tyler Kellen"
|
341
|
+
]
|
342
|
+
},
|
343
|
+
"data": {
|
344
|
+
// ...
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
The data might be accessed in this way:
|
349
|
+
|
350
|
+
article.meta # Meta object
|
351
|
+
article.meta.copyright # "Copyright 2015 Example Corp."
|
352
|
+
|
353
|
+
## Using Inheritance
|
354
|
+
|
355
|
+
Another way to use Subjoin is via inheritance. Using this approach you
|
356
|
+
create your own classes to represent JSON-API resource types of a
|
357
|
+
specific JSON-API server implementation. These classes must be
|
358
|
+
sub-classes of `Subjoin::Resource` and must include
|
359
|
+
`Subjoin::Inheritable`, which adds some constants and methods that
|
360
|
+
`Subjoin::Document` will use to instantiate objects correctly. Next
|
361
|
+
you must override a class variable, `ROOT_URI`, which should be the
|
362
|
+
root of all URIs of the API. For instance, in the examples above,
|
363
|
+
"http://example.com" would be the value of `ROOT_URI`. By default,
|
364
|
+
Subjoin will use the lower-cased name of the class as the type in
|
365
|
+
URIs. If the class name does not match the type, you can further
|
366
|
+
override `TYPE_PATH` to indicate the name (or longer URI fragment)
|
367
|
+
that should be used in URIs to request the resource type.
|
368
|
+
|
369
|
+
Your custom classes must also be part of the ```Subjoin``` module. You
|
370
|
+
should probably create one sub-class of `Subjoin::Resource` that
|
371
|
+
overrides `ROOT_URI`, and then create other classes as sub-classes of
|
372
|
+
this:
|
373
|
+
|
374
|
+
require "subjoin"
|
375
|
+
|
376
|
+
module Subjoin
|
377
|
+
# Use this class as the parent of further subclasses.
|
378
|
+
# They will inherit the ROOT_URI defined here
|
379
|
+
class ExampleResource < Subjoin::Resource
|
380
|
+
include Inheritable
|
381
|
+
ROOT_URI="http://example.com"
|
382
|
+
end
|
383
|
+
|
384
|
+
# Subjoin will make requests to http://example.com/articles
|
385
|
+
class Articles < ExampleResource
|
386
|
+
end
|
387
|
+
|
388
|
+
# Use TYPE_PATH if you don't want to name the class the same thing as
|
389
|
+
# the type
|
390
|
+
class ArticleComments < ExampleResource
|
391
|
+
TYPE_PATH="comments"
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
Now, when you get a document, the resources in it will be mapped to an available type:
|
396
|
+
|
397
|
+
doc = Subjoin::Document.new(URI("http://example.com/articles/1", {"include" => ["author" ,"comments"]}))
|
398
|
+
|
399
|
+
# We mapped the article type to the Article class
|
400
|
+
article = doc.data.first
|
401
|
+
article.class
|
402
|
+
=> Subjoin::Article
|
403
|
+
|
404
|
+
# We mapped the comment type to the ArticleComment class
|
405
|
+
comment = article.rels["comments"].first
|
406
|
+
comment.class
|
407
|
+
=> Subjoin::ArticleComment
|
408
|
+
|
409
|
+
# We didn't map the person type to anything, so we get a Resource
|
410
|
+
author = article.rels["author"].first
|
411
|
+
author.class
|
412
|
+
=> Subjoin::Resource
|
413
|
+
|
414
|
+
## Limitations
|
415
|
+
|
416
|
+
Subjoin currently only supports GET requests.
|
417
|
+
|
418
|
+
Some features, such as pagination, should work generically but could
|
419
|
+
have more convenient methods to handle them.
|
420
|
+
|
421
|
+
## Why is it called "Subjoin"
|
422
|
+
|
423
|
+
Nice word. Sounds coder-y. Has most of the letters of "Ruby JSON-API".
|
424
|
+
|
425
|
+
## Contributing
|
426
|
+
|
427
|
+
1. Fork it ( https://github.com/seanredmond/subjoin/fork )
|
428
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
429
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
430
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
431
|
+
5. Create a new Pull Request
|