api-model 0.1.2 → 0.1.3

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: 820bf511fd4b03fc1a8d9523717d6f5a880f4ed5
4
- data.tar.gz: c412f230bde85508e50b9ccb4615b79522b8d70e
3
+ metadata.gz: b46c6c4b3e683a5e7c5a3577611b72fb7b398e8e
4
+ data.tar.gz: 89a47c86aecc1c2b66e1566511b2939335d2e385
5
5
  SHA512:
6
- metadata.gz: 4300025629a98a9c70f6c8f81cb9b0311f5a439256bdf0a5a68d3ba0595fc67049af6e7fb17add9452b5cbb875feb221b755aa690764186ce28f00c8c79d46a9
7
- data.tar.gz: fbf370237c20cbc647435cf72feb51d5732cc9bf4f78aaa67dfebf247d7798bba4cd72c56e527ab994e1c73e5862d9ea9e99f6fbb570220bee1753935f915cf0
6
+ metadata.gz: dab983c5d688a24d9916f7a2a73073a3b63e59d8cae7296e3b4eb554081f031f03b375690768258507fb1d07c7ceacb7779cd3f3a50ca780b87866627eb2c804
7
+ data.tar.gz: fb188b0fed0aeb683e9c9c3e84fe979e79d0045c766e81b115c69bbf03c951ca396289955154e5de92ab17d8b4f31831a7a2ef2f280ae8b23b1226ed0309d6e8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- api-model (0.1.2)
4
+ api-model (0.1.3)
5
5
  activemodel
6
6
  activesupport
7
7
  hashie
@@ -35,7 +35,7 @@ GEM
35
35
  method_source (0.8.2)
36
36
  mime-types (1.25.1)
37
37
  minitest (4.7.5)
38
- multi_json (1.8.2)
38
+ multi_json (1.8.4)
39
39
  pry (0.9.12.2)
40
40
  coderay (~> 1.0.5)
41
41
  method_source (~> 0.8)
data/README.md CHANGED
@@ -143,7 +143,7 @@ configuration options may not be available on the per-api call technique).
143
143
 
144
144
  ```ruby
145
145
  ApiModel::Base.api_config do |config|
146
- config.api_host = "http:://someserver.com"
146
+ config.host = "http:://someserver.com"
147
147
  end
148
148
  ```
149
149
 
@@ -189,17 +189,19 @@ an API which returns something other than JSON, you can set custom parsers to de
189
189
  before they are sent to builder classes. The parser should work in the same way as a custom builder, except it needs
190
190
  to respond to `#parse`, with the raw response body as an argument.
191
191
 
192
- ### Raise on not found or unauthenticated
192
+ ### Raising exceptions
193
193
 
194
194
  ```ruby
195
195
  ApiModel::Base.api_config do |config|
196
196
  config.raise_on_not_found = true
197
197
  config.raise_on_unauthenticated = true
198
+ config.raise_on_server_error = true
198
199
  end
199
200
  ```
200
201
 
201
- This will cause any API requests which return a 404 status to raise an ApiModel::NotFoundError exception, and requests
202
- which return a 401 to raise an ApiModel::UnauthenticatedError exception. Both default to `false`.
202
+ This will cause any API requests which return a 404 status to raise an ApiModel::NotFoundError exception,
203
+ requests which return 500 to raise an ApiModel::ServerError exception, and requests which return a 401
204
+ to raise an ApiModel::UnauthenticatedError exception. All default to `false`.
203
205
 
204
206
  ### Cache strategy & settings
205
207
 
data/api-model.gemspec CHANGED
@@ -2,7 +2,7 @@ $:.push File.expand_path("../lib", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "api-model"
5
- s.version = "0.1.2"
5
+ s.version = "0.1.3"
6
6
  s.authors = ["Damien Timewell"]
7
7
  s.email = ["mail@damientimewell.com"]
8
8
  s.homepage = "https://github.com/iZettle/api-model"
data/lib/api-model.rb CHANGED
@@ -6,6 +6,7 @@ require 'hashie'
6
6
  require 'typhoeus'
7
7
  require 'ostruct'
8
8
 
9
+ require 'api_model/assignment'
9
10
  require 'api_model/initializer'
10
11
  require 'api_model/http_request'
11
12
  require 'api_model/response'
@@ -22,6 +23,7 @@ module ApiModel
22
23
  class ResponseBuilderError < StandardError; end
23
24
  class UnauthenticatedError < StandardError; end
24
25
  class NotFoundError < StandardError; end
26
+ class ServerError < StandardError; end
25
27
 
26
28
  if defined?(Rails)
27
29
  class Railtie < Rails::Railtie
@@ -40,6 +42,7 @@ module ApiModel
40
42
  extend ActiveModel::Callbacks
41
43
 
42
44
  extend ClassMethods
45
+ include Assignment
43
46
  include ConfigurationMethods
44
47
  include InstanceMethods
45
48
  end
@@ -0,0 +1,20 @@
1
+ module ApiModel
2
+ module Assignment
3
+
4
+ # Convenience method to change attributes on an instance en-masse using a hash. This is
5
+ # useful for when an api response includes changed attributes and you want to update the current
6
+ # instance with the changes.
7
+ def update_attributes(values={})
8
+ return unless values.present?
9
+
10
+ values.each do |key,value|
11
+ begin
12
+ public_send "#{key}=", value
13
+ rescue
14
+ Log.debug "Could not set #{key} on #{self.class.name}"
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -3,7 +3,7 @@ module ApiModel
3
3
  include Initializer
4
4
 
5
5
  attr_accessor :host, :json_root, :headers, :raise_on_unauthenticated, :cache_settings,
6
- :raise_on_not_found, :cache_strategy, :parser, :builder
6
+ :raise_on_not_found, :cache_strategy, :parser, :builder, :raise_on_server_error
7
7
 
8
8
  def self.from_inherited_config(config)
9
9
  new config.instance_values.reject {|k,v| v.blank? }
@@ -1,6 +1,6 @@
1
1
  module ApiModel
2
2
  class HttpRequest
3
- include ApiModel::Initializer
3
+ include Initializer
4
4
 
5
5
  attr_accessor :path, :method, :options, :api_call, :builder, :config, :cache_id
6
6
 
@@ -14,6 +14,7 @@ module ApiModel
14
14
 
15
15
  def run
16
16
  run_callbacks :run do
17
+ Log.debug "#{method.to_s.upcase} #{full_path} #{options}"
17
18
  self.api_call = Typhoeus.send method, full_path, options
18
19
  Response.new self, config
19
20
  end
@@ -1,5 +1,6 @@
1
1
  module ApiModel
2
2
  module Initializer
3
+ include ApiModel::Assignment
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  included do
@@ -13,17 +14,5 @@ module ApiModel
13
14
  end
14
15
  end
15
16
 
16
- def update_attributes(values={})
17
- return unless values.present?
18
-
19
- values.each do |key,value|
20
- begin
21
- public_send "#{key}=", value
22
- rescue
23
- Log.debug "Could not set #{key} on #{self.class.name}"
24
- end
25
- end
26
- end
27
-
28
17
  end
29
18
  end
@@ -30,21 +30,6 @@ module ApiModel
30
30
  end
31
31
  end
32
32
 
33
- # Convenience method to change attributes on an instance en-masse using a hash. This is
34
- # useful for when an api response includes changed attributes and you want to update the current
35
- # instance with the changes.
36
- def update_attributes_from_hash(values={})
37
- return unless values.present?
38
-
39
- values.each do |key,value|
40
- begin
41
- public_send "#{key}=", value
42
- rescue
43
- Log.debug "Could not set #{key} on #{self.class.name}"
44
- end
45
- end
46
- end
47
-
48
33
  # Sends a request to the api to update a resource. If the response was successful, then it will
49
34
  # update the instance with any changes which the API has returned. If not, it will set ActiveModel
50
35
  # errors.
@@ -68,7 +53,7 @@ module ApiModel
68
53
 
69
54
  if response_success
70
55
  run_callbacks :successful_save do
71
- update_attributes_from_hash response.response_body
56
+ update_attributes response.response_body
72
57
  end
73
58
  else
74
59
  run_callbacks :unsuccessful_save do
@@ -21,6 +21,7 @@ module ApiModel
21
21
  def build_objects
22
22
  raise UnauthenticatedError if @_config.raise_on_unauthenticated && http_response.api_call.response_code == 401
23
23
  raise NotFoundError if @_config.raise_on_not_found && http_response.api_call.response_code == 404
24
+ raise ServerError if @_config.raise_on_server_error && http_response.api_call.response_code == 500
24
25
  return if response_body.nil?
25
26
 
26
27
  if response_build_hash.is_a? Array
@@ -44,6 +45,10 @@ module ApiModel
44
45
  @response_body ||= @_config.parser.parse http_response.api_call.body
45
46
  end
46
47
 
48
+ def successful?
49
+ http_response.api_call.success?
50
+ end
51
+
47
52
  # Define common methods which should never be called on this abstract class, and should always be
48
53
  # passed down to the #objects
49
54
  FALL_THROUGH_METHODS.each do |transparent_method|
@@ -121,9 +121,7 @@ describe ApiModel do
121
121
  end
122
122
 
123
123
  describe "with a single object which has properties which are undefined" do
124
- let :new_car do
125
- VCR.use_cassette('cars') { Car.get_json "http://cars.com/new_model" }
126
- end
124
+ let(:new_car) { VCR.use_cassette('cars') { Car.get_json "http://cars.com/new_model" } }
127
125
 
128
126
  it "should not raise an exception" do
129
127
  expect {
@@ -164,19 +162,19 @@ describe ApiModel do
164
162
  it 'should change an existing attribute' do
165
163
  car.name = "Chevvy"
166
164
  expect {
167
- car.update_attributes_from_hash name: "Ford"
165
+ car.update_attributes name: "Ford"
168
166
  }.to change{ car.name }.from("Chevvy").to("Ford")
169
167
  end
170
168
 
171
169
  it 'should set an attribute if unset' do
172
170
  expect {
173
- car.update_attributes_from_hash number_of_doors: 2
171
+ car.update_attributes number_of_doors: 2
174
172
  }.to change{ car.number_of_doors }.from(nil).to(2)
175
173
  end
176
174
 
177
175
  it 'should log if the attribute is not defined' do
178
176
  ApiModel::Log.should_receive(:debug).with "Could not set age on Car"
179
- car.update_attributes_from_hash age: 2
177
+ car.update_attributes age: 2
180
178
  end
181
179
  end
182
180
 
@@ -201,8 +199,8 @@ describe ApiModel do
201
199
  VCR.use_cassette('posts') { blog_post.save "/post/2", name: "foobarbaz" }
202
200
  end
203
201
 
204
- it 'should use #update_attributes_from_hash using the response body to update the instance' do
205
- blog_post.should_receive(:update_attributes_from_hash).with "name" => "foobarbaz"
202
+ it 'should use #update_attributes using the response body to update the instance' do
203
+ blog_post.should_receive(:update_attributes).with "name" => "foobarbaz"
206
204
  VCR.use_cassette('posts') { blog_post.save "/post/2", name: "foobarbaz" }
207
205
  end
208
206
 
@@ -247,4 +245,18 @@ describe ApiModel do
247
245
  end
248
246
  end
249
247
 
248
+ describe "successful?" do
249
+ let(:new_car) { VCR.use_cassette('cars') { Car.get_json "http://cars.com/new_model" } }
250
+
251
+ it 'should be true if the api call was successful' do
252
+ new_car.stub_chain(:http_response, :api_call, :success?).and_return true
253
+ new_car.successful?.should be_true
254
+ end
255
+
256
+ it 'should be false if the api call was not successful' do
257
+ new_car.stub_chain(:http_response, :api_call, :success?).and_return false
258
+ new_car.successful?.should be_false
259
+ end
260
+ end
261
+
250
262
  end
@@ -169,6 +169,28 @@ describe ApiModel::Response do
169
169
  }.to_not raise_error
170
170
  end
171
171
  end
172
+
173
+ describe "for requests which return a 500" do
174
+ let :api_request do
175
+ VCR.use_cassette('errors') do
176
+ BlogPost.get_json "http://api-model-specs.com/server_error"
177
+ end
178
+ end
179
+
180
+ it 'should raise an ApiModel::ServerError if raise_on_server_error is true' do
181
+ BlogPost.api_config { |c| c.raise_on_server_error = true }
182
+ expect {
183
+ api_request
184
+ }.to raise_error(ApiModel::ServerError)
185
+ end
186
+
187
+ it 'should not raise an ApiModel::ServerError if raise_on_server_error is false' do
188
+ BlogPost.api_config { |c| c.raise_on_server_error = false }
189
+ expect {
190
+ api_request
191
+ }.to_not raise_error
192
+ end
193
+ end
172
194
  end
173
195
 
174
196
  end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,10 @@ VCR.configure do |c|
10
10
  c.hook_into :webmock # or :fakeweb
11
11
  end
12
12
 
13
+ # Disable STDOUT logging during tests
14
+ ApiModel.send :remove_const, :Log
15
+ ApiModel::Log = Logger.new('/dev/null')
16
+
13
17
  RSpec.configure do |config|
14
18
 
15
19
  # Reset any config changes after each spec
@@ -54,4 +54,31 @@ http_interactions:
54
54
  http_version:
55
55
  recorded_at: Thu, 28 Nov 2013 16:02:20 GMT
56
56
 
57
+ - request:
58
+ method: get
59
+ uri: http://api-model-specs.com/server_error
60
+ headers:
61
+ User-Agent:
62
+ - Typhoeus - https://github.com/typhoeus/typhoeus
63
+ response:
64
+ status:
65
+ code: 500
66
+ message: OK
67
+ headers:
68
+ Server:
69
+ - nginx/1.4.1
70
+ Date:
71
+ - Thu, 28 Nov 2013 16:02:56 GMT
72
+ Content-Type:
73
+ - text/plain; charset=utf-8
74
+ Content-Length:
75
+ - '248'
76
+ Connection:
77
+ - keep-alive
78
+ body:
79
+ encoding: UTF-8
80
+ string: "Oh no, something went wrong"
81
+ http_version:
82
+ recorded_at: Thu, 28 Nov 2013 16:02:20 GMT
83
+
57
84
  recorded_with: VCR 2.8.0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damien Timewell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-10 00:00:00.000000000 Z
11
+ date: 2014-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -139,6 +139,7 @@ files:
139
139
  - README.md
140
140
  - api-model.gemspec
141
141
  - lib/api-model.rb
142
+ - lib/api_model/assignment.rb
142
143
  - lib/api_model/builder/hash.rb
143
144
  - lib/api_model/cache_stategy/no_cache.rb
144
145
  - lib/api_model/class_methods.rb