json_api_client 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8321eeb175cf8813d29558dd026494b395e46de2
4
- data.tar.gz: f43c277cea007075b8a2e50950a03e6828dd78ac
3
+ metadata.gz: 27bde5e4eec74b2589b7ec2c121e799d40defbc9
4
+ data.tar.gz: 8a25b071e84fd39f17e0044eda38eff1107d75bb
5
5
  SHA512:
6
- metadata.gz: c2a4359579478dd853e4cf2c487385cdae6da8d7bb6e89f24fbdd26a67a241d5fa2cc0d5c76de7bf7f7a9b594063a772ae0dd7dc65639a97794f630b488d3468
7
- data.tar.gz: da0d908b8db521d6a3f2b02834ce8c0a9f3056774c4d1e400ef1d018f9af95f516f683aab8abf1c41a07011c207debf444748b883b397b7405febc8038d639a1
6
+ metadata.gz: 86f7e70883d0521db847055f539cc8adff437f375f76a113b6d7abe5f960f6b50b82edee08a789886e0f34aa7dc9a1d9a8f5657d1a342d97bb35427f2403196e
7
+ data.tar.gz: 8f7d8fc7e34e175bb7c3c5cf230d0bf00995bfbc07cb09d29890262f738b3b205cc45359ba80dcc8f04620b7f430c7c1d72beadf9dd4241833bf02850b340e89
data/README.md CHANGED
@@ -8,9 +8,9 @@ This gem is meant to help you build an API client for interacting with REST APIs
8
8
 
9
9
  You will want to create your own resource classes that inherit from `JsonApiClient::Resource` similar to how you would create an `ActiveRecord` class. You may also want to create your own abstract base class to share common behavior. Additionally, you will probably want to namespace your models. Namespacing your model will not affect the url routing to that resource.
10
10
 
11
- ```
11
+ ```ruby
12
12
  module MyApi
13
- # this is an "abstract" base class that
13
+ # this is an "abstract" base class that
14
14
  class Base < JsonApiClient::Resource
15
15
  # set the api base url in an abstract base class
16
16
  self.site = "http://example.com/"
@@ -31,7 +31,7 @@ By convention, we figure guess the resource route from the class name. In the ab
31
31
 
32
32
  Some basic example usage:
33
33
 
34
- ```
34
+ ```ruby
35
35
  MyApi::Article.all
36
36
  MyApi::Article.where(author_id: 1).find(2)
37
37
  MyApi::Article.where(author_id: 1).all
@@ -62,33 +62,35 @@ All class level finders/creators should return a `JsonApiClient::ResultSet` whic
62
62
 
63
63
  Out of the box, `json_api_client` handles server side validation only.
64
64
 
65
- ```
65
+ ```ruby
66
66
  User.create(name: "Bob", email_address: "invalid email")
67
- => false
67
+ # => false
68
68
 
69
69
  user = User.new(name: "Bob", email_address: "invalid email")
70
70
  user.save
71
- => false
71
+ # => false
72
72
 
73
73
  # returns an error collector which is array-like
74
74
  user.errors
75
- => ["Email address is invalid"]
75
+ # => ["Email address is invalid"]
76
76
 
77
77
  # get all error titles
78
78
  user.errors.full_messages
79
- => ["Email address is invalid"]
79
+ # => ["Email address is invalid"]
80
80
 
81
81
  # get errors for a specific parameter
82
82
  user.errors[:email_address]
83
- => ["Email address is invalid"]
83
+ # => ["Email address is invalid"]
84
84
 
85
85
  user = User.find(1)
86
86
  user.update_attributes(email_address: "invalid email")
87
- => false
87
+ # => false
88
+
88
89
  user.errors
89
- => ["Email address is invalid"]
90
+ # => ["Email address is invalid"]
91
+
90
92
  user.email_address
91
- => "invalid email"
93
+ # => "invalid email"
92
94
  ```
93
95
 
94
96
  For now we are assuming that error sources are all parameters.
@@ -101,7 +103,7 @@ If you want to add client side validation, I suggest creating a form model class
101
103
 
102
104
  If the response has a top level meta data section, we can access it via the `meta` accessor on `ResultSet`.
103
105
 
104
- ```
106
+ ```ruby
105
107
  # Example response:
106
108
  {
107
109
  "meta": {
@@ -119,9 +121,10 @@ If the response has a top level meta data section, we can access it via the `met
119
121
  articles = Articles.all
120
122
 
121
123
  articles.meta.copyright
122
- => "Copyright 2015 Example Corp."
124
+ # => "Copyright 2015 Example Corp."
125
+
123
126
  articles.meta.authors
124
- => ["Yehuda Katz", "Steve Klabnik", "Dan Gebhardt"]
127
+ # => ["Yehuda Katz", "Steve Klabnik", "Dan Gebhardt"]
125
128
  ```
126
129
 
127
130
  ## Top-level Links
@@ -130,7 +133,7 @@ articles.meta.authors
130
133
 
131
134
  If the resource returns top level links, we can access them via the `links` accessor on `ResultSet`.
132
135
 
133
- ```
136
+ ```ruby
134
137
  articles = Articles.find(1)
135
138
  articles.links.related
136
139
  ```
@@ -141,41 +144,40 @@ You can force nested resource paths for your models by using a `belongs_to` asso
141
144
 
142
145
  **Note: Using belongs_to is only necessary for setting a nested path.**
143
146
 
144
- ```
147
+ ```ruby
145
148
  module MyApi
146
149
  class Account < JsonApiClient::Resource
147
- belongs_to :user
150
+ belongs_to :user
148
151
  end
149
152
  end
150
153
 
151
154
  # try to find without the nested parameter
152
155
  MyApi::Account.find(1)
153
- => raises ArgumentError
156
+ # => raises ArgumentError
154
157
 
155
158
  # makes request to /users/2/accounts/1
156
159
  MyApi::Account.where(user_id: 2).find(1)
157
- => returns ResultSet
160
+ # => returns ResultSet
158
161
  ```
159
162
 
160
163
  ## Custom Methods
161
164
 
162
165
  You can create custom methods on both collections (class method) and members (instance methods).
163
166
 
164
- ```
167
+ ```ruby
165
168
  module MyApi
166
169
  class User < JsonApiClient::Resource
170
+ # GET /users/search
171
+ custom_endpoint :search, on: :collection, request_method: :get
167
172
 
168
- # GET /users/search
169
- custom_endpoint :search, on: :collection, request_method: :get
170
-
171
- # PUT /users/:id/verify
172
- custom_endpoint :verify, on: :member, request_method: :put
173
+ # PUT /users/:id/verify
174
+ custom_endpoint :verify, on: :member, request_method: :put
173
175
  end
174
176
  end
175
177
 
176
178
  # makes GET request to /users/search?name=Jeff
177
179
  MyApi::User.search(name: 'Jeff')
178
- => <ResultSet of MyApi::User instances>
180
+ # => <ResultSet of MyApi::User instances>
179
181
 
180
182
  user = MyApi::User.find(1)
181
183
  # makes PUT request to /users/1/verify?foo=bar
@@ -188,7 +190,7 @@ user.verify(foo: 'bar')
188
190
 
189
191
  If the response returns a [compound document](http://jsonapi.org/format/#document-structure-compound-documents), then we should be able to get the related resources.
190
192
 
191
- ```
193
+ ```ruby
192
194
  # makes request to /articles/1?include=author,comments.author
193
195
  results = Article.includes(:author, :comments => :author).find(1)
194
196
 
@@ -200,24 +202,24 @@ authors = results.map(&:author)
200
202
 
201
203
  [See specification](http://jsonapi.org/format/#fetching-sparse-fieldsets)
202
204
 
203
- ```
205
+ ```ruby
204
206
  # makes request to /articles?fields[articles]=title,body
205
207
  article = Article.select("title,body").first
206
208
 
207
209
  # should have fetched the requested fields
208
210
  article.title
209
- => "Rails is Omakase"
211
+ # => "Rails is Omakase"
210
212
 
211
213
  # should not have returned the created_at
212
214
  article.created_at
213
- => raise NoMethodError
215
+ # => raise NoMethodError
214
216
  ```
215
217
 
216
218
  ## Sorting
217
219
 
218
220
  [See specification](http://jsonapi.org/format/#fetching-sorting)
219
221
 
220
- ```
222
+ ```ruby
221
223
  # makes request to /people?sort=age
222
224
  youngest = Person.sort(:age).all
223
225
 
@@ -234,7 +236,7 @@ oldest = Person.sort(age: :desc).all
234
236
 
235
237
  ### Requesting
236
238
 
237
- ```
239
+ ```ruby
238
240
  # makes request to /articles?page=2&per_page=30
239
241
  articles = Article.page(2).per(30).to_a
240
242
 
@@ -248,7 +250,7 @@ articles = Article.paginate(page: 2, per_page: 30).to_a
248
250
 
249
251
  If the response contains additional pagination links, you can also get at those:
250
252
 
251
- ```
253
+ ```ruby
252
254
  articles = Article.paginate(page: 2, per_page: 30).to_a
253
255
  articles.pages.next
254
256
  articles.pages.last
@@ -262,7 +264,7 @@ A `JsonApiClient::ResultSet` object should be paginatable with both `kaminari` a
262
264
 
263
265
  [See specifiation](http://jsonapi.org/format/#fetching-filtering)
264
266
 
265
- ```
267
+ ```ruby
266
268
  # makes request to /people?filter[name]=Jeff
267
269
  Person.where(name: 'Jeff').all
268
270
  ```
@@ -277,7 +279,7 @@ The added benefit of declaring your schema is that you can access fields before
277
279
 
278
280
  ### Example
279
281
 
280
- ```
282
+ ```ruby
281
283
  class User < JsonApiClient::Resource
282
284
  property :name, type: :string
283
285
  property :is_admin, type: :boolean, default: false
@@ -287,18 +289,20 @@ end
287
289
 
288
290
  # default values
289
291
  u = User.new
292
+
290
293
  u.name
291
- => nil
294
+ # => nil
295
+
292
296
  u.is_admin
293
- => false
297
+ # => false
298
+
294
299
  u.points_accrued
295
- => 0
300
+ # => 0
296
301
 
297
302
  # casting
298
303
  u.average_points_per_day = "0.3"
299
304
  u.average_points_per_day
300
- => 0.3
301
-
305
+ # => 0.3
302
306
  ```
303
307
 
304
308
  ### Types
@@ -321,7 +325,7 @@ Note : Do not map the primary key as int.
321
325
 
322
326
  You can customize this path by changing your resource's `table_name`:
323
327
 
324
- ```
328
+ ```ruby
325
329
  module MyApi
326
330
  class SomeResource < Base
327
331
  def self.table_name
@@ -338,7 +342,7 @@ MyApi::SomeResource.all
338
342
 
339
343
  You can configure your API client to use a custom connection that implementes the `run` instance method. It should return data that your parser can handle. The default connection class wraps Faraday and lets you add middleware.
340
344
 
341
- ```
345
+ ```ruby
342
346
  class NullConnection
343
347
  def initialize(*args)
344
348
  end
@@ -352,7 +356,6 @@ end
352
356
  class CustomConnectionResource < TestResource
353
357
  self.connection_class = NullConnection
354
358
  end
355
-
356
359
  ```
357
360
 
358
361
  #### Connection Options
@@ -360,10 +363,10 @@ end
360
363
  You can configure your connection using Faraday middleware. In general, you'll want
361
364
  to do this in a base model that all your resources inherit from:
362
365
 
363
- ```
366
+ ```ruby
364
367
  MyApi::Base.connection do |connection|
365
368
  # set OAuth2 headers
366
- connection.use Faraday::Request::Oauth2, 'MYTOKEN'
369
+ connection.use FaradayMiddleware::OAuth2, 'MYTOKEN'
367
370
 
368
371
  # log responses
369
372
  connection.use Faraday::Response::Logger
@@ -382,10 +385,10 @@ end
382
385
 
383
386
  You can configure your API client to use a custom parser that implements the `parse` class method. It should return a `JsonApiClient::ResultSet` instance. You can use it by setting the parser attribute on your model:
384
387
 
385
- ```
388
+ ```ruby
386
389
  class MyCustomParser
387
390
  def self.parse(klass, response)
388
-
391
+ #
389
392
  # returns some ResultSet object
390
393
  end
391
394
  end
@@ -399,14 +402,14 @@ end
399
402
 
400
403
  You can customize how the scope builder methods map to request parameters.
401
404
 
402
- ```
405
+ ```ruby
403
406
  class MyQueryBuilder
404
407
  def def initialize(klass); end
405
408
 
406
409
  def where(conditions = {})
407
410
  end
408
411
 
409
- … add order, includes, paginate, page, first, build
412
+ # … add order, includes, paginate, page, first, build
410
413
  end
411
414
 
412
415
  class MyApi::Base < JsonApiClient::Resource
@@ -418,7 +421,7 @@ end
418
421
 
419
422
  You can customize how your resources find pagination information from the response.
420
423
 
421
- ```
424
+ ```ruby
422
425
  class MyPaginator
423
426
  def initialize(result_set, data); end
424
427
  # implement current_page, total_entries, etc
@@ -13,6 +13,9 @@ module JsonApiClient
13
13
  class AccessDenied < ClientError
14
14
  end
15
15
 
16
+ class NotAuthorized < ClientError
17
+ end
18
+
16
19
  class ConnectionError < ApiError
17
20
  end
18
21
 
@@ -11,7 +11,7 @@ module JsonApiClient
11
11
 
12
12
  return @attributes unless attrs.present?
13
13
  attrs.each do |key, value|
14
- set_attribute(key, value)
14
+ send("#{key}=", value)
15
15
  end
16
16
  end
17
17
 
@@ -57,4 +57,4 @@ module JsonApiClient
57
57
 
58
58
  end
59
59
  end
60
- end
60
+ end
@@ -20,6 +20,8 @@ module JsonApiClient
20
20
  def handle_status(code, env)
21
21
  case code
22
22
  when 200..399
23
+ when 401
24
+ raise Errors::NotAuthorized, env
23
25
  when 403
24
26
  raise Errors::AccessDenied, env
25
27
  when 404
@@ -78,7 +78,7 @@ module JsonApiClient
78
78
  #
79
79
  # @return [Connection] The connection to the json api server
80
80
  def connection(rebuild = false, &block)
81
- _build_connection(&block)
81
+ _build_connection(rebuild, &block)
82
82
  connection_object
83
83
  end
84
84
 
@@ -334,6 +334,11 @@ module JsonApiClient
334
334
  relationships.set_all_attributes_dirty if relationships
335
335
  end
336
336
 
337
+ def valid?(context = nil)
338
+ context ||= (new_record? ? :create : :update)
339
+ super(context)
340
+ end
341
+
337
342
  # Commit the current changes to the resource to the remote server.
338
343
  # If the resource was previously loaded from the server, we will
339
344
  # try to update the record. Otherwise if it's a new record, then
@@ -1,3 +1,3 @@
1
1
  module JsonApiClient
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Ching
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-13 00:00:00.000000000 Z
11
+ date: 2015-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -175,8 +175,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
175
  version: '0'
176
176
  requirements: []
177
177
  rubyforge_project:
178
- rubygems_version: 2.4.5
178
+ rubygems_version: 2.4.8
179
179
  signing_key:
180
180
  specification_version: 4
181
181
  summary: Build client libraries compliant with specification defined by jsonapi.org
182
182
  test_files: []
183
+ has_rdoc: