flexirest 1.10.0 → 1.10.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/docs/authentication.md +24 -0
- data/docs/caching.md +8 -0
- data/docs/filtering-result-lists.md +1 -1
- data/docs/json-api.md +16 -4
- data/docs/plain-requests.md +1 -1
- data/docs/proxying-apis.md +1 -1
- data/docs/raw-requests.md +2 -2
- data/docs/root-elements.md +41 -6
- data/docs/using-callbacks.md +28 -1
- data/flexirest.gemspec +1 -1
- data/lib/flexirest/base_without_validation.rb +16 -0
- data/lib/flexirest/configuration.rb +44 -0
- data/lib/flexirest/json_api_proxy.rb +1 -4
- data/lib/flexirest/lazy_association_loader.rb +4 -0
- data/lib/flexirest/request.rb +68 -19
- data/lib/flexirest/result_iterator.rb +2 -0
- data/lib/flexirest/version.rb +1 -1
- data/spec/lib/base_without_validation_spec.rb +30 -0
- data/spec/lib/json_api_spec.rb +40 -6
- data/spec/lib/request_spec.rb +231 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10e663045de906cbfcd8e79800a795c440cb32b5f8e47e4b54b38aa85c450f15
|
4
|
+
data.tar.gz: c6b66793a525149f3fa1eec607c8a5cb8f3fa43fd5386b4e5a845b5e0d8359e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16bf500083c920340ff812d84d6cd6d6a7489783b229eb51822e4b994bba812226574c5831dc34bb1bcbe3c2a98e155ceaceb13c41270309b3573268ffced862
|
7
|
+
data.tar.gz: eff6f4b1699d63af2390b3c7ef970c301d2fc62cd2fda190b57f28132353c00f3a365567193cf9a2c98f5e97c5b7a1027fcf01197af34aa54f26dc57764319e6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.10.4
|
4
|
+
|
5
|
+
Enhancement:
|
6
|
+
|
7
|
+
- Implement support for in-header Basic Auth (thanks to François Ferrandis for the PR)
|
8
|
+
|
9
|
+
## 1.10.3
|
10
|
+
|
11
|
+
Enhancement:
|
12
|
+
|
13
|
+
- Ignore/wrap root functionality available for all routes, rather than just route specifically (thanks to Sampat Badhe for the PR)
|
14
|
+
|
15
|
+
## 1.10.2
|
16
|
+
|
17
|
+
Bugfix:
|
18
|
+
|
19
|
+
- JSON-API calls do not include linked resources when no other parameter is passed (thanks to Stevo-S for the bug report and François Ferrandis for the PR)
|
20
|
+
|
21
|
+
## 1.10.1
|
22
|
+
|
23
|
+
Enhancement:
|
24
|
+
|
25
|
+
- Nested objects now report their dirty/changed status up to the parent (thanks to Matthias Hähnel for the bug report)
|
26
|
+
|
3
27
|
## 1.10.0
|
4
28
|
|
5
29
|
Enhancement:
|
data/docs/authentication.md
CHANGED
@@ -40,6 +40,30 @@ Or if it's called from a class context:
|
|
40
40
|
Person.find(id: 1234)
|
41
41
|
```
|
42
42
|
|
43
|
+
### Basic authentication method
|
44
|
+
|
45
|
+
Flexirest provides two methods for HTTP Basic Auth. The default method is `:url`:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class Person < Flexirest::Base
|
49
|
+
basic_auth_method :url
|
50
|
+
end
|
51
|
+
# Includes the credentials in the URL:
|
52
|
+
# https://my_username:my_password@example.com/
|
53
|
+
```
|
54
|
+
|
55
|
+
But you might want to keep the credentials out of your logs and use the `:header` method:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Person < Flexirest::Base
|
59
|
+
basic_auth_method :header
|
60
|
+
end
|
61
|
+
# Clean URL:
|
62
|
+
# https://example.com/
|
63
|
+
# with the base64 encoded credentials:
|
64
|
+
# Authorization: Basic YXBpOmViNjkzZWMtODI1MmMtZDYzMDEtMDJmZDAtZDBmYjctYzM0ODU=
|
65
|
+
```
|
66
|
+
|
43
67
|
## Api-Auth
|
44
68
|
|
45
69
|
Using the [Api-Auth](https://github.com/mgomes/api_auth) integration it is very easy to sign requests. Include the Api-Auth gem in your `Gemfile` and then add it to your application. Then simply configure Api-Auth one time in your app and all requests will be signed from then on.
|
data/docs/caching.md
CHANGED
@@ -14,6 +14,14 @@ class Person < Flexirest::Base
|
|
14
14
|
end
|
15
15
|
```
|
16
16
|
|
17
|
+
or per request endpoint with:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class Person < Flexirest::Base
|
21
|
+
get :all, "/people", skip_caching: true
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
17
25
|
If Rails is defined, it will default to using Rails.cache as the cache store, if not, you'll need to configure one with a `ActiveSupport::Cache::Store` compatible object using:
|
18
26
|
|
19
27
|
```ruby
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# *Flexirest:* Filtering result lists
|
2
2
|
|
3
|
-
If the API returns a JSON list of items, this is
|
3
|
+
If the API returns a JSON list of items, this is returned to you as a `Flexirest::ResultIterator` object. A `ResultIterator` sorts simple filtering of the list using a `where` method based on values matching a specified criteria (or matching using regular expressions):
|
4
4
|
|
5
5
|
```ruby
|
6
6
|
class Article < Flexirest::Base
|
data/docs/json-api.md
CHANGED
@@ -12,17 +12,26 @@ This proxy translates requests according to the JSON API specifications, parses
|
|
12
12
|
|
13
13
|
It supports lazy loading by default. Unless a compound document is returned from the connected JSON API service, it will make another request to the service for the specified linked resource.
|
14
14
|
|
15
|
+
|
16
|
+
## Including associations
|
17
|
+
|
15
18
|
To reduce the number of requests to the service, you can ask the service to include the linked resources in the response. Such responses are called "compound documents". To do this, use the `includes` method:
|
16
19
|
|
17
20
|
```ruby
|
18
|
-
# Makes a call to /articles
|
21
|
+
# Makes a call to: /articles?include=images
|
19
22
|
Article.includes(:images).all
|
20
23
|
|
21
|
-
#
|
24
|
+
# Fetch nested resources: /articles?include=images.tags,images.photographer
|
22
25
|
Article.includes(:images => [:tags, :photographer]).all
|
26
|
+
|
27
|
+
# Note: the `includes` method takes precedence over the passed `:include` parameter.
|
28
|
+
# This will result in query: /articles?include=images
|
29
|
+
Article.includes(:images).all(include: "author")
|
23
30
|
```
|
24
31
|
|
25
|
-
|
32
|
+
## Resource type
|
33
|
+
|
34
|
+
The `type` value is guessed from the class name, but it can be set specifically with `alias_type`:
|
26
35
|
|
27
36
|
```ruby
|
28
37
|
class Photographer < Flexirest::Base
|
@@ -34,7 +43,10 @@ class Photographer < Flexirest::Base
|
|
34
43
|
end
|
35
44
|
```
|
36
45
|
|
37
|
-
|
46
|
+
|
47
|
+
## Notes
|
48
|
+
|
49
|
+
Updating relationships is not yet supported.
|
38
50
|
|
39
51
|
|
40
52
|
-----
|
data/docs/plain-requests.md
CHANGED
@@ -7,7 +7,7 @@ class Person < Flexirest::Base
|
|
7
7
|
end
|
8
8
|
|
9
9
|
people = Person._plain_request('http://api.example.com/v1/people') # Defaults to get with no parameters
|
10
|
-
# people is a
|
10
|
+
# people is a string containing the response
|
11
11
|
|
12
12
|
Person._plain_request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
|
13
13
|
```
|
data/docs/proxying-apis.md
CHANGED
@@ -40,7 +40,7 @@ Article.all.first_name == "Billy"
|
|
40
40
|
This example does two things:
|
41
41
|
|
42
42
|
1. It rewrites the incoming URL for any requests matching "_/all_" to "/all_people"
|
43
|
-
2. It uses the `translate` method to move the "fname" attribute from the response body to be called "first_name". The translate method must return the new object at the end (either the existing object
|
43
|
+
2. It uses the `translate` method to move the "fname" attribute from the response body to be called "first_name". The translate method must return the new object at the end (either the existing object altered, or a new object to replace it with)
|
44
44
|
|
45
45
|
As the comment shows, you can use `url value` to set the request URL to a particular value, or you can call `gsub!` on the url to replace parts of it using more complicated regular expressions.
|
46
46
|
|
data/docs/raw-requests.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# *Flexirest:* Raw requests
|
2
2
|
|
3
|
-
Sometimes you have
|
3
|
+
Sometimes you have a URL that you just want to force through, but have the response handled in the same way as normal objects or you want to have the callbacks run (say for authentication). The easiest way to do that is to call `_request` on the class:
|
4
4
|
|
5
5
|
```ruby
|
6
6
|
class Person < Flexirest::Base
|
@@ -12,7 +12,7 @@ people = Person._request('http://api.example.com/v1/people') # Defaults to get w
|
|
12
12
|
Person._request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
|
13
13
|
```
|
14
14
|
|
15
|
-
When you need to specify custom headers (for example for authentication) you can do this with a fourth option to the `_request` method. If you are using the default
|
15
|
+
When you need to specify custom headers (for example for authentication) you can do this with a fourth option to the `_request` method. If you are using the default parameters you'll need to specify them. For example:
|
16
16
|
|
17
17
|
```ruby
|
18
18
|
Person._request("http://api.example.com/v1/people", :get, {}, {headers:{"X-Something": "foo/bar"}})
|
data/docs/root-elements.md
CHANGED
@@ -2,13 +2,32 @@
|
|
2
2
|
|
3
3
|
If your response comes back with a root node and you'd like to ignore it, you can define the mapping as:
|
4
4
|
|
5
|
+
```ruby
|
6
|
+
Flexirest::Base.ignore_root = "data"
|
7
|
+
```
|
8
|
+
|
9
|
+
Any `ignore_root` setting in specific class overrides this declared default.
|
10
|
+
|
5
11
|
```ruby
|
6
12
|
class Feed < Flexirest::Base
|
7
|
-
|
13
|
+
ignore_root: "feed"
|
14
|
+
|
15
|
+
post :list, "/feed"
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
And any `ignore_root` setting in specific request overrides the both default and class specific setting.
|
20
|
+
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class Feed < Flexirest::Base
|
24
|
+
ignore_root: 'feed'
|
25
|
+
|
26
|
+
post :list, "/feed", ignore_root: "result"
|
8
27
|
end
|
9
28
|
```
|
10
29
|
|
11
|
-
|
30
|
+
You can also assign an array to `ignore_root` if you'd want to remove a tree of root nodes.
|
12
31
|
|
13
32
|
```ruby
|
14
33
|
class Feed < Flexirest::Base
|
@@ -26,16 +45,32 @@ Alternatively if you want to wrap your JSON request body in a root element, e.g.
|
|
26
45
|
}
|
27
46
|
```
|
28
47
|
|
29
|
-
You can do it
|
48
|
+
You can do it using `wrap_root`:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Flexirest::Base.wrap_root = "data"
|
52
|
+
```
|
53
|
+
|
54
|
+
Any `wrap_root` setting in specific class overrides this declared default.
|
30
55
|
|
31
56
|
```ruby
|
32
57
|
class Feed < Flexirest::Base
|
33
|
-
|
34
|
-
end
|
58
|
+
wrap_root: "feed"
|
35
59
|
|
36
|
-
|
60
|
+
post :list, "/feed"
|
61
|
+
end
|
37
62
|
```
|
38
63
|
|
64
|
+
And any `wrap_root` setting in specific request overrides the both default and class specific setting.
|
65
|
+
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class Feed < Flexirest::Base
|
69
|
+
wrap_root: 'feed'
|
70
|
+
|
71
|
+
post :list, "/feed", wrap_root: "data"
|
72
|
+
end
|
73
|
+
```
|
39
74
|
|
40
75
|
-----
|
41
76
|
|
data/docs/using-callbacks.md
CHANGED
@@ -66,6 +66,7 @@ After callbacks work in exactly the same way:
|
|
66
66
|
```ruby
|
67
67
|
class Person < Flexirest::Base
|
68
68
|
get :all, "/people"
|
69
|
+
get :all, "/people"
|
69
70
|
|
70
71
|
after_request :fix_empty_content
|
71
72
|
after_request :cache_all_people
|
@@ -88,6 +89,32 @@ end
|
|
88
89
|
|
89
90
|
**Note:** since v1.3.21 the empty response trick above isn't necessary, empty responses for 204 are accepted normally (the method returns `true`), but this is here to show an example of an `after_request` callback adjusting the body. The `cache_all_people` example shows how to cache a response even if the server doesn't send the correct headers.
|
90
91
|
|
92
|
+
If you manually set caching responses like the above, you may want to invalidate that cache when you make a create, update, delete etc request for the resource, for example:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
class Animal < Flexirest::Base
|
96
|
+
after_request :cache
|
97
|
+
before_request :cache_cleanup
|
98
|
+
|
99
|
+
get :get, '/animals/:id'
|
100
|
+
post :update, '/animals/:id'
|
101
|
+
delete :delete, '/animals/:id'
|
102
|
+
|
103
|
+
def cache_cleanup(name, request)
|
104
|
+
if name == :update || name == :delete
|
105
|
+
Flexirest::Logger.info(" \033[1;4;32m#{Flexirest.name}\033[0m Invalidating cache for #{self.class.name} #{request.url}")
|
106
|
+
Rails.cache.delete("#{self.class.name}:#{request.url}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def cache(name, response)
|
111
|
+
if name == :get
|
112
|
+
response.response_headers["Expires"] = 1.hour.from_now.iso8601
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
91
118
|
If you want to trap an error in an `after_request` callback and retry the request, this can be done - but retries will only happen once for each request (so we'd recommend checking all conditions in a single `after_request` and then retrying after fixing them all). You achieve this by raising a `Flexirest::CallbackRetryRequestException` from the callback.
|
92
119
|
|
93
120
|
```ruby
|
@@ -100,7 +127,7 @@ class Person < Flexirest::Base
|
|
100
127
|
|
101
128
|
def fix_invalid_request(name, response)
|
102
129
|
if response.status == 401
|
103
|
-
# Do something to fix the state of caches/variables used in the
|
130
|
+
# Do something to fix the state of caches/variables used in the
|
104
131
|
# before_request, etc
|
105
132
|
raise Flexirest::CallbackRetryRequestException.new
|
106
133
|
end
|
data/flexirest.gemspec
CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
|
|
39
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
|
-
spec.add_development_dependency 'rest-client'
|
42
|
+
spec.add_development_dependency 'rest-client'
|
43
43
|
|
44
44
|
spec.add_runtime_dependency "mime-types"
|
45
45
|
spec.add_runtime_dependency "multi_json"
|
@@ -11,6 +11,8 @@ module Flexirest
|
|
11
11
|
attr_accessor :_status
|
12
12
|
attr_accessor :_etag
|
13
13
|
attr_accessor :_headers
|
14
|
+
attr_accessor :_parent
|
15
|
+
attr_accessor :_parent_attribute_name
|
14
16
|
|
15
17
|
instance_methods.each do |m|
|
16
18
|
next unless %w{display presence load require untrust trust freeze method enable_warnings with_warnings suppress capture silence quietly debugger breakpoint}.map(&:to_sym).include? m
|
@@ -41,6 +43,13 @@ module Flexirest
|
|
41
43
|
def _copy_from(result)
|
42
44
|
@attributes = result._attributes
|
43
45
|
@_status = result._status
|
46
|
+
self._parent = result._parent
|
47
|
+
self._parent_attribute_name = result._parent_attribute_name
|
48
|
+
@attributes.each do |k,v|
|
49
|
+
if v.respond_to?(:_parent) && v._parent.present?
|
50
|
+
@attributes[k]._parent = self
|
51
|
+
end
|
52
|
+
end
|
44
53
|
_clean!
|
45
54
|
end
|
46
55
|
|
@@ -184,6 +193,10 @@ module Flexirest
|
|
184
193
|
output.to_json
|
185
194
|
end
|
186
195
|
|
196
|
+
def _set_dirty(key)
|
197
|
+
@dirty_attributes[key.to_sym] = true
|
198
|
+
end
|
199
|
+
|
187
200
|
private
|
188
201
|
|
189
202
|
def _set_attribute(key, value)
|
@@ -191,6 +204,9 @@ module Flexirest
|
|
191
204
|
old_value = @attributes[key.to_sym] unless old_value
|
192
205
|
old_value = old_value[0] if old_value and old_value.is_a? Array
|
193
206
|
@dirty_attributes[key.to_sym] = [old_value, value] if old_value != value
|
207
|
+
if _parent
|
208
|
+
_parent._set_dirty(_parent_attribute_name)
|
209
|
+
end
|
194
210
|
@attributes[key.to_sym] = value
|
195
211
|
end
|
196
212
|
|
@@ -13,6 +13,32 @@ module Flexirest
|
|
13
13
|
@api_auth_access_id = nil
|
14
14
|
@api_auth_secret_key = nil
|
15
15
|
@api_auth_options = {}
|
16
|
+
@ignore_root = nil
|
17
|
+
@wrap_root = nil
|
18
|
+
|
19
|
+
def ignore_root(value=nil)
|
20
|
+
if value.nil?
|
21
|
+
value = if @ignore_root.nil? && superclass.respond_to?(:ignore_root)
|
22
|
+
superclass.ignore_root
|
23
|
+
else
|
24
|
+
@ignore_root
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@ignore_root = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def wrap_root(value=nil)
|
32
|
+
if value.nil?
|
33
|
+
value = if @wrap_root.nil? && superclass.respond_to?(:wrap_root)
|
34
|
+
superclass.wrap_root
|
35
|
+
else
|
36
|
+
@wrap_root
|
37
|
+
end
|
38
|
+
else
|
39
|
+
@wrap_root = value
|
40
|
+
end
|
41
|
+
end
|
16
42
|
|
17
43
|
def base_url(value = nil)
|
18
44
|
@base_url ||= nil
|
@@ -109,6 +135,23 @@ module Flexirest
|
|
109
135
|
@@password = value
|
110
136
|
end
|
111
137
|
|
138
|
+
DEFAULT_BASIC_URL_METHOD = :url
|
139
|
+
|
140
|
+
def basic_auth_method(value = nil)
|
141
|
+
if value.nil? # Used as a getter method
|
142
|
+
if @basic_auth_method.nil? && superclass.respond_to?(:basic_auth_method)
|
143
|
+
superclass.basic_auth_method
|
144
|
+
else
|
145
|
+
@basic_auth_method || DEFAULT_BASIC_URL_METHOD
|
146
|
+
end
|
147
|
+
else # Used as a setter method
|
148
|
+
unless [:header, :url].include?(value)
|
149
|
+
raise %(Invalid basic_auth_method #{value.inspect}. Valid methods are :url (default) and :header.)
|
150
|
+
end
|
151
|
+
@basic_auth_method = value
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
112
155
|
def alias_type(value = nil)
|
113
156
|
@alias_type ||= nil
|
114
157
|
if value.nil?
|
@@ -285,6 +328,7 @@ module Flexirest
|
|
285
328
|
@adapter = Faraday.default_adapter
|
286
329
|
@api_auth_access_id = nil
|
287
330
|
@api_auth_secret_key = nil
|
331
|
+
@basic_auth_method = :url
|
288
332
|
end
|
289
333
|
|
290
334
|
private
|
@@ -50,11 +50,8 @@ module Flexirest
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def translate(params, include_associations)
|
53
|
-
# Return to caller if nothing is to be done
|
54
|
-
return params unless params.present? && include_associations.present?
|
55
|
-
|
56
53
|
# Format the linked resources array, and assign to include key
|
57
|
-
params[:include] = format_include_params(include_associations)
|
54
|
+
params[:include] = format_include_params(include_associations) if include_associations.present?
|
58
55
|
end
|
59
56
|
|
60
57
|
private
|
@@ -94,6 +94,10 @@ module Flexirest
|
|
94
94
|
request = Flexirest::Request.new(method, @request.object)
|
95
95
|
request.url = request.forced_url = @url
|
96
96
|
@object = request.call
|
97
|
+
if @object.respond_to?(:_parent=)
|
98
|
+
@object._parent = @options[:parent]
|
99
|
+
@object._parent_attribute_name = @options[:parent_attribute_name]
|
100
|
+
end
|
97
101
|
end
|
98
102
|
end
|
99
103
|
end
|
data/lib/flexirest/request.rb
CHANGED
@@ -32,6 +32,10 @@ module Flexirest
|
|
32
32
|
!@object.respond_to?(:dirty?)
|
33
33
|
end
|
34
34
|
|
35
|
+
def model_class
|
36
|
+
object_is_class? ? @object : @object.class
|
37
|
+
end
|
38
|
+
|
35
39
|
def class_name
|
36
40
|
if object_is_class?
|
37
41
|
@object.name
|
@@ -124,6 +128,18 @@ module Flexirest
|
|
124
128
|
ret
|
125
129
|
end
|
126
130
|
|
131
|
+
def inject_basic_auth_in_url(url)
|
132
|
+
url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if !url[%r{//[^/]*:[^/]*@}]
|
133
|
+
end
|
134
|
+
|
135
|
+
def using_basic_auth?
|
136
|
+
!!username
|
137
|
+
end
|
138
|
+
|
139
|
+
def basic_auth_digest
|
140
|
+
Base64.strict_encode64("#{username}:#{password}")
|
141
|
+
end
|
142
|
+
|
127
143
|
def request_body_type
|
128
144
|
if @method[:options][:request_body_type]
|
129
145
|
@method[:options][:request_body_type]
|
@@ -136,6 +152,30 @@ module Flexirest
|
|
136
152
|
end
|
137
153
|
end
|
138
154
|
|
155
|
+
def ignore_root
|
156
|
+
if @method[:options][:ignore_root]
|
157
|
+
@method[:options][:ignore_root]
|
158
|
+
elsif @object.nil?
|
159
|
+
nil
|
160
|
+
elsif object_is_class?
|
161
|
+
@object.ignore_root
|
162
|
+
else
|
163
|
+
@object.class.ignore_root
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def wrap_root
|
168
|
+
if @method[:options][:wrap_root]
|
169
|
+
@method[:options][:wrap_root]
|
170
|
+
elsif @object.nil?
|
171
|
+
nil
|
172
|
+
elsif object_is_class?
|
173
|
+
@object.wrap_root
|
174
|
+
else
|
175
|
+
@object.class.wrap_root
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
139
179
|
def verbose?
|
140
180
|
if object_is_class?
|
141
181
|
@object.verbose
|
@@ -272,7 +312,7 @@ module Flexirest
|
|
272
312
|
|
273
313
|
result = handle_response(response_env, cached)
|
274
314
|
@response_delegate.__setobj__(result)
|
275
|
-
original_object_class.write_cached_response(self, response_env, result)
|
315
|
+
original_object_class.write_cached_response(self, response_env, result) unless @method[:options][:skip_caching]
|
276
316
|
end
|
277
317
|
|
278
318
|
# If this was not a parallel request just return the original result
|
@@ -438,8 +478,8 @@ module Flexirest
|
|
438
478
|
@post_params
|
439
479
|
else
|
440
480
|
p = (params || @post_params || {})
|
441
|
-
if
|
442
|
-
p = {
|
481
|
+
if wrap_root.present?
|
482
|
+
p = {wrap_root => p}
|
443
483
|
end
|
444
484
|
p.to_query
|
445
485
|
end
|
@@ -452,8 +492,8 @@ module Flexirest
|
|
452
492
|
@post_params
|
453
493
|
else
|
454
494
|
p = (params || @post_params || {})
|
455
|
-
if
|
456
|
-
p = {
|
495
|
+
if wrap_root.present?
|
496
|
+
p = {wrap_root => p}
|
457
497
|
end
|
458
498
|
data, mp_headers = Flexirest::Multipart::Post.prepare_query(p)
|
459
499
|
mp_headers.each do |k,v|
|
@@ -467,8 +507,8 @@ module Flexirest
|
|
467
507
|
elsif @post_params.is_a?(String)
|
468
508
|
@post_params
|
469
509
|
else
|
470
|
-
if
|
471
|
-
{
|
510
|
+
if wrap_root.present?
|
511
|
+
{wrap_root => (params || @post_params || {})}.to_json
|
472
512
|
else
|
473
513
|
(params || @post_params || {}).to_json
|
474
514
|
end
|
@@ -483,7 +523,7 @@ module Flexirest
|
|
483
523
|
|
484
524
|
def do_request(etag)
|
485
525
|
http_headers = {}
|
486
|
-
http_headers["If-None-Match"] = etag if etag
|
526
|
+
http_headers["If-None-Match"] = etag if etag && !@method[:options][:skip_caching]
|
487
527
|
http_headers["Accept"] = "application/hal+json, application/json;q=0.5"
|
488
528
|
headers.each do |key,value|
|
489
529
|
value = value.join(",") if value.is_a?(Array)
|
@@ -503,7 +543,9 @@ module Flexirest
|
|
503
543
|
else
|
504
544
|
_, @base_url, @url = parts
|
505
545
|
end
|
506
|
-
|
546
|
+
if using_basic_auth? && model_class.basic_auth_method == :url
|
547
|
+
inject_basic_auth_in_url(base_url)
|
548
|
+
end
|
507
549
|
connection = Flexirest::ConnectionManager.get_connection(base_url)
|
508
550
|
end
|
509
551
|
else
|
@@ -516,7 +558,9 @@ module Flexirest
|
|
516
558
|
else
|
517
559
|
base_url = parts[0]
|
518
560
|
end
|
519
|
-
|
561
|
+
if using_basic_auth? && model_class.basic_auth_method == :url
|
562
|
+
inject_basic_auth_in_url(base_url)
|
563
|
+
end
|
520
564
|
connection = Flexirest::ConnectionManager.get_connection(base_url)
|
521
565
|
end
|
522
566
|
if @method[:options][:direct]
|
@@ -542,6 +586,8 @@ module Flexirest
|
|
542
586
|
:api_auth_secret_key => api_auth_secret_key,
|
543
587
|
:api_auth_options => api_auth_options
|
544
588
|
}
|
589
|
+
elsif using_basic_auth? && model_class.basic_auth_method == :header
|
590
|
+
http_headers["Authorization"] = "Basic #{basic_auth_digest}"
|
545
591
|
end
|
546
592
|
if @method[:options][:timeout]
|
547
593
|
request_options[:timeout] = @method[:options][:timeout]
|
@@ -601,7 +647,7 @@ module Flexirest
|
|
601
647
|
else
|
602
648
|
Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
|
603
649
|
end
|
604
|
-
result = generate_new_object(ignore_root:
|
650
|
+
result = generate_new_object(ignore_root: ignore_root, ignore_xml_root: @method[:options][:ignore_xml_root])
|
605
651
|
# TODO: Cleanup when ignore_xml_root is removed
|
606
652
|
else
|
607
653
|
raise ResponseParseException.new(status:status, body:@response.body, headers: @response.headers)
|
@@ -651,7 +697,7 @@ module Flexirest
|
|
651
697
|
result
|
652
698
|
end
|
653
699
|
|
654
|
-
def new_object(attributes, name = nil)
|
700
|
+
def new_object(attributes, name = nil, parent = nil, parent_attribute_name = nil)
|
655
701
|
@method[:options][:has_many] ||= {}
|
656
702
|
name = name.to_sym rescue nil
|
657
703
|
if @method[:options][:has_many][name]
|
@@ -664,6 +710,9 @@ module Flexirest
|
|
664
710
|
object = create_object_instance
|
665
711
|
end
|
666
712
|
|
713
|
+
object._parent = parent
|
714
|
+
object._parent_attribute_name = parent_attribute_name
|
715
|
+
|
667
716
|
if hal_response? && name.nil?
|
668
717
|
attributes = handle_hal_links_embedded(object, attributes)
|
669
718
|
end
|
@@ -691,9 +740,9 @@ module Flexirest
|
|
691
740
|
v = value
|
692
741
|
assignable_hash = value_from_object ? object._attributes : {}
|
693
742
|
if value_from_object && @method[:options][:lazy].include?(k)
|
694
|
-
assignable_hash[k] = Flexirest::LazyAssociationLoader.new(overridden_name, v, self, overridden_name:(overridden_name))
|
743
|
+
assignable_hash[k] = Flexirest::LazyAssociationLoader.new(overridden_name, v, self, overridden_name:(overridden_name), parent: object, parent_attribute_name: k)
|
695
744
|
elsif v.is_a? Hash
|
696
|
-
assignable_hash[k] = new_object(v, overridden_name )
|
745
|
+
assignable_hash[k] = new_object(v, overridden_name, object, k)
|
697
746
|
elsif v.is_a? Array
|
698
747
|
if @method[:options][:array].include?(k)
|
699
748
|
assignable_hash[k] = Array.new
|
@@ -811,15 +860,15 @@ module Flexirest
|
|
811
860
|
body = JsonAPIProxy::Response.parse(body, @object)
|
812
861
|
end
|
813
862
|
|
814
|
-
if
|
815
|
-
[
|
863
|
+
if ignore_root
|
864
|
+
[ignore_root].flatten.each do |key|
|
816
865
|
body = body[key.to_s]
|
817
866
|
end
|
818
867
|
end
|
819
868
|
elsif is_xml_response?
|
820
869
|
body = @response.body.blank? ? {} : Crack::XML.parse(@response.body)
|
821
|
-
if
|
822
|
-
[
|
870
|
+
if ignore_root
|
871
|
+
[ignore_root].flatten.each do |key|
|
823
872
|
body = body[key.to_s]
|
824
873
|
end
|
825
874
|
elsif options[:ignore_xml_root]
|
@@ -841,7 +890,7 @@ module Flexirest
|
|
841
890
|
result = new_object(body, @overridden_name)
|
842
891
|
result._status = @response.status
|
843
892
|
result._headers = @response.response_headers
|
844
|
-
result._etag = @response.response_headers['ETag']
|
893
|
+
result._etag = @response.response_headers['ETag'] unless @method[:options][:skip_caching]
|
845
894
|
if !object_is_class? && options[:mutable] != false
|
846
895
|
@object._copy_from(result)
|
847
896
|
@object._clean!
|
data/lib/flexirest/version.rb
CHANGED
@@ -12,6 +12,11 @@ class TranslatorExample
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
class NestedExample < Flexirest::BaseWithoutValidation
|
16
|
+
get :all, "/all", fake:"{\"person\":{\"name\": \"Billy\"}}"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
15
20
|
class AlteringClientExample < Flexirest::BaseWithoutValidation
|
16
21
|
translator TranslatorExample
|
17
22
|
base_url "http://www.example.com"
|
@@ -140,6 +145,31 @@ describe Flexirest::BaseWithoutValidation do
|
|
140
145
|
expect(client).to be_dirty
|
141
146
|
end
|
142
147
|
|
148
|
+
it "should store attribute changes on nested objects and mark them as dirty in the parent" do
|
149
|
+
client = NestedExample.all
|
150
|
+
client.person.name = "John"
|
151
|
+
expect(client.person.name.to_s).to eq("John")
|
152
|
+
|
153
|
+
expect(client).to be_dirty
|
154
|
+
expect(client.changes.keys).to include(:person)
|
155
|
+
|
156
|
+
expect(client.person).to be_dirty
|
157
|
+
expect(client.person.changes.keys).to include(:name)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should store attribute changes on nested objects loaded via instance methods and mark them as dirty in the parent" do
|
161
|
+
client = NestedExample.new()
|
162
|
+
client.all
|
163
|
+
client.person.name = "John"
|
164
|
+
expect(client.person.name.to_s).to eq("John")
|
165
|
+
|
166
|
+
expect(client).to be_dirty
|
167
|
+
expect(client.changes.keys).to include(:person)
|
168
|
+
|
169
|
+
expect(client.person).to be_dirty
|
170
|
+
expect(client.person.changes.keys).to include(:name)
|
171
|
+
end
|
172
|
+
|
143
173
|
it "should track changed attributes and provide access to previous values (similar to ActiveRecord/Mongoid)" do
|
144
174
|
client = EmptyExample.new()
|
145
175
|
client["test"] = "Something"
|
data/spec/lib/json_api_spec.rb
CHANGED
@@ -303,7 +303,7 @@ describe 'JSON API' do
|
|
303
303
|
let(:tags) { JsonAPIExample::Tag }
|
304
304
|
let(:author) { JsonAPIExample::Author }
|
305
305
|
|
306
|
-
|
306
|
+
describe 'responses' do
|
307
307
|
it 'should return the data object if the response contains only one data instance' do
|
308
308
|
expect(subject.find(1)).to be_an_instance_of(JsonAPIExampleArticle)
|
309
309
|
end
|
@@ -370,17 +370,17 @@ describe 'JSON API' do
|
|
370
370
|
end
|
371
371
|
end
|
372
372
|
|
373
|
-
|
373
|
+
describe 'attributes' do
|
374
374
|
it 'should return the attributes as part of the data instance' do
|
375
|
-
expect(subject.find(1).item).
|
375
|
+
expect(subject.find(1).item).to eq("item one")
|
376
376
|
end
|
377
377
|
|
378
378
|
it 'should return the association\'s attributes as part of the association instance' do
|
379
|
-
expect(subject.includes(:author).find_single_author(1).author.item).
|
379
|
+
expect(subject.includes(:author).find_single_author(1).author.item).to eq("item two")
|
380
380
|
end
|
381
381
|
end
|
382
382
|
|
383
|
-
|
383
|
+
describe 'associations' do
|
384
384
|
it 'should retrieve the resource\'s associations via its relationships object' do
|
385
385
|
expect(subject.includes(:tags).find(1).tags.size).to eq(2)
|
386
386
|
end
|
@@ -415,6 +415,40 @@ describe 'JSON API' do
|
|
415
415
|
end
|
416
416
|
end
|
417
417
|
|
418
|
+
describe 'requests' do
|
419
|
+
describe 'the `include=` parameter' do
|
420
|
+
before { stub_request(:get, %r{example\.com/articles}) }
|
421
|
+
|
422
|
+
context 'when using `.includes(:tags)`' do
|
423
|
+
it 'equal "tags"' do
|
424
|
+
JsonAPIExample::Article.includes(:tags).real_index
|
425
|
+
expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags')
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
context 'when using `.includes(tags: [:authors, :articles])`' do
|
430
|
+
it 'equal "tags.authors,tags.articles"' do
|
431
|
+
JsonAPIExample::Article.includes(tags: [:authors, :articles]).real_index
|
432
|
+
expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags.authors,tags.articles')
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
context 'when using both `.includes(:tags)` and other params in the final call' do
|
437
|
+
it 'uses the values passed to the `includes() method`' do
|
438
|
+
JsonAPIExample::Article.includes(:tags).real_index(filter: { author_id: 4 })
|
439
|
+
expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?filter%5Bauthor_id%5D=4&include=tags')
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
context 'when using both `.includes(:tags)` and the :include param in final call' do
|
444
|
+
it 'uses the values passed to the `includes() method`' do
|
445
|
+
JsonAPIExample::Article.includes(:tags).real_index(include: "author")
|
446
|
+
expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags')
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
418
452
|
context 'lazy loading' do
|
419
453
|
it 'should fetch association lazily' do
|
420
454
|
stub_request(:get, /www.example.com\/articles\/1\/tags/)
|
@@ -434,7 +468,7 @@ describe 'JSON API' do
|
|
434
468
|
end
|
435
469
|
end
|
436
470
|
|
437
|
-
|
471
|
+
describe 'client' do
|
438
472
|
it 'should request with json api format, and expect a json api response' do
|
439
473
|
expect_any_instance_of(Flexirest::Connection).to receive(:post) { |_, _, _, options|
|
440
474
|
expect(options[:headers]).to include('Content-Type' => 'application/vnd.api+json')
|
data/spec/lib/request_spec.rb
CHANGED
@@ -41,6 +41,7 @@ describe Flexirest::Request do
|
|
41
41
|
get :find, "/:id", required: [:id]
|
42
42
|
get :find_cat, "/:id/cat"
|
43
43
|
get :fruits, "/fruits"
|
44
|
+
get :uncached, "/uncached", skip_caching: true
|
44
45
|
get :change, "/change"
|
45
46
|
get :plain, "/plain/:id", plain: true
|
46
47
|
post :create, "/create", rubify_names: true
|
@@ -81,6 +82,26 @@ describe Flexirest::Request do
|
|
81
82
|
get :all, "/"
|
82
83
|
end
|
83
84
|
|
85
|
+
class AuthenticatedBasicHeaderExampleClient < Flexirest::Base
|
86
|
+
base_url "http://www.example.com"
|
87
|
+
username "john"
|
88
|
+
password "smith"
|
89
|
+
basic_auth_method :header
|
90
|
+
get :all, "/"
|
91
|
+
end
|
92
|
+
|
93
|
+
class AuthenticatedBasicHeaderExampleClientChildClass < AuthenticatedBasicHeaderExampleClient
|
94
|
+
get :child_method, "/"
|
95
|
+
end
|
96
|
+
|
97
|
+
class AuthenticatedBasicUrlExampleClient < Flexirest::Base
|
98
|
+
base_url "http://www.example.com"
|
99
|
+
username "john"
|
100
|
+
password "smith"
|
101
|
+
basic_auth_method :url
|
102
|
+
get :all, "/"
|
103
|
+
end
|
104
|
+
|
84
105
|
class AuthenticatedProcExampleClient < Flexirest::Base
|
85
106
|
base_url "http://www.example.com"
|
86
107
|
username Proc.new { |obj| obj ? "bill-#{obj.id}" : "bill" }
|
@@ -199,6 +220,89 @@ describe Flexirest::Request do
|
|
199
220
|
}
|
200
221
|
end
|
201
222
|
|
223
|
+
class LocalIgnoredRootExampleClient < ExampleClient
|
224
|
+
ignore_root "feed"
|
225
|
+
|
226
|
+
get :root, "/root", fake: %Q{
|
227
|
+
{
|
228
|
+
"feed": {
|
229
|
+
"title": "Example Feed"
|
230
|
+
}
|
231
|
+
}
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
class LocalIgnoredMultiLevelRootExampleClient < ExampleClient
|
236
|
+
ignore_root [:response, "data", "object"]
|
237
|
+
|
238
|
+
get :multi_level_root, "/multi-level-root", fake: %Q{
|
239
|
+
{
|
240
|
+
"response": {
|
241
|
+
"data": {
|
242
|
+
"object": {
|
243
|
+
"title": "Example Multi Level Feed"
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
class BaseIgnoredRootExampleClient < Flexirest::Base
|
252
|
+
base_url "http://www.example.com"
|
253
|
+
ignore_root "feed"
|
254
|
+
end
|
255
|
+
|
256
|
+
class GlobalIgnoredRootExampleClient < BaseIgnoredRootExampleClient
|
257
|
+
get :root, "/root", fake: %Q{
|
258
|
+
{
|
259
|
+
"feed": {
|
260
|
+
"title": "Example Feed"
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
class OverrideGlobalIgnoredRootForFileExampleClient < BaseIgnoredRootExampleClient
|
267
|
+
ignore_root "data"
|
268
|
+
|
269
|
+
get :root, "/root", fake: %Q{
|
270
|
+
{
|
271
|
+
"data": {
|
272
|
+
"title": "Example Feed"
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
end
|
277
|
+
|
278
|
+
class OverrideGlobalIgnoredRootForRequestExampleClient < BaseIgnoredRootExampleClient
|
279
|
+
get :root, "/root", ignore_root: "data", fake: %Q{
|
280
|
+
{
|
281
|
+
"data": {
|
282
|
+
"title": "Example Feed"
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
class BaseWrappedRootExampleClient < Flexirest::Base
|
289
|
+
base_url "http://www.example.com"
|
290
|
+
wrap_root "base_data"
|
291
|
+
end
|
292
|
+
|
293
|
+
class GlobalWrappedRootExampleClient < BaseWrappedRootExampleClient
|
294
|
+
put :wrapped, "/put/:id"
|
295
|
+
end
|
296
|
+
|
297
|
+
class OverrideGlobalWrappedRootForFileExampleClient < BaseWrappedRootExampleClient
|
298
|
+
wrap_root "class_specific_data"
|
299
|
+
put :wrapped, "/put/:id"
|
300
|
+
end
|
301
|
+
|
302
|
+
class OverrideGlobalWrappedRootForRequestExampleClient < BaseWrappedRootExampleClient
|
303
|
+
put :wrapped, "/put/:id", wrap_root: "request_specific_data"
|
304
|
+
end
|
305
|
+
|
202
306
|
class WhitelistedDateClient < Flexirest::Base
|
203
307
|
base_url "http://www.example.com"
|
204
308
|
put :conversion, "/put/:id"
|
@@ -231,13 +335,53 @@ describe Flexirest::Request do
|
|
231
335
|
expect(servers.uniq.count).to eq(2)
|
232
336
|
end
|
233
337
|
|
234
|
-
it "should
|
338
|
+
it "should use the URL method for Basic HTTP Auth when no basic_auth_method is set" do
|
339
|
+
mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
|
340
|
+
|
235
341
|
connection = double(Flexirest::Connection).as_null_object
|
236
342
|
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://john:smith@www.example.com").and_return(connection)
|
237
|
-
expect(connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(
|
343
|
+
expect(connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(mocked_response)
|
238
344
|
AuthenticatedExampleClient.all
|
239
345
|
end
|
240
346
|
|
347
|
+
it "should use the headers method for Basic auth when basic_auth_method is set to :header" do
|
348
|
+
mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
|
349
|
+
headers_including_auth = hash_including({ "Authorization" => "Basic am9objpzbWl0aA==" })
|
350
|
+
|
351
|
+
connection = double(Flexirest::Connection).as_null_object
|
352
|
+
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://www.example.com").and_return(connection)
|
353
|
+
expect(connection).to receive(:get).with("/", hash_including(headers: headers_including_auth)).and_return(mocked_response)
|
354
|
+
AuthenticatedBasicHeaderExampleClient.all
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should raise an error if Basic HTTP method is not :header or :url" do
|
358
|
+
expect do
|
359
|
+
AuthenticatedExampleClient.class_eval do
|
360
|
+
basic_auth_method :some_invalid_value
|
361
|
+
end
|
362
|
+
end.to raise_error(RuntimeError, "Invalid basic_auth_method :some_invalid_value. Valid methods are :url (default) and :header.")
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should use the setting set on the parent class" do
|
366
|
+
mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
|
367
|
+
headers_including_auth = hash_including({ "Authorization" => "Basic am9objpzbWl0aA==" })
|
368
|
+
|
369
|
+
connection = double(Flexirest::Connection).as_null_object
|
370
|
+
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://www.example.com").and_return(connection)
|
371
|
+
expect(connection).to receive(:get).with("/", hash_including(headers: headers_including_auth)).and_return(mocked_response)
|
372
|
+
AuthenticatedBasicHeaderExampleClientChildClass.child_method
|
373
|
+
end
|
374
|
+
|
375
|
+
it "should use the URL method for Basic auth when basic_auth_method is set to :url (and not include Authorization header)" do
|
376
|
+
mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
|
377
|
+
headers_not_including_auth = hash_excluding("Authorization")
|
378
|
+
|
379
|
+
connection = double(Flexirest::Connection).as_null_object
|
380
|
+
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://john:smith@www.example.com").and_return(connection)
|
381
|
+
expect(connection).to receive(:get).with("/", headers: headers_not_including_auth).and_return(mocked_response)
|
382
|
+
AuthenticatedBasicUrlExampleClient.all
|
383
|
+
end
|
384
|
+
|
241
385
|
it "should get an HTTP connection with basic authentication using procs when called in a class context" do
|
242
386
|
connection = double(Flexirest::Connection).as_null_object
|
243
387
|
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://bill:jones@www.example.com").and_return(connection)
|
@@ -854,6 +998,35 @@ describe Flexirest::Request do
|
|
854
998
|
expect(object._etag).to eq("123456")
|
855
999
|
end
|
856
1000
|
|
1001
|
+
it "shouldn't expose the etag header if skip_caching is enabled" do
|
1002
|
+
response = ::FaradayResponseMock.new(OpenStruct.new(body: "{}", response_headers: {"ETag" => "123456"}, status: 200))
|
1003
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/uncached", an_instance_of(Hash)).and_return(response)
|
1004
|
+
object = ExampleClient.uncached
|
1005
|
+
expect(object._etag).to_not eq("123456")
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
it "shouldn't send the etag header if skip_caching is enabled" do
|
1009
|
+
cached_response = Flexirest::CachedResponse.new(status:200, result:"", response_headers: {})
|
1010
|
+
cached_response.etag = "123456"
|
1011
|
+
expect(ExampleClient).to receive(:read_cached_response).and_return(cached_response)
|
1012
|
+
|
1013
|
+
response = ::FaradayResponseMock.new(OpenStruct.new(body: "{}", response_headers: {"ETag" => "123456"}, status: 200))
|
1014
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/uncached", {
|
1015
|
+
api_auth: {
|
1016
|
+
api_auth_access_id: "id123",
|
1017
|
+
api_auth_options: {},
|
1018
|
+
api_auth_secret_key: "secret123"
|
1019
|
+
},
|
1020
|
+
headers: {
|
1021
|
+
"Accept"=>"application/hal+json, application/json;q=0.5",
|
1022
|
+
"Content-Type"=>"application/x-www-form-urlencoded; charset=utf-8"
|
1023
|
+
}
|
1024
|
+
}).and_return(response)
|
1025
|
+
|
1026
|
+
expect(ExampleClient).to_not receive(:write_cached_response)
|
1027
|
+
object = ExampleClient.uncached
|
1028
|
+
end
|
1029
|
+
|
857
1030
|
it "should expose all headers" do
|
858
1031
|
response = ::FaradayResponseMock.new(OpenStruct.new(body: "{}", response_headers: {"X-Test-Header" => "true"}, status: 200))
|
859
1032
|
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/123", an_instance_of(Hash)).and_return(response)
|
@@ -1355,6 +1528,62 @@ describe Flexirest::Request do
|
|
1355
1528
|
expect(IgnoredMultiLevelRootExampleClient.multi_level_root.title).to eq("Example Multi Level Feed")
|
1356
1529
|
end
|
1357
1530
|
|
1531
|
+
it "should ignore a specified root element" do
|
1532
|
+
expect(LocalIgnoredRootExampleClient.root.title).to eq("Example Feed")
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
it "should ignore a specified multi-level root element" do
|
1536
|
+
expect(LocalIgnoredMultiLevelRootExampleClient.multi_level_root.title).to eq("Example Multi Level Feed")
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
it "should ignore a specified root element" do
|
1540
|
+
expect(GlobalIgnoredRootExampleClient.root.title).to eq("Example Feed")
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
it "should ignore a specified root element" do
|
1544
|
+
expect(OverrideGlobalIgnoredRootForFileExampleClient.root.title).to eq("Example Feed")
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
it "should ignore a specified root element" do
|
1548
|
+
expect(OverrideGlobalIgnoredRootForRequestExampleClient.root.title).to eq("Example Feed")
|
1549
|
+
end
|
1550
|
+
|
1551
|
+
it "should wrap elements if specified, in form-encoded format" do
|
1552
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(base_data%5Bdebug%5D=true&base_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1553
|
+
GlobalWrappedRootExampleClient.request_body_type :form_encoded
|
1554
|
+
GlobalWrappedRootExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1555
|
+
end
|
1556
|
+
|
1557
|
+
it "should wrap elements if specified, in form-encoded format" do
|
1558
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(class_specific_data%5Bdebug%5D=true&class_specific_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1559
|
+
OverrideGlobalWrappedRootForFileExampleClient.request_body_type :form_encoded
|
1560
|
+
OverrideGlobalWrappedRootForFileExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1561
|
+
end
|
1562
|
+
|
1563
|
+
it "should wrap elements if specified, in form-encoded format" do
|
1564
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(request_specific_data%5Bdebug%5D=true&request_specific_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1565
|
+
OverrideGlobalWrappedRootForRequestExampleClient.request_body_type :form_encoded
|
1566
|
+
OverrideGlobalWrappedRootForRequestExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1567
|
+
end
|
1568
|
+
|
1569
|
+
it "should encode the body wrapped in a root element in a JSON format if specified" do
|
1570
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"base_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1571
|
+
GlobalWrappedRootExampleClient.request_body_type :json
|
1572
|
+
GlobalWrappedRootExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
it "should encode the body wrapped in a root element in a JSON format if specified" do
|
1576
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"class_specific_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1577
|
+
OverrideGlobalWrappedRootForFileExampleClient.request_body_type :json
|
1578
|
+
OverrideGlobalWrappedRootForFileExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1579
|
+
end
|
1580
|
+
|
1581
|
+
it "should encode the body wrapped in a root element in a JSON format if specified" do
|
1582
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"request_specific_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
|
1583
|
+
OverrideGlobalWrappedRootForRequestExampleClient.request_body_type :json
|
1584
|
+
OverrideGlobalWrappedRootForRequestExampleClient.wrapped id:1234, debug:true, test:'foo'
|
1585
|
+
end
|
1586
|
+
|
1358
1587
|
context "Parameter preparation" do
|
1359
1588
|
method = {url: "http://www.example.com", method: :get}
|
1360
1589
|
object = nil
|
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.10.
|
4
|
+
version: 1.10.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Jeffries
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -176,14 +176,14 @@ dependencies:
|
|
176
176
|
requirements:
|
177
177
|
- - ">="
|
178
178
|
- !ruby/object:Gem::Version
|
179
|
-
version:
|
179
|
+
version: '0'
|
180
180
|
type: :development
|
181
181
|
prerelease: false
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
184
|
- - ">="
|
185
185
|
- !ruby/object:Gem::Version
|
186
|
-
version:
|
186
|
+
version: '0'
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
188
|
name: mime-types
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|