flexirest 1.9.11 → 1.9.16
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 +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +31 -0
- data/docs/httpparse-error-handling.md +16 -3
- data/flexirest.gemspec +1 -1
- data/lib/flexirest/attribute_parsing.rb +2 -1
- data/lib/flexirest/base_without_validation.rb +2 -1
- data/lib/flexirest/caching.rb +4 -1
- data/lib/flexirest/json_api_proxy.rb +4 -2
- data/lib/flexirest/request.rb +50 -38
- data/lib/flexirest/result_iterator.rb +4 -0
- data/lib/flexirest/version.rb +1 -1
- data/spec/lib/base_without_validation_spec.rb +14 -0
- data/spec/lib/caching_spec.rb +12 -0
- data/spec/lib/json_api_spec.rb +35 -17
- data/spec/lib/request_spec.rb +138 -17
- data/spec/spec_helper.rb +2 -2
- metadata +9 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70788d1c6cfd0e3490c50e6eec78136eb5f6e1031dd6135e943ab7a1a0367db0
|
|
4
|
+
data.tar.gz: ed5282f589dd2893fc16db20197d6109382887a6b3a5a936e2f04113c6ba70cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21b69a5820a346cbdfded7e4f0c30e79f5ff10d4f2e272d59f0163070d1e4a729ebaf95d9fe7ccbb70fc15ba952bdee741bcbb994740b40e1882d7c6a0516ba3
|
|
7
|
+
data.tar.gz: 57fc2b560629d9cf2521d4f06b3f0dcdca059a686a88f3fe7cc8ca2b4ac912bd1896074243c8a589d5989b4019acc8d0eac709dd95d1f2cd7885ac0523eac702
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.16
|
|
4
|
+
|
|
5
|
+
Bugfix:
|
|
6
|
+
|
|
7
|
+
- Cached responses were always returning as `dirty?`/`changed?` (thanks to AKRathore for the bug report).
|
|
8
|
+
|
|
9
|
+
## 1.9.15
|
|
10
|
+
|
|
11
|
+
Bugfix:
|
|
12
|
+
|
|
13
|
+
- Fix not marking unchanged attributes as dirty (thanks to Khairi Adnan for the bug report).
|
|
14
|
+
|
|
15
|
+
## 1.9.14
|
|
16
|
+
|
|
17
|
+
Bugfix:
|
|
18
|
+
|
|
19
|
+
- Remove deprecation warning for `URI.escape` on Ruby 2.7.x.
|
|
20
|
+
|
|
21
|
+
## 1.9.13
|
|
22
|
+
|
|
23
|
+
Change:
|
|
24
|
+
|
|
25
|
+
- Unified the response body to be `body` for all exceptions instead of sometimes being `body` and sometimes being `raw_response`, although both are available as aliases where they were defined before (thanks to Romain Gisiger for the PR).
|
|
26
|
+
- Adjust parsing of attributes to be done in a more unified way and lighten the CPU load (thanks to Romain Gisiger for the PR)
|
|
27
|
+
|
|
28
|
+
## 1.9.12
|
|
29
|
+
|
|
30
|
+
Bugfix:
|
|
31
|
+
|
|
32
|
+
- Prevent crash on JSONAPI invalid error response (thanks to François Ferrandis for the PR).
|
|
33
|
+
|
|
3
34
|
## 1.9.11
|
|
4
35
|
|
|
5
36
|
Bugfix:
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
# *Flexirest:* HTTP/parse error handling
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## HTTP Errors
|
|
4
|
+
|
|
5
|
+
Sometimes the backend server may respond with a non-2xx/3xx header, in which case the code will raise an `Flexirest::HTTPClientException` for 4xx errors or an `Flexirest::HTTPServerException` for 5xx errors.
|
|
6
|
+
|
|
7
|
+
These both have a `status` accessor, a `result` accessor (for getting access to the parsed body) and a `body` accessor (for getting access to the original unparsed body). However, you can make use of the `message` method (or the `to_s` method) that will build a nice error message for you (containing the URL and the HTTP method used for the request as well as the HTTP status code and the original body of the response).
|
|
4
8
|
|
|
5
9
|
```ruby
|
|
6
10
|
begin
|
|
7
11
|
Person.all
|
|
8
12
|
rescue Flexirest::HTTPClientException, Flexirest::HTTPServerException => e
|
|
9
|
-
|
|
13
|
+
# Display the HTTP status and parsed body
|
|
14
|
+
puts "Backend returned HTTP #{e.status} with following parsed body: #{e.result}"
|
|
15
|
+
|
|
16
|
+
# Display the unparsed body
|
|
17
|
+
puts "Original body is: #{e.body}"
|
|
18
|
+
|
|
19
|
+
# Using the message method, same than calling the to_s method
|
|
20
|
+
puts e.message
|
|
10
21
|
end
|
|
11
22
|
```
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
## Parse Error
|
|
25
|
+
|
|
26
|
+
If the original response is unparsable (e.g. not in the desired content type), then it will raise an `Flexirest::ResponseParseException` which has a `status` accessor for the HTTP status code and a `body` accessor for the unparsed response body.
|
|
14
27
|
|
|
15
28
|
-----
|
|
16
29
|
|
data/flexirest.gemspec
CHANGED
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.add_development_dependency "simplecov"
|
|
37
37
|
spec.add_development_dependency "simplecov-rcov"
|
|
38
38
|
spec.add_development_dependency 'coveralls'
|
|
39
|
-
spec.add_development_dependency "api-auth", ">= 1.3.1"
|
|
39
|
+
spec.add_development_dependency "api-auth", ">= 1.3.1", "< 2.4"
|
|
40
40
|
spec.add_development_dependency 'typhoeus'
|
|
41
41
|
spec.add_development_dependency 'activemodel'
|
|
42
42
|
|
|
@@ -3,7 +3,8 @@ module Flexirest
|
|
|
3
3
|
private
|
|
4
4
|
|
|
5
5
|
def parse_attribute_value(v)
|
|
6
|
-
return v if v.is_a?(Date) || v.is_a?(DateTime)
|
|
6
|
+
return v if v.is_a?(Date) || v.is_a?(DateTime) ||
|
|
7
|
+
v.kind_of?(NilClass) || v.kind_of?(TrueClass) || v.kind_of?(FalseClass) || v.kind_of?(Numeric)
|
|
7
8
|
|
|
8
9
|
if v.to_s[(/\A(((19|20)\d\d[- \/.](0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9]))|((0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9])[- \/.](19|20)\d\d))\Z/)]
|
|
9
10
|
Date.parse(v) rescue v
|
|
@@ -41,6 +41,7 @@ module Flexirest
|
|
|
41
41
|
def _copy_from(result)
|
|
42
42
|
@attributes = result._attributes
|
|
43
43
|
@_status = result._status
|
|
44
|
+
_clean!
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def dirty?
|
|
@@ -189,7 +190,7 @@ module Flexirest
|
|
|
189
190
|
old_value = @dirty_attributes[key.to_sym]
|
|
190
191
|
old_value = @attributes[key.to_sym] unless old_value
|
|
191
192
|
old_value = old_value[0] if old_value and old_value.is_a? Array
|
|
192
|
-
@dirty_attributes[key.to_sym] = [old_value, value]
|
|
193
|
+
@dirty_attributes[key.to_sym] = [old_value, value] if old_value != value
|
|
193
194
|
@attributes[key.to_sym] = value
|
|
194
195
|
end
|
|
195
196
|
|
data/lib/flexirest/caching.rb
CHANGED
|
@@ -110,9 +110,12 @@ module Flexirest
|
|
|
110
110
|
if @result.is_a?(Array)
|
|
111
111
|
ri = ResultIterator.new(self)
|
|
112
112
|
ri.items = @result.map{|i| @class_name.constantize.new(i)}
|
|
113
|
+
ri._clean!
|
|
113
114
|
ri
|
|
114
115
|
else
|
|
115
|
-
@class_name.constantize.new(@result)
|
|
116
|
+
obj = @class_name.constantize.new(@result)
|
|
117
|
+
obj._clean!
|
|
118
|
+
obj
|
|
116
119
|
end
|
|
117
120
|
end
|
|
118
121
|
end
|
|
@@ -196,8 +196,10 @@ module Flexirest
|
|
|
196
196
|
# Save resource class for building lazy association loaders
|
|
197
197
|
save_resource_class(object)
|
|
198
198
|
|
|
199
|
-
#
|
|
200
|
-
|
|
199
|
+
# According to the spec:
|
|
200
|
+
# "The members data and errors MUST NOT coexist in the same document."
|
|
201
|
+
# Thus, if the "errors" key is present, we can return it and ignore the "data" key.
|
|
202
|
+
return body['errors'] if body.include?('errors')
|
|
201
203
|
|
|
202
204
|
# return early if data is an empty array
|
|
203
205
|
return [] if body['data'] == []
|
data/lib/flexirest/request.rb
CHANGED
|
@@ -380,7 +380,7 @@ module Flexirest
|
|
|
380
380
|
if target.to_s.blank?
|
|
381
381
|
missing << token
|
|
382
382
|
end
|
|
383
|
-
@url.gsub!(":#{token}", URI.
|
|
383
|
+
@url.gsub!(":#{token}", URI.encode_www_form_component(target.to_s))
|
|
384
384
|
end
|
|
385
385
|
end
|
|
386
386
|
|
|
@@ -656,40 +656,52 @@ module Flexirest
|
|
|
656
656
|
k = k.to_sym
|
|
657
657
|
end
|
|
658
658
|
overridden_name = select_name(k, overridden_name)
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
659
|
+
set_corresponding_value(v, k, object, overridden_name)
|
|
660
|
+
end
|
|
661
|
+
object.clean! unless object_is_class?
|
|
662
|
+
|
|
663
|
+
object
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
def set_corresponding_value(value, key = nil, object = nil, overridden_name = nil)
|
|
667
|
+
optional_args = [key, object, overridden_name]
|
|
668
|
+
value_from_object = optional_args.all? # trying to parse a JSON Hash value
|
|
669
|
+
value_from_other_type = optional_args.none? # trying to parse anything else
|
|
670
|
+
raise Flexirest::InvalidArgumentsException.new("Optional args need all to be filled or none") unless value_from_object || value_from_other_type
|
|
671
|
+
k = key || :key
|
|
672
|
+
v = value
|
|
673
|
+
assignable_hash = value_from_object ? object._attributes : {}
|
|
674
|
+
if value_from_object && @method[:options][:lazy].include?(k)
|
|
675
|
+
assignable_hash[k] = Flexirest::LazyAssociationLoader.new(overridden_name, v, self, overridden_name:(overridden_name))
|
|
676
|
+
elsif v.is_a? Hash
|
|
677
|
+
assignable_hash[k] = new_object(v, overridden_name )
|
|
678
|
+
elsif v.is_a? Array
|
|
679
|
+
if @method[:options][:array].include?(k)
|
|
680
|
+
assignable_hash[k] = Array.new
|
|
676
681
|
else
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
object._attributes[k] = v
|
|
683
|
-
elsif Flexirest::Base.disable_automatic_date_parsing
|
|
684
|
-
object._attributes[k] = v
|
|
682
|
+
assignable_hash[k] = Flexirest::ResultIterator.new
|
|
683
|
+
end
|
|
684
|
+
v.each do |item|
|
|
685
|
+
if item.is_a? Hash
|
|
686
|
+
assignable_hash[k] << new_object(item, overridden_name)
|
|
685
687
|
else
|
|
686
|
-
|
|
688
|
+
assignable_hash[k] << set_corresponding_value(item)
|
|
687
689
|
end
|
|
688
690
|
end
|
|
691
|
+
else
|
|
692
|
+
parse_fields = [ @method[:options][:parse_fields], @object._date_fields ].compact.reduce([], :|)
|
|
693
|
+
parse_fields = nil if parse_fields.empty?
|
|
694
|
+
if (parse_fields && parse_fields.include?(k))
|
|
695
|
+
assignable_hash[k] = parse_attribute_value(v)
|
|
696
|
+
elsif parse_fields
|
|
697
|
+
assignable_hash[k] = v
|
|
698
|
+
elsif Flexirest::Base.disable_automatic_date_parsing
|
|
699
|
+
assignable_hash[k] = v
|
|
700
|
+
else
|
|
701
|
+
assignable_hash[k] = parse_attribute_value(v)
|
|
702
|
+
end
|
|
689
703
|
end
|
|
690
|
-
object
|
|
691
|
-
|
|
692
|
-
object
|
|
704
|
+
value_from_object ? object : assignable_hash[k]
|
|
693
705
|
end
|
|
694
706
|
|
|
695
707
|
def hal_response?
|
|
@@ -822,12 +834,10 @@ module Flexirest
|
|
|
822
834
|
|
|
823
835
|
def add_nested_body_to_iterator(result, items)
|
|
824
836
|
items.each do |json_object|
|
|
825
|
-
if json_object.is_a?
|
|
826
|
-
iterator = ResultIterator.new
|
|
827
|
-
add_nested_body_to_iterator(iterator, json_object)
|
|
828
|
-
result << iterator
|
|
829
|
-
else
|
|
837
|
+
if json_object.is_a? Hash
|
|
830
838
|
result << new_object(json_object, @overridden_name)
|
|
839
|
+
else
|
|
840
|
+
result << set_corresponding_value(json_object)
|
|
831
841
|
end
|
|
832
842
|
end
|
|
833
843
|
end
|
|
@@ -838,6 +848,7 @@ module Flexirest
|
|
|
838
848
|
end
|
|
839
849
|
|
|
840
850
|
class RequestException < StandardError ; end
|
|
851
|
+
class InvalidArgumentsException < StandardError ; end
|
|
841
852
|
|
|
842
853
|
class InvalidRequestException < RequestException ; end
|
|
843
854
|
class MissingParametersException < RequestException ; end
|
|
@@ -851,18 +862,19 @@ module Flexirest
|
|
|
851
862
|
end
|
|
852
863
|
|
|
853
864
|
class HTTPException < RequestException
|
|
854
|
-
attr_accessor :status, :result, :request_url
|
|
865
|
+
attr_accessor :status, :result, :request_url, :body, :raw_response
|
|
855
866
|
def initialize(options)
|
|
856
867
|
@status = options[:status]
|
|
857
868
|
@result = options[:result]
|
|
858
869
|
@request_url = options[:url]
|
|
859
|
-
@
|
|
870
|
+
@body = options[:raw_response]
|
|
860
871
|
@method = options[:method]
|
|
861
872
|
end
|
|
873
|
+
alias_method :body, :raw_response
|
|
862
874
|
|
|
863
875
|
def message
|
|
864
876
|
method = @method.try(:upcase)
|
|
865
|
-
"The #{method} to '#{@request_url}' returned a #{@status} status, which raised a #{self.class.to_s} with a body of: #{@
|
|
877
|
+
"The #{method} to '#{@request_url}' returned a #{@status} status, which raised a #{self.class.to_s} with a body of: #{@body}"
|
|
866
878
|
end
|
|
867
879
|
|
|
868
880
|
def to_s
|
data/lib/flexirest/version.rb
CHANGED
|
@@ -126,6 +126,13 @@ describe Flexirest::BaseWithoutValidation do
|
|
|
126
126
|
expect(client).to be_dirty
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
it "should not mark attributes that don't change as dirty" do
|
|
130
|
+
client = EmptyExample.new(test: "Foo")
|
|
131
|
+
client._clean!
|
|
132
|
+
client.test = client.test
|
|
133
|
+
expect(client).to_not be_dirty
|
|
134
|
+
end
|
|
135
|
+
|
|
129
136
|
it "should store attribute set using []= array notation and mark them as dirty" do
|
|
130
137
|
client = EmptyExample.new()
|
|
131
138
|
client["test"] = "Something"
|
|
@@ -171,6 +178,13 @@ describe Flexirest::BaseWithoutValidation do
|
|
|
171
178
|
expect(client).to be_dirty
|
|
172
179
|
end
|
|
173
180
|
|
|
181
|
+
it "should not mark a freshly retrieved object as changed" do
|
|
182
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
|
183
|
+
client = AlteringClientExample.find(id: 1)
|
|
184
|
+
expect(client).to_not be_changed
|
|
185
|
+
expect(client.changes).to eq({})
|
|
186
|
+
end
|
|
187
|
+
|
|
174
188
|
it 'should respond_to? attributes defined in the response' do
|
|
175
189
|
client = EmptyExample.new(hello: "World")
|
|
176
190
|
expect(client.respond_to?(:hello)).to be_truthy
|
data/spec/lib/caching_spec.rb
CHANGED
|
@@ -184,6 +184,18 @@ describe Flexirest::Caching do
|
|
|
184
184
|
expect(ret.first_name).to eq("Johnny")
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
+
it "cache read objects shouldn't be marked as changed" do
|
|
188
|
+
cached_response = Flexirest::CachedResponse.new(
|
|
189
|
+
status:200,
|
|
190
|
+
result:@cached_object,
|
|
191
|
+
expires:Time.now + 30)
|
|
192
|
+
expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(Marshal.dump(cached_response))
|
|
193
|
+
expect_any_instance_of(Flexirest::Connection).not_to receive(:get)
|
|
194
|
+
ret = Person.all
|
|
195
|
+
expect(ret).to_not be_changed
|
|
196
|
+
expect(ret.changes).to eq({})
|
|
197
|
+
end
|
|
198
|
+
|
|
187
199
|
it "should read from the cache store and restore to the same object" do
|
|
188
200
|
cached_response = Flexirest::CachedResponse.new(
|
|
189
201
|
status:200,
|
data/spec/lib/json_api_spec.rb
CHANGED
|
@@ -312,28 +312,46 @@ describe 'JSON API' do
|
|
|
312
312
|
expect(subject.find_all).to be_an_instance_of(Flexirest::ResultIterator)
|
|
313
313
|
end
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
let(:response_body) do
|
|
318
|
-
{
|
|
319
|
-
errors: [
|
|
320
|
-
{
|
|
321
|
-
title: "Record not found",
|
|
322
|
-
detail: "The record identified by 123456 could not be found",
|
|
323
|
-
code: "not_found",
|
|
324
|
-
status: "404",
|
|
325
|
-
}
|
|
326
|
-
]
|
|
327
|
-
}
|
|
328
|
-
end
|
|
315
|
+
describe 'error responses' do
|
|
316
|
+
subject(:make_request) { JsonAPIExample::Article.real_find(123) }
|
|
329
317
|
|
|
330
|
-
|
|
318
|
+
before do
|
|
319
|
+
headers = { "Content-Type" => "application/vnd.api+json" }
|
|
331
320
|
expect_any_instance_of(Flexirest::Connection).
|
|
332
321
|
to receive(:get).with("/articles/123", an_instance_of(Hash)).
|
|
333
322
|
and_return(::FaradayResponseMock.new(OpenStruct.new(body: response_body.to_json, response_headers: headers, status: 404)))
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
context 'when no "data" key is present alongside the "errors" key' do
|
|
326
|
+
let(:response_body) do
|
|
327
|
+
{
|
|
328
|
+
errors: [
|
|
329
|
+
{ detail: "The record identified by 123456 could not be found", }
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it 'should raise the relevant Flexirest error' do
|
|
335
|
+
expect(-> { make_request }).to raise_error(Flexirest::HTTPNotFoundClientException) do |exception|
|
|
336
|
+
expect(exception.result.first.detail).to eq("The record identified by 123456 could not be found")
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
context 'when a "data" key is present alongside the "errors" key (although this is forbidden by the spec)' do
|
|
342
|
+
let(:response_body) do
|
|
343
|
+
{
|
|
344
|
+
errors: [
|
|
345
|
+
{ detail: "The record identified by 123456 could not be found", }
|
|
346
|
+
],
|
|
347
|
+
data: {}
|
|
348
|
+
}
|
|
349
|
+
end
|
|
334
350
|
|
|
335
|
-
|
|
336
|
-
expect(
|
|
351
|
+
it 'should ignore the "data" key and raise the relevant Flexirest error' do
|
|
352
|
+
expect(-> { make_request }).to raise_error(Flexirest::HTTPNotFoundClientException) do |exception|
|
|
353
|
+
expect(exception.result.first.detail).to eq("The record identified by 123456 could not be found")
|
|
354
|
+
end
|
|
337
355
|
end
|
|
338
356
|
end
|
|
339
357
|
end
|
data/spec/lib/request_spec.rb
CHANGED
|
@@ -31,6 +31,8 @@ describe Flexirest::Request do
|
|
|
31
31
|
get :flat, "/", params_encoder: :flat
|
|
32
32
|
get :array, "/johnny", array: [:likes, :dislikes]
|
|
33
33
|
get :babies, "/babies", has_many: {children: ExampleOtherClient}
|
|
34
|
+
get :basket, "/basket", array: [:options]
|
|
35
|
+
get :dates, "/dates", array: [:dates]
|
|
34
36
|
get :single_association, "/single", has_one: {single: ExampleSingleClient}, has_many: {children: ExampleOtherClient}
|
|
35
37
|
get :headers, "/headers"
|
|
36
38
|
get :cancel_callback, "/cancel-callback"
|
|
@@ -38,6 +40,7 @@ describe Flexirest::Request do
|
|
|
38
40
|
put :headers_json, "/headers_json", request_body_type: :json
|
|
39
41
|
get :find, "/:id", required: [:id]
|
|
40
42
|
get :find_cat, "/:id/cat"
|
|
43
|
+
get :fruits, "/fruits"
|
|
41
44
|
get :change, "/change"
|
|
42
45
|
get :plain, "/plain/:id", plain: true
|
|
43
46
|
post :create, "/create", rubify_names: true
|
|
@@ -46,11 +49,14 @@ describe Flexirest::Request do
|
|
|
46
49
|
put :update, "/put/:id"
|
|
47
50
|
put :wrapped, "/put/:id", wrap_root: "example"
|
|
48
51
|
put :conversion, "/put/:id", parse_fields: [:converted]
|
|
52
|
+
put :conversion_child, "/put/:id", parse_fields: [:converted_child]
|
|
49
53
|
delete :remove, "/remove/:id"
|
|
50
54
|
delete :remove_body, "/remove/:id", send_delete_body: true
|
|
51
55
|
get :hal, "/hal", fake:"{\"_links\":{\"child\": {\"href\": \"/child/1\"}, \"other\": {\"href\": \"/other/1\"}, \"cars\":[{\"href\": \"/car/1\", \"name\":\"car1\"}, {\"href\": \"/car/2\", \"name\":\"car2\"}, {\"href\": \"/car/not-embed\", \"name\":\"car_not_embed\"} ], \"lazy\": {\"href\": \"/lazy/load\"}, \"invalid\": [{\"href\": \"/invalid/1\"}]}, \"_embedded\":{\"other\":{\"name\":\"Jane\"},\"child\":{\"name\":\"Billy\"}, \"cars\":[{\"_links\": {\"self\": {\"href\": \"/car/1\"} }, \"make\": \"Bugatti\", \"model\": \"Veyron\"}, {\"_links\": {\"self\": {\"href\": \"/car/2\"} }, \"make\": \"Ferrari\", \"model\": \"F458 Italia\"} ], \"invalid\": [{\"present\":true, \"_links\": {} } ] } }", has_many:{other:ExampleOtherClient}
|
|
52
|
-
get :
|
|
53
|
-
get :
|
|
56
|
+
get :fake_object, "/fake", fake:"{\"result\":true, \"list\":[1,2,3,{\"test\":true}], \"child\":{\"grandchild\":{\"test\":true}}}"
|
|
57
|
+
get :fake_proc_object, "/fake", fake:->(request) { "{\"result\":#{request.get_params[:id]}}" }
|
|
58
|
+
get :fake_array, "/fake", fake:"[1,2,3,{\"test\":true},null]"
|
|
59
|
+
get :fake_proc_array, "/fake", fake:->(request) { "[{\"result\":#{request.get_params[:id]}},null]" }
|
|
54
60
|
get :defaults, "/defaults", defaults:{overwrite:"no", persist:"yes"}
|
|
55
61
|
get :requires, "/requires", requires:[:name, :age]
|
|
56
62
|
patch :only_changed_1, "/changed1", only_changed: true
|
|
@@ -143,7 +149,8 @@ describe Flexirest::Request do
|
|
|
143
149
|
class LazyLoadedExampleClient < ExampleClient
|
|
144
150
|
base_url "http://www.example.com"
|
|
145
151
|
lazy_load!
|
|
146
|
-
get :
|
|
152
|
+
get :fake_object, "/fake", fake:"{\"result\":true, \"list\":[1,2,3,{\"test\":true}], \"child\":{\"grandchild\":{\"test\":true}}}"
|
|
153
|
+
get :fake_array, "/fake", fake:"[1,2,3,{\"test\":true},{\"child\":{\"grandchild\":{\"test\":true}}}]"
|
|
147
154
|
get :lazy_test, "/does-not-matter", fake:"{\"people\":[\"http://www.example.com/some/url\"]}", lazy: [:people]
|
|
148
155
|
end
|
|
149
156
|
|
|
@@ -190,7 +197,8 @@ describe Flexirest::Request do
|
|
|
190
197
|
class WhitelistedDateClient < Flexirest::Base
|
|
191
198
|
base_url "http://www.example.com"
|
|
192
199
|
put :conversion, "/put/:id"
|
|
193
|
-
|
|
200
|
+
put :conversion_child, "/put/:id"
|
|
201
|
+
parse_date :converted, :converted_child
|
|
194
202
|
end
|
|
195
203
|
|
|
196
204
|
allow_any_instance_of(Flexirest::Request).to receive(:read_cached_response)
|
|
@@ -336,7 +344,7 @@ describe Flexirest::Request do
|
|
|
336
344
|
end
|
|
337
345
|
|
|
338
346
|
it "should pass URL-encode URL parameters" do
|
|
339
|
-
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/foo
|
|
347
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/foo+bar", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
|
|
340
348
|
ExampleClient.find id:"foo bar"
|
|
341
349
|
end
|
|
342
350
|
|
|
@@ -511,33 +519,84 @@ describe Flexirest::Request do
|
|
|
511
519
|
end
|
|
512
520
|
end
|
|
513
521
|
|
|
514
|
-
it "should only convert date times in JSON if specified" do
|
|
522
|
+
it "should only convert date times in JSON if specified when converted is root property" do
|
|
515
523
|
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", "debug=true", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"converted\":\"2012-03-04T01:02:03Z\", \"not_converted\":\"2012-03-04T01:02:03Z\"}", response_headers:{})))
|
|
516
524
|
object = ExampleClient.conversion id:1234, debug:true
|
|
517
525
|
expect(object.converted).to be_an_instance_of(DateTime)
|
|
518
526
|
expect(object.not_converted).to be_an_instance_of(String)
|
|
519
527
|
end
|
|
520
528
|
|
|
521
|
-
it "should convert date times in JSON if
|
|
529
|
+
it "should only convert date times in JSON if specified when converted is child property" do
|
|
530
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", "debug=true", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"not_converted\":\"2012-03-04T01:02:03Z\", \"child\":{\"converted_child\":\"2012-03-04T01:02:03Z\"}}", response_headers:{})))
|
|
531
|
+
object = ExampleClient.conversion_child id:1234, debug:true
|
|
532
|
+
expect(object.child.converted_child).to be_an_instance_of(DateTime)
|
|
533
|
+
expect(object.not_converted).to be_an_instance_of(String)
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
it "should convert date times in JSON if root property is whitelisted" do
|
|
522
537
|
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", "debug=true", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"converted\":\"2012-03-04T01:02:03Z\", \"not_converted\":\"2012-03-04T01:02:03Z\"}", response_headers:{})))
|
|
523
538
|
object = WhitelistedDateClient.conversion id:1234, debug:true
|
|
524
539
|
expect(object.converted).to be_an_instance_of(DateTime)
|
|
525
540
|
expect(object.not_converted).to be_an_instance_of(String)
|
|
526
541
|
end
|
|
527
542
|
|
|
528
|
-
it "should
|
|
529
|
-
|
|
543
|
+
it "should convert date times in JSON if child property is whitelisted" do
|
|
544
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", "debug=true", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"not_converted\":\"2012-03-04T01:02:03Z\", \"child\":{\"converted_child\":\"2012-03-04T01:02:03Z\"}}", response_headers:{})))
|
|
545
|
+
object = WhitelistedDateClient.conversion_child id:1234, debug:true
|
|
546
|
+
expect(object.child.converted_child).to be_an_instance_of(DateTime)
|
|
547
|
+
expect(object.not_converted).to be_an_instance_of(String)
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
it "should convert date times in JSON from a result iterator response" do
|
|
551
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/dates", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"[\"2012-03-04T01:02:03Z\", \"2012-03-04T01:02:03Z\"]", response_headers:{})))
|
|
552
|
+
object = ExampleClient.dates
|
|
553
|
+
expect(object).to be_a(Flexirest::ResultIterator)
|
|
554
|
+
expect(object.items).to be_a(Array)
|
|
555
|
+
expect(object.first).to be_an_instance_of(DateTime)
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
it "should convert date times in JSON even in a pure array" do
|
|
559
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/dates", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"dates\":[\"2012-03-04T01:02:03Z\", \"2012-03-04T01:02:03Z\"]}", response_headers:{})))
|
|
560
|
+
object = ExampleClient.dates
|
|
561
|
+
expect(object).to be_a(ExampleClient)
|
|
562
|
+
expect(object.dates).to be_a(Array)
|
|
563
|
+
expect(object.dates.first).to be_an_instance_of(DateTime)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it "should parse JSON object and return a nice object for faked responses" do
|
|
567
|
+
object = ExampleClient.fake_object id:1234, debug:true
|
|
530
568
|
expect(object.result).to eq(true)
|
|
531
569
|
expect(object.list.first).to eq(1)
|
|
532
570
|
expect(object.list.last.test).to eq(true)
|
|
533
571
|
expect(object.child.grandchild.test).to eq(true)
|
|
534
572
|
end
|
|
535
573
|
|
|
536
|
-
it "should parse JSON from a fake response generated by a proc" do
|
|
537
|
-
object = ExampleClient.
|
|
574
|
+
it "should parse JSON object from a fake response generated by a proc" do
|
|
575
|
+
object = ExampleClient.fake_proc_object id:1234
|
|
538
576
|
expect(object.result).to eq(1234)
|
|
539
577
|
end
|
|
540
578
|
|
|
579
|
+
it "should parse JSON array and return a nice result iterator for faked responses" do
|
|
580
|
+
object = ExampleClient.fake_array debug:true
|
|
581
|
+
expect(object).to be_instance_of(Flexirest::ResultIterator)
|
|
582
|
+
expect(object.size).to eq(5)
|
|
583
|
+
expect(object.first).to eq(1)
|
|
584
|
+
expect(object.last).to eq(nil)
|
|
585
|
+
expect(object[3]).to be_instance_of(ExampleClient)
|
|
586
|
+
expect(object[3].test).to eq(true)
|
|
587
|
+
expect(object._status).to eq(200)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it "should parse JSON array from a fake response generated by a proc" do
|
|
591
|
+
object = ExampleClient.fake_proc_array id:1234
|
|
592
|
+
expect(object).to be_instance_of(Flexirest::ResultIterator)
|
|
593
|
+
expect(object.size).to eq(2)
|
|
594
|
+
expect(object.first).to be_instance_of(ExampleClient)
|
|
595
|
+
expect(object.first.result).to eq(1234)
|
|
596
|
+
expect(object.last).to eq(nil)
|
|
597
|
+
expect(object._status).to eq(200)
|
|
598
|
+
end
|
|
599
|
+
|
|
541
600
|
it "should not parse JSON from a plain request" do
|
|
542
601
|
response_body = "This is another non-JSON string"
|
|
543
602
|
expect_any_instance_of(Flexirest::Connection).to receive(:get).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response_body)))
|
|
@@ -570,19 +629,36 @@ describe Flexirest::Request do
|
|
|
570
629
|
expect(ExampleClient.all).to be_truthy
|
|
571
630
|
end
|
|
572
631
|
|
|
573
|
-
it "should return a lazy loader object if lazy loading is enabled" do
|
|
574
|
-
object = LazyLoadedExampleClient.
|
|
632
|
+
it "should return a lazy loader object if lazy loading is enabled for JSON object" do
|
|
633
|
+
object = LazyLoadedExampleClient.fake_object id:1234, debug:true
|
|
575
634
|
expect(object).to be_an_instance_of(Flexirest::LazyLoader)
|
|
576
635
|
end
|
|
577
636
|
|
|
578
|
-
it "should proxy through nice object for lazy loaded responses" do
|
|
579
|
-
object = LazyLoadedExampleClient.
|
|
580
|
-
expect(object.result).to
|
|
637
|
+
it "should proxy through nice object for lazy loaded responses from JSON object" do
|
|
638
|
+
object = LazyLoadedExampleClient.fake_object id:1234, debug:true
|
|
639
|
+
expect(object.instance_variable_get(:@result)).to be(nil)
|
|
640
|
+
expect(object.result).to eq(true) # method call the attribute received in response and never the instance attribute of the LazyLoader class
|
|
641
|
+
expect(object.instance_variable_get(:@result)).to be_a(LazyLoadedExampleClient)
|
|
581
642
|
expect(object.list.first).to eq(1)
|
|
582
643
|
expect(object.list.last.test).to eq(true)
|
|
583
644
|
expect(object.child.grandchild.test).to eq(true)
|
|
584
645
|
end
|
|
585
646
|
|
|
647
|
+
it "should return a lazy loader object if lazy loading is enabled for JSON array" do
|
|
648
|
+
object = LazyLoadedExampleClient.fake_array debug:true
|
|
649
|
+
expect(object).to be_an_instance_of(Flexirest::LazyLoader)
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
it "should proxy through nice result iterator for lazy loaded responses from JSON array" do
|
|
653
|
+
object = LazyLoadedExampleClient.fake_array debug:true
|
|
654
|
+
expect(object.instance_variable_get(:@result)).to be(nil)
|
|
655
|
+
expect(object.items).to be_a(Array)
|
|
656
|
+
expect(object.instance_variable_get(:@result)).to be_a(Flexirest::ResultIterator)
|
|
657
|
+
expect(object.first).to eq(1)
|
|
658
|
+
expect(object[3].test).to eq(true)
|
|
659
|
+
expect(object.last.child.grandchild.test).to eq(true)
|
|
660
|
+
end
|
|
661
|
+
|
|
586
662
|
it "should return a LazyAssociationLoader for lazy loaded properties" do
|
|
587
663
|
object = LazyLoadedExampleClient.lazy_test
|
|
588
664
|
expect(object.people.size).to eq(1)
|
|
@@ -592,7 +668,7 @@ describe Flexirest::Request do
|
|
|
592
668
|
it "should log faked responses" do
|
|
593
669
|
allow(Flexirest::Logger).to receive(:debug)
|
|
594
670
|
expect(Flexirest::Logger).to receive(:debug).with(/Faked response found/)
|
|
595
|
-
ExampleClient.
|
|
671
|
+
ExampleClient.fake_object id:1234, debug:true
|
|
596
672
|
end
|
|
597
673
|
|
|
598
674
|
it "should parse an array within JSON to be a result iterator" do
|
|
@@ -628,6 +704,51 @@ describe Flexirest::Request do
|
|
|
628
704
|
#TODO
|
|
629
705
|
end
|
|
630
706
|
|
|
707
|
+
it "should parse an attribute to be an array if attribute included in a nested array" do
|
|
708
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/johnny", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"Johnny\", \"nested_array\":[[{\"likes\":[\"donuts\", \"bacon\"], \"dislikes\":[\"politicians\", \"lawyers\", \"taxes\"]}]]}", status:200, response_headers:{})))
|
|
709
|
+
object = ExampleClient.array
|
|
710
|
+
nested_array = object.nested_array[0][0]
|
|
711
|
+
expect(nested_array.likes).to be_instance_of(Array)
|
|
712
|
+
expect(nested_array.likes.size).to eq(2)
|
|
713
|
+
expect(nested_array.likes[0]).to eq("donuts")
|
|
714
|
+
expect(nested_array.likes[1]).to eq("bacon")
|
|
715
|
+
expect(nested_array.dislikes).to be_instance_of(Array)
|
|
716
|
+
expect(nested_array.dislikes.size).to eq(3)
|
|
717
|
+
expect(nested_array.dislikes[0]).to eq("politicians")
|
|
718
|
+
expect(nested_array.dislikes[1]).to eq("lawyers")
|
|
719
|
+
expect(nested_array.dislikes[2]).to eq("taxes")
|
|
720
|
+
#TODO - Pasted from the Test above
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
it "should parse an attribute to be either a result iterator or an array and containing simple values like integers" do
|
|
724
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/basket", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"products\":[101, 55, 37], \"options\":[854, 225, 772]}", status:200, response_headers:{})))
|
|
725
|
+
object = ExampleClient.basket
|
|
726
|
+
expect(object).to be_instance_of(ExampleClient)
|
|
727
|
+
expect(object.products).to be_a(Flexirest::ResultIterator)
|
|
728
|
+
expect(object.products.size).to eq(3)
|
|
729
|
+
expect(object.products.first).to eq(101)
|
|
730
|
+
expect(object.products[1]).to eq(55)
|
|
731
|
+
expect(object.products.last).to eq(37)
|
|
732
|
+
expect(object.options).to be_a(Array)
|
|
733
|
+
expect(object.options.size).to eq(3)
|
|
734
|
+
expect(object.options.first).to eq(854)
|
|
735
|
+
expect(object.options[1]).to eq(225)
|
|
736
|
+
expect(object.options.last).to eq(772)
|
|
737
|
+
expect(object._status).to eq(200)
|
|
738
|
+
#TODO - Pasted from the Test above
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
it "should parse the response to be a result iterator and containing simple values like strings" do
|
|
742
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/fruits", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"[\"apple\", \"banana\", \"pear\", \"watermelon\"]", status:200, response_headers:{})))
|
|
743
|
+
object = ExampleClient.fruits
|
|
744
|
+
expect(object).to be_instance_of(Flexirest::ResultIterator)
|
|
745
|
+
expect(object.first).to eq('apple')
|
|
746
|
+
expect(object[1]).to eq('banana')
|
|
747
|
+
expect(object.last).to eq('watermelon')
|
|
748
|
+
expect(object._status).to eq(200)
|
|
749
|
+
#TODO - Pasted from the Test above
|
|
750
|
+
end
|
|
751
|
+
|
|
631
752
|
it "should only send changed attributes if only_changed:true" do
|
|
632
753
|
expect_any_instance_of(Flexirest::Connection).to receive(:patch).with("/changed1", "debug=true", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"[{\"first_name\":\"Johnny\"}, {\"first_name\":\"Billy\"}, {\"debug\":\"true\"}]", status:200, response_headers:{})))
|
|
633
754
|
object = ExampleClient.new
|
data/spec/spec_helper.rb
CHANGED
|
@@ -66,12 +66,12 @@ class FaradayResponseMock < ::Flexirest::FaradayResponseProxy
|
|
|
66
66
|
@finished = false
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
def on_complete
|
|
69
|
+
def on_complete(&block)
|
|
70
70
|
if @auto_resolve
|
|
71
71
|
@finished = true
|
|
72
72
|
yield(@response)
|
|
73
73
|
else
|
|
74
|
-
@callback =
|
|
74
|
+
@callback = block
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flexirest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Jeffries
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-07-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -129,6 +129,9 @@ dependencies:
|
|
|
129
129
|
- - ">="
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
131
|
version: 1.3.1
|
|
132
|
+
- - "<"
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: '2.4'
|
|
132
135
|
type: :development
|
|
133
136
|
prerelease: false
|
|
134
137
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -136,6 +139,9 @@ dependencies:
|
|
|
136
139
|
- - ">="
|
|
137
140
|
- !ruby/object:Gem::Version
|
|
138
141
|
version: 1.3.1
|
|
142
|
+
- - "<"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '2.4'
|
|
139
145
|
- !ruby/object:Gem::Dependency
|
|
140
146
|
name: typhoeus
|
|
141
147
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -364,7 +370,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
364
370
|
- !ruby/object:Gem::Version
|
|
365
371
|
version: '0'
|
|
366
372
|
requirements: []
|
|
367
|
-
rubygems_version: 3.
|
|
373
|
+
rubygems_version: 3.1.2
|
|
368
374
|
signing_key:
|
|
369
375
|
specification_version: 4
|
|
370
376
|
summary: This gem is for accessing REST services in a flexible way. ActiveResource
|