active_rest_client 1.1.12 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +28 -7
- data/active_rest_client.gemspec +0 -1
- data/lib/active_rest_client/base.rb +3 -3
- data/lib/active_rest_client/configuration.rb +23 -11
- data/lib/active_rest_client/connection.rb +26 -16
- data/lib/active_rest_client/monkey_patching.rb +6 -2
- data/lib/active_rest_client/proxy_base.rb +15 -2
- data/lib/active_rest_client/request.rb +41 -6
- data/lib/active_rest_client/version.rb +1 -1
- data/spec/lib/base_spec.rb +7 -0
- data/spec/lib/caching_spec.rb +8 -2
- data/spec/lib/configuration_spec.rb +16 -1
- data/spec/lib/connection_spec.rb +10 -2
- data/spec/lib/proxy_spec.rb +19 -0
- data/spec/lib/request_spec.rb +19 -4
- data/spec/lib/xml_spec.rb +10 -0
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa1076e05dc54a578810a49033b1cfc0502b1292
|
4
|
+
data.tar.gz: 6f191932544fa702a4924b52baa9dc938a7a026e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0cd5f8c5c5e9cd899c2d079e0daaa16afe0529eb9dbbf07612cbba5d9086ccf0d1114ba93991c1c6294039b5366e99a1a560b997b82bbfa32ca79a9745131a2b
|
7
|
+
data.tar.gz: fb8400a0f3c11bc3fbb5ce3a531119dc8af08f5700ebcf286dc4399a320286f4cc80a84e4e5892d23fb46cd808522ea3938a9409c43395f74ab648cb032690c6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 1.2.0
|
4
|
+
|
5
|
+
Features:
|
6
|
+
|
7
|
+
- Allows for beta-support for XML APIs as well as JSON ones.
|
8
|
+
|
9
|
+
Bugfixes:
|
10
|
+
|
11
|
+
- In order to allow JRuby to work with ActiveRestClient, the hard-coded dependency on Patron has been removed.
|
12
|
+
|
13
|
+
## 1.1.10 - 1.1.12
|
14
|
+
|
15
|
+
Features:
|
16
|
+
|
17
|
+
- Parallel requests can now be made
|
18
|
+
|
19
|
+
Bugfixes
|
20
|
+
|
21
|
+
- Some work around Faraday's weird method naming
|
22
|
+
- Start of XML support
|
23
|
+
- URL encoding username and password
|
24
|
+
|
25
|
+
## 1.0.9
|
26
|
+
|
27
|
+
Bugfixes
|
28
|
+
|
29
|
+
- Correctly handling invalid cache expiry times
|
30
|
+
|
31
|
+
## 1.0.8
|
32
|
+
|
33
|
+
Features:
|
34
|
+
|
35
|
+
- Added Api-Auth for authentication against APIs that use it
|
36
|
+
- Supporting array parameter types
|
37
|
+
- Relationships for 'has_one' can now be used
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/whichdigital/active-rest-client/badge.png)](https://coveralls.io/r/whichdigital/active-rest-client)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/whichdigital/active-rest-client.png)](https://codeclimate.com/github/whichdigital/active-rest-client)
|
6
6
|
[![Gem Version](https://badge.fury.io/rb/active_rest_client.png)](http://badge.fury.io/rb/active_rest_client)
|
7
|
+
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/whichdigital/active-rest-client.svg)](http://isitmaintained.com/project/whichdigital/active-rest-client "Average time to resolve an issue")
|
8
|
+
[![Percentage of issues still open](http://isitmaintained.com/badge/open/whichdigital/active-rest-client.svg)](http://isitmaintained.com/project/whichdigital/active-rest-client "Percentage of issues still open")
|
7
9
|
|
8
10
|
This gem is for accessing REST services in an ActiveRecord style. ActiveResource already exists for this, but it doesn't work where the resource naming doesn't follow Rails conventions, it doesn't have in-built caching and it's not as flexible in general.
|
9
11
|
|
@@ -125,13 +127,17 @@ puts @person.to_json
|
|
125
127
|
|
126
128
|
### Faraday Configuration
|
127
129
|
|
128
|
-
ActiveRestClient uses Faraday to allow switching HTTP backends, the default is
|
130
|
+
ActiveRestClient uses Faraday to allow switching HTTP backends, the default is to just use Faraday's default. To change the used backend just set it in the class by setting `adapter` to a Faraday supported adapter symbol.
|
129
131
|
|
130
132
|
```ruby
|
131
133
|
ActiveRestClient::Base.adapter = :net_http
|
134
|
+
# or ...
|
135
|
+
ActiveRestClient::Base.adapter = :patron
|
132
136
|
```
|
133
137
|
|
134
|
-
|
138
|
+
In versions before 1.2.0 the adapter was hardcoded to `:patron`, so if you want to ensure it still uses Patron, you should set this setting.
|
139
|
+
|
140
|
+
If you want more control you can pass a **complete** configuration block ("complete" means that the block does not *override* [the default configuration](https://github.com/whichdigital/active-rest-client/blob/5b1953d89e26c02ca74f74464ccb7cd4c9439dcc/lib/active_rest_client/configuration.rb#L184-L201), but rather *replaces* it). For available config variables look into the Faraday documentation.
|
135
141
|
|
136
142
|
```ruby
|
137
143
|
ActiveRestClient::Base.faraday_config do |faraday|
|
@@ -139,7 +145,7 @@ ActiveRestClient::Base.faraday_config do |faraday|
|
|
139
145
|
faraday.options.timeout = 10
|
140
146
|
faraday.headers['User-Agent'] = "ActiveRestClient/#{ActiveRestClient::VERSION}"
|
141
147
|
end
|
142
|
-
|
148
|
+
```
|
143
149
|
### Associations
|
144
150
|
|
145
151
|
There are two types of association. One assumes when you call a method you actually want it to call the method on a separate class (as that class has other methods that are useful). The other is lazy loading related classes from a separate URL.
|
@@ -205,9 +211,9 @@ And use it like this:
|
|
205
211
|
|
206
212
|
#### Association Type 3 - HAL Auto-loaded Resources
|
207
213
|
|
208
|
-
You don't need to define lazy attributes if they are defined using [HAL](http://stateless.co/hal_specification.html) (with an optional embedded representation). If your resource has an _links item (and optionally an _embedded item) then it will automatically treat the linked resources (with the _embedded cache) as if they were defined using `:lazy` as per type 2 above.
|
214
|
+
You don't need to define lazy attributes if they are defined using [HAL](http://stateless.co/hal_specification.html) (with an optional embedded representation). If your resource has an `_links` item (and optionally an `_embedded` item) then it will automatically treat the linked resources (with the `_embedded` cache) as if they were defined using `:lazy` as per type 2 above.
|
209
215
|
|
210
|
-
If you need to, you can access properties of the HAL association. By default just using the HAL association gets the embedded resource (or requests the remote resource if not available in the _embedded list).
|
216
|
+
If you need to, you can access properties of the HAL association. By default just using the HAL association gets the embedded resource (or requests the remote resource if not available in the `_embedded` list).
|
211
217
|
|
212
218
|
```ruby
|
213
219
|
@person = Person.find(1)
|
@@ -464,6 +470,13 @@ require 'api-auth'
|
|
464
470
|
ActiveRestClient::Base.api_auth_credentials(@access_id, @secret_key)
|
465
471
|
```
|
466
472
|
|
473
|
+
You can also specify different credentials for different models just like configuring base_url
|
474
|
+
```ruby
|
475
|
+
class Person < ActiveRestClient::Base
|
476
|
+
api_auth_credentials('123456', 'abcdef')
|
477
|
+
end
|
478
|
+
```
|
479
|
+
|
467
480
|
For more information on how to generate an access id and secret key please read the [Api-Auth](https://github.com/mgomes/api_auth) documentation.
|
468
481
|
|
469
482
|
### Body Types
|
@@ -577,7 +590,7 @@ people = Person._plain_request('http://api.example.com/v1/people') # Defaults to
|
|
577
590
|
Person._plain_request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
|
578
591
|
```
|
579
592
|
|
580
|
-
The parameters are the same as for _request
|
593
|
+
The parameters are the same as for `_request`, but it does no parsing on the response
|
581
594
|
|
582
595
|
### Proxying APIs
|
583
596
|
|
@@ -814,6 +827,14 @@ puts @atom.feed.link.href
|
|
814
827
|
end
|
815
828
|
```
|
816
829
|
|
830
|
+
If your XML object comes back with a root node and you'd like to ignore it, you can define the mapping as:
|
831
|
+
|
832
|
+
```ruby
|
833
|
+
class Feed < ActiveRestClient::Base
|
834
|
+
get :atom, "/atom", ignore_xml_root: "feed"
|
835
|
+
end
|
836
|
+
```
|
837
|
+
|
817
838
|
For testing purposes, if you are using a `fake` content response when defining your endpoint, you should also provide `fake_content_type: "application/xml"` so that the parser knows to use XML parsing.
|
818
839
|
|
819
840
|
## Contributing
|
@@ -822,4 +843,4 @@ For testing purposes, if you are using a `fake` content response when defining y
|
|
822
843
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
823
844
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
824
845
|
4. Push to the branch (`git push origin my-new-feature`)
|
825
|
-
5. Create new Pull Request
|
846
|
+
5. Create new Pull Request
|
data/active_rest_client.gemspec
CHANGED
@@ -36,5 +36,4 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_runtime_dependency "crack"
|
37
37
|
spec.add_runtime_dependency "activesupport"
|
38
38
|
spec.add_runtime_dependency "faraday"
|
39
|
-
spec.add_runtime_dependency "patron", ">= 0.4.9" # 0.4.18 breaks against Curl v0.7.15 but works with webmock
|
40
39
|
end
|
@@ -24,10 +24,10 @@ module ActiveRestClient
|
|
24
24
|
|
25
25
|
attrs.each do |attribute_name, attribute_value|
|
26
26
|
attribute_name = attribute_name.to_sym
|
27
|
-
if attribute_value.to_s[
|
28
|
-
@attributes[attribute_name] = DateTime.parse(attribute_value)
|
29
|
-
elsif attribute_value.to_s =~ /^\d{4}\-\d{2}-\d{2}$/
|
27
|
+
if attribute_value.to_s[/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6]))))$/]
|
30
28
|
@attributes[attribute_name] = Date.parse(attribute_value)
|
29
|
+
elsif attribute_value.to_s[/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/]
|
30
|
+
@attributes[attribute_name] = DateTime.parse(attribute_value)
|
31
31
|
else
|
32
32
|
@attributes[attribute_name] = attribute_value
|
33
33
|
end
|
@@ -8,8 +8,8 @@ module ActiveRestClient
|
|
8
8
|
@@password = nil
|
9
9
|
@@request_body_type = :form_encoded
|
10
10
|
@lazy_load = false
|
11
|
-
|
12
|
-
|
11
|
+
@api_auth_access_id = nil
|
12
|
+
@api_auth_secret_key = nil
|
13
13
|
|
14
14
|
def base_url(value = nil)
|
15
15
|
if value.nil?
|
@@ -91,7 +91,7 @@ module ActiveRestClient
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def adapter
|
94
|
-
@adapter ||=
|
94
|
+
@adapter ||= Faraday.default_adapter
|
95
95
|
end
|
96
96
|
|
97
97
|
def faraday_config(&block)
|
@@ -121,20 +121,32 @@ module ActiveRestClient
|
|
121
121
|
raise MissingOptionalLibraryError.new("You must include the gem 'api-auth' in your Gemfile to set api-auth credentials.")
|
122
122
|
end
|
123
123
|
|
124
|
-
|
125
|
-
|
124
|
+
@api_auth_access_id = access_id
|
125
|
+
@api_auth_secret_key = secret_key
|
126
126
|
end
|
127
127
|
|
128
128
|
def using_api_auth?
|
129
|
-
|
129
|
+
!self.api_auth_access_id.nil? && !self.api_auth_secret_key.nil?
|
130
130
|
end
|
131
131
|
|
132
132
|
def api_auth_access_id
|
133
|
-
|
133
|
+
if !@api_auth_access_id.nil?
|
134
|
+
return @api_auth_access_id
|
135
|
+
elsif self.superclass.respond_to?(:api_auth_access_id)
|
136
|
+
return self.superclass.api_auth_access_id
|
137
|
+
end
|
138
|
+
|
139
|
+
return nil
|
134
140
|
end
|
135
141
|
|
136
142
|
def api_auth_secret_key
|
137
|
-
|
143
|
+
if !@api_auth_secret_key.nil?
|
144
|
+
return @api_auth_secret_key
|
145
|
+
elsif self.superclass.respond_to?(:api_auth_secret_key)
|
146
|
+
return self.superclass.api_auth_secret_key
|
147
|
+
end
|
148
|
+
|
149
|
+
return nil
|
138
150
|
end
|
139
151
|
|
140
152
|
def verbose!
|
@@ -162,9 +174,9 @@ module ActiveRestClient
|
|
162
174
|
@whiny_missing = nil
|
163
175
|
@lazy_load = false
|
164
176
|
@faraday_config = default_faraday_config
|
165
|
-
@adapter =
|
166
|
-
|
167
|
-
|
177
|
+
@adapter = Faraday.default_adapter
|
178
|
+
@api_auth_access_id = nil
|
179
|
+
@api_auth_secret_key = nil
|
168
180
|
end
|
169
181
|
|
170
182
|
private
|
@@ -34,40 +34,44 @@ module ActiveRestClient
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
def get(path,
|
37
|
+
def get(path, options={})
|
38
|
+
set_defaults(options)
|
38
39
|
make_safe_request(path) do
|
39
40
|
@session.get(path) do |req|
|
40
|
-
req.headers = req.headers.merge(headers)
|
41
|
-
sign_request(req)
|
41
|
+
req.headers = req.headers.merge(options[:headers])
|
42
|
+
sign_request(req, options[:api_auth])
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
def put(path, data,
|
47
|
+
def put(path, data, options={})
|
48
|
+
set_defaults(options)
|
47
49
|
make_safe_request(path) do
|
48
50
|
@session.put(path) do |req|
|
49
|
-
req.headers = req.headers.merge(headers)
|
51
|
+
req.headers = req.headers.merge(options[:headers])
|
50
52
|
req.body = data
|
51
|
-
sign_request(req)
|
53
|
+
sign_request(req, options[:api_auth])
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def post(path, data,
|
58
|
+
def post(path, data, options={})
|
59
|
+
set_defaults(options)
|
57
60
|
make_safe_request(path) do
|
58
61
|
@session.post(path) do |req|
|
59
|
-
req.headers = req.headers.merge(headers)
|
62
|
+
req.headers = req.headers.merge(options[:headers])
|
60
63
|
req.body = data
|
61
|
-
sign_request(req)
|
64
|
+
sign_request(req, options[:api_auth])
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
66
|
-
def delete(path,
|
69
|
+
def delete(path, options={})
|
70
|
+
set_defaults(options)
|
67
71
|
make_safe_request(path) do
|
68
72
|
@session.delete(path) do |req|
|
69
|
-
req.headers = req.headers.merge(headers)
|
70
|
-
sign_request(req)
|
73
|
+
req.headers = req.headers.merge(options[:headers])
|
74
|
+
sign_request(req, options[:api_auth])
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
@@ -82,12 +86,18 @@ module ActiveRestClient
|
|
82
86
|
@session.build_url(path).to_s
|
83
87
|
end
|
84
88
|
|
85
|
-
def
|
86
|
-
|
89
|
+
def set_defaults(options)
|
90
|
+
options[:headers] ||= {}
|
91
|
+
options[:api_auth] ||= {}
|
92
|
+
return options
|
93
|
+
end
|
94
|
+
|
95
|
+
def sign_request(request, api_auth)
|
96
|
+
return if api_auth[:api_auth_access_id].nil? || api_auth[:api_auth_secret_key].nil?
|
87
97
|
ApiAuth.sign!(
|
88
98
|
request,
|
89
|
-
|
90
|
-
|
99
|
+
api_auth[:api_auth_access_id],
|
100
|
+
api_auth[:api_auth_secret_key])
|
91
101
|
end
|
92
102
|
end
|
93
103
|
end
|
@@ -66,11 +66,24 @@ module ActiveRestClient
|
|
66
66
|
@original_handler.call(@request)
|
67
67
|
end
|
68
68
|
|
69
|
+
def result_is_json_or_unspecified?(result)
|
70
|
+
result.headers['Content-Type'].include?('json')
|
71
|
+
rescue
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
69
75
|
def translate(result, options = {})
|
70
|
-
result.headers[
|
76
|
+
incoming_content_type = result.headers['Content-Type']
|
77
|
+
if result_is_json_or_unspecified?(result)
|
78
|
+
result.headers["content-type"] = "application/hal+json"
|
79
|
+
end
|
71
80
|
result = FaradayResponseProxy.new(OpenStruct.new(status:result.status, response_headers:result.headers, body:result.body))
|
72
81
|
if result.body.present?
|
73
|
-
|
82
|
+
if incoming_content_type && incoming_content_type["xml"]
|
83
|
+
result.body = yield Crack::XML.parse(result.body)
|
84
|
+
else
|
85
|
+
result.body = yield MultiJson.load(result.body)
|
86
|
+
end
|
74
87
|
end
|
75
88
|
result
|
76
89
|
end
|
@@ -48,6 +48,30 @@ module ActiveRestClient
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
def using_api_auth?
|
52
|
+
if object_is_class?
|
53
|
+
@object.using_api_auth?
|
54
|
+
else
|
55
|
+
@object.class.using_api_auth?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def api_auth_access_id
|
60
|
+
if object_is_class?
|
61
|
+
@object.api_auth_access_id
|
62
|
+
else
|
63
|
+
@object.class.api_auth_access_id
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def api_auth_secret_key
|
68
|
+
if object_is_class?
|
69
|
+
@object.api_auth_secret_key
|
70
|
+
else
|
71
|
+
@object.class.api_auth_secret_key
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
51
75
|
def username
|
52
76
|
if object_is_class?
|
53
77
|
@object.username
|
@@ -283,15 +307,23 @@ module ActiveRestClient
|
|
283
307
|
ActiveRestClient::Logger.debug " >> Body:\n#{@body}"
|
284
308
|
end
|
285
309
|
|
310
|
+
request_options = {:headers => http_headers}
|
311
|
+
if using_api_auth?
|
312
|
+
request_options[:api_auth] = {
|
313
|
+
:api_auth_access_id => api_auth_access_id,
|
314
|
+
:api_auth_secret_key => api_auth_secret_key
|
315
|
+
}
|
316
|
+
end
|
317
|
+
|
286
318
|
case http_method
|
287
319
|
when :get
|
288
|
-
response = connection.get(@url,
|
320
|
+
response = connection.get(@url, request_options)
|
289
321
|
when :put
|
290
|
-
response = connection.put(@url, @body,
|
322
|
+
response = connection.put(@url, @body, request_options)
|
291
323
|
when :post
|
292
|
-
response = connection.post(@url, @body,
|
324
|
+
response = connection.post(@url, @body, request_options)
|
293
325
|
when :delete
|
294
|
-
response = connection.delete(@url,
|
326
|
+
response = connection.delete(@url, request_options)
|
295
327
|
else
|
296
328
|
raise InvalidRequestException.new("Invalid method #{http_method}")
|
297
329
|
end
|
@@ -331,13 +363,13 @@ module ActiveRestClient
|
|
331
363
|
else
|
332
364
|
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
|
333
365
|
end
|
334
|
-
result = generate_new_object
|
366
|
+
result = generate_new_object(ignore_xml_root: @method[:options][:ignore_xml_root])
|
335
367
|
else
|
336
368
|
raise ResponseParseException.new(status:status, body:@response.body)
|
337
369
|
end
|
338
370
|
else
|
339
371
|
if is_json_response? || is_xml_response?
|
340
|
-
error_response = generate_new_object(mutable: false)
|
372
|
+
error_response = generate_new_object(mutable: false, ignore_xml_root: @method[:options][:ignore_xml_root])
|
341
373
|
else
|
342
374
|
error_response = @response.body
|
343
375
|
end
|
@@ -483,6 +515,9 @@ module ActiveRestClient
|
|
483
515
|
body = @response.body.blank? ? {} : MultiJson.load(@response.body)
|
484
516
|
elsif is_xml_response?
|
485
517
|
body = @response.body.blank? ? {} : Crack::XML.parse(@response.body)
|
518
|
+
if options[:ignore_xml_root]
|
519
|
+
body = body[options[:ignore_xml_root].to_s]
|
520
|
+
end
|
486
521
|
end
|
487
522
|
body = begin
|
488
523
|
@method[:name].nil? ? body : translator.send(@method[:name], body)
|
data/spec/lib/base_spec.rb
CHANGED
@@ -80,6 +80,13 @@ describe ActiveRestClient::Base do
|
|
80
80
|
expect(client["test"].to_s).to eq(t.to_datetime.to_s)
|
81
81
|
end
|
82
82
|
|
83
|
+
it "should automatically parse ISO 8601 format date and time with milliseconds" do
|
84
|
+
t = Time.now
|
85
|
+
client = EmptyExample.new(:test => t.iso8601(3))
|
86
|
+
expect(client["test"]).to be_an_instance_of(DateTime)
|
87
|
+
expect(client["test"].to_s).to eq(t.to_datetime.to_s)
|
88
|
+
end
|
89
|
+
|
83
90
|
it "should automatically parse ISO 8601 format dates" do
|
84
91
|
d = Date.today
|
85
92
|
client = EmptyExample.new(:test => d.iso8601)
|
data/spec/lib/caching_spec.rb
CHANGED
@@ -111,7 +111,10 @@ describe ActiveRestClient::Caching do
|
|
111
111
|
result:@cached_object,
|
112
112
|
etag:@etag)
|
113
113
|
expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(Marshal.dump(cached_response))
|
114
|
-
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get)
|
114
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get){ |connection, path, options|
|
115
|
+
expect(path).to eq('/')
|
116
|
+
expect(options[:headers]).to include("If-None-Match" => @etag)
|
117
|
+
}.and_return(::FaradayResponseMock.new(OpenStruct.new(status:304, response_headers:{})))
|
115
118
|
ret = Person.all
|
116
119
|
expect(ret.first_name).to eq("Johnny")
|
117
120
|
end
|
@@ -127,7 +130,10 @@ describe ActiveRestClient::Caching do
|
|
127
130
|
response_body = Person.new(first_name: new_name).to_json
|
128
131
|
response = ::FaradayResponseMock.new(double(status: 200, response_headers: {}, body: response_body))
|
129
132
|
allow_any_instance_of(ActiveRestClient::Connection).to(
|
130
|
-
receive(:get)
|
133
|
+
receive(:get){ |connection, path, options|
|
134
|
+
expect(path).to eq('/')
|
135
|
+
expect(options[:headers]).to include('If-None-Match' => @etag)
|
136
|
+
}.and_return(response))
|
131
137
|
|
132
138
|
result = Person.all
|
133
139
|
|
@@ -155,6 +155,21 @@ describe ActiveRestClient::Configuration do
|
|
155
155
|
it "should remember setting api_auth_secret_key" do
|
156
156
|
expect(ConfigurationExample.api_auth_secret_key).to eq('secret123')
|
157
157
|
end
|
158
|
+
|
159
|
+
it "should inherit api_auth_credentials when not set" do
|
160
|
+
class ConfigurationExtension < ConfigurationExample
|
161
|
+
end
|
162
|
+
expect(ConfigurationExtension.api_auth_access_id).to eq('id123')
|
163
|
+
expect(ConfigurationExtension.api_auth_secret_key).to eq('secret123')
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should override inherited api_auth_credentials when set" do
|
167
|
+
class ConfigurationExtension2 < ConfigurationExample
|
168
|
+
end
|
169
|
+
ConfigurationExtension2.api_auth_credentials('id456', 'secret456')
|
170
|
+
expect(ConfigurationExtension2.api_auth_access_id).to eq('id456')
|
171
|
+
expect(ConfigurationExtension2.api_auth_secret_key).to eq('secret456')
|
172
|
+
end
|
158
173
|
end
|
159
174
|
end
|
160
175
|
|
@@ -194,7 +209,7 @@ describe ActiveRestClient::Configuration do
|
|
194
209
|
let(:faraday_double){double(:faraday).as_null_object}
|
195
210
|
|
196
211
|
it "should use default adapter if no other block set" do
|
197
|
-
expect(faraday_double).to receive(:adapter).with(
|
212
|
+
expect(faraday_double).to receive(:adapter).with(Faraday.default_adapter)
|
198
213
|
ConfigurationExample.faraday_config.call(faraday_double)
|
199
214
|
end
|
200
215
|
|
data/spec/lib/connection_spec.rb
CHANGED
@@ -100,8 +100,16 @@ describe ActiveRestClient::Connection do
|
|
100
100
|
|
101
101
|
context 'with api auth signing requests' do
|
102
102
|
before(:each) do
|
103
|
+
# Need to still call this to load the api_auth library so tests work
|
103
104
|
ActiveRestClient::Base.api_auth_credentials('id123', 'secret123')
|
104
105
|
|
106
|
+
@options = {
|
107
|
+
:api_auth => {
|
108
|
+
:api_auth_access_id => 'id123',
|
109
|
+
:api_auth_secret_key => 'secret123'
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
105
113
|
@default_headers = {'Date' => 'Sat, 14 Mar 2015 15:13:24 GMT'}
|
106
114
|
|
107
115
|
ActiveRestClient::Base.faraday_config do |faraday|
|
@@ -115,7 +123,7 @@ describe ActiveRestClient::Connection do
|
|
115
123
|
stub_request(:get, "www.example.com/foo")
|
116
124
|
.with(:headers => @default_headers)
|
117
125
|
.to_return(body: "{result:true}")
|
118
|
-
result = @connection.get("/foo")
|
126
|
+
result = @connection.get("/foo", @options)
|
119
127
|
expect(result.env.request_headers['Authorization']).to eq("APIAuth id123:PMWBThkB8vKbvUccHvoqu9G3eVk=")
|
120
128
|
end
|
121
129
|
|
@@ -124,7 +132,7 @@ describe ActiveRestClient::Connection do
|
|
124
132
|
with(body: "body", :headers => @default_headers).
|
125
133
|
to_return(body: "{result:true}")
|
126
134
|
|
127
|
-
result = @connection.put("/foo", "body")
|
135
|
+
result = @connection.put("/foo", "body", @options)
|
128
136
|
expect(result.env.request_headers['Content-MD5']).to eq("hBotaJrYa9FhFEdFPCLG/A==")
|
129
137
|
end
|
130
138
|
end
|
data/spec/lib/proxy_spec.rb
CHANGED
@@ -43,6 +43,14 @@ class ProxyExample < ActiveRestClient::ProxyBase
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
get "/change-xml-format" do
|
47
|
+
response = passthrough
|
48
|
+
translate(response) do |body|
|
49
|
+
body["first_name"] = body["object"].delete("fname")
|
50
|
+
body
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
46
54
|
get "/hal_test/:id" do
|
47
55
|
response = passthrough
|
48
56
|
translate(response) do |body|
|
@@ -70,6 +78,7 @@ class ProxyClientExample < ActiveRestClient::Base
|
|
70
78
|
get :fake, "/fake"
|
71
79
|
get :param, "/param/:id/:name"
|
72
80
|
get :change_format, "/change-format"
|
81
|
+
get :change_xml_format, "/change-xml-format"
|
73
82
|
post :create, "/create"
|
74
83
|
put :update, "/update"
|
75
84
|
get :not_proxied, "/not_proxied"
|
@@ -120,6 +129,16 @@ describe ActiveRestClient::Base do
|
|
120
129
|
expect(ret.first_name).to eq("Billy")
|
121
130
|
end
|
122
131
|
|
132
|
+
it "can intercept XML responses, parse the response, alter it and pass it on during the request" do
|
133
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get).with("/change-xml-format",
|
134
|
+
instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(
|
135
|
+
body:"<?xml version=\"1.0\" encoding=\"UTF-8\"?><object><fname>Billy</fname></object>",
|
136
|
+
status:200,
|
137
|
+
response_headers:{"Content-Type" => "application/xml"})))
|
138
|
+
ret = ProxyClientExample.change_xml_format
|
139
|
+
expect(ret.first_name).to eq("Billy")
|
140
|
+
end
|
141
|
+
|
123
142
|
it 'skips the altering of the response body when there is none' do
|
124
143
|
allow_any_instance_of(ActiveRestClient::Connection).to receive(:get).with('/change-format', instance_of(Hash))
|
125
144
|
.and_return(double(body: '', status: 200, headers: {}))
|
data/spec/lib/request_spec.rb
CHANGED
@@ -7,6 +7,7 @@ describe ActiveRestClient::Request do
|
|
7
7
|
class ExampleClient < ActiveRestClient::Base
|
8
8
|
base_url "http://www.example.com"
|
9
9
|
request_body_type :form_encoded
|
10
|
+
api_auth_credentials('id123', 'secret123')
|
10
11
|
|
11
12
|
before_request do |name, request|
|
12
13
|
if request.method[:name] == :headers
|
@@ -160,17 +161,28 @@ describe ActiveRestClient::Request do
|
|
160
161
|
end
|
161
162
|
|
162
163
|
it "should pass through custom headers" do
|
163
|
-
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get)
|
164
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get){ |connection, path, options|
|
165
|
+
expect(path).to eq('/headers')
|
166
|
+
expect(options[:headers]).to include("X-My-Header" => "myvalue")
|
167
|
+
}.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
|
164
168
|
ExampleClient.headers
|
165
169
|
end
|
166
170
|
|
167
171
|
it "should set request header with content-type for default" do
|
168
|
-
expect_any_instance_of(ActiveRestClient::Connection).to receive(:put)
|
172
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:put){ |connection, path, data, options|
|
173
|
+
expect(path).to eq('/headers_default')
|
174
|
+
expect(data).to eq('')
|
175
|
+
expect(options[:headers]).to include("Content-Type" => "application/x-www-form-urlencoded")
|
176
|
+
}.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
|
169
177
|
ExampleClient.headers_default
|
170
178
|
end
|
171
179
|
|
172
180
|
it "should set request header with content-type for JSON" do
|
173
|
-
expect_any_instance_of(ActiveRestClient::Connection).to receive(:put)
|
181
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:put){ |connection, path, data, options|
|
182
|
+
expect(path).to eq('/headers_json')
|
183
|
+
expect(data).to eq('{}')
|
184
|
+
expect(options[:headers]).to include("Content-Type" => "application/json; charset=utf-8")
|
185
|
+
}.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
|
174
186
|
ExampleClient.headers_json
|
175
187
|
end
|
176
188
|
|
@@ -578,7 +590,10 @@ describe ActiveRestClient::Request do
|
|
578
590
|
let(:hal) { ExampleClient.hal }
|
579
591
|
|
580
592
|
it "should request a HAL response or plain JSON" do
|
581
|
-
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get)
|
593
|
+
expect_any_instance_of(ActiveRestClient::Connection).to receive(:get){ |connection, path, options|
|
594
|
+
expect(path).to eq('/headers')
|
595
|
+
expect(options[:headers]).to include("Accept" => "application/hal+json, application/json;q=0.5")
|
596
|
+
}.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
|
582
597
|
ExampleClient.headers
|
583
598
|
end
|
584
599
|
|
data/spec/lib/xml_spec.rb
CHANGED
@@ -2,6 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
class XmlResponseExample < ActiveRestClient::Base
|
4
4
|
base_url "http://www.example.com/v1/"
|
5
|
+
get :root, "/root", ignore_xml_root: "feed", fake_content_type: "application/xml", fake: %Q{
|
6
|
+
<?xml version="1.0" encoding="utf-8"?>
|
7
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
8
|
+
<title>Example Feed</title>
|
9
|
+
</feed>
|
10
|
+
}
|
5
11
|
get :atom, "/atom", fake: %Q{
|
6
12
|
<?xml version="1.0" encoding="utf-8"?>
|
7
13
|
<feed xmlns="http://www.w3.org/2005/Atom">
|
@@ -61,4 +67,8 @@ describe XmlResponseExample do
|
|
61
67
|
expect(@atom.feed.entry[1].title).to eq("Something else cool happened")
|
62
68
|
end
|
63
69
|
|
70
|
+
it "allows ignoring of the XML root node" do
|
71
|
+
@feed = XmlResponseExample.root
|
72
|
+
expect(@feed.title).to eq("Example Feed")
|
73
|
+
end
|
64
74
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_rest_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Which Ltd
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-09-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -235,20 +235,6 @@ dependencies:
|
|
235
235
|
- - ">="
|
236
236
|
- !ruby/object:Gem::Version
|
237
237
|
version: '0'
|
238
|
-
- !ruby/object:Gem::Dependency
|
239
|
-
name: patron
|
240
|
-
requirement: !ruby/object:Gem::Requirement
|
241
|
-
requirements:
|
242
|
-
- - ">="
|
243
|
-
- !ruby/object:Gem::Version
|
244
|
-
version: 0.4.9
|
245
|
-
type: :runtime
|
246
|
-
prerelease: false
|
247
|
-
version_requirements: !ruby/object:Gem::Requirement
|
248
|
-
requirements:
|
249
|
-
- - ">="
|
250
|
-
- !ruby/object:Gem::Version
|
251
|
-
version: 0.4.9
|
252
238
|
description: Accessing REST services in an ActiveRecord style
|
253
239
|
email:
|
254
240
|
- swlicensing@which.co.uk
|
@@ -261,6 +247,7 @@ files:
|
|
261
247
|
- ".rspec"
|
262
248
|
- ".simplecov"
|
263
249
|
- ".travis.yml"
|
250
|
+
- CHANGELOG.md
|
264
251
|
- CONTRIBUTING.md
|
265
252
|
- Gemfile
|
266
253
|
- Guardfile
|