hyperclient 0.5.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +8 -16
- data/CHANGELOG.md +13 -0
- data/README.md +67 -8
- data/UPGRADING.md +14 -0
- data/examples/splines_api.rb +16 -1
- data/features/steps/default_config.rb +1 -1
- data/lib/hyperclient.rb +2 -2
- data/lib/hyperclient/entry_point.rb +73 -8
- data/lib/hyperclient/link.rb +41 -42
- data/lib/hyperclient/version.rb +1 -1
- data/test/hyperclient/entry_point_test.rb +104 -8
- data/test/hyperclient/link_test.rb +52 -46
- data/test/hyperclient_test.rb +31 -0
- metadata +2 -3
- data/.rvmrc +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 743f6bc67f84cca3d8e2994ad47a38d7e031a300
|
4
|
+
data.tar.gz: 689b06b2eb057ca7bd28e74071ecca60ba954344
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17ea7ceb37ecc125395b13d37caf7e134b7b9ef1e21ee258a1d92309f2cc3fadbe398916c3642b50cda8ccd62260b57d5eea3b38f786c4c03a2fea5a97f6e1f2
|
7
|
+
data.tar.gz: 1f5b27c757676834dfb1aaa33741b7be19ce09e9822c869f4ecabcaceeaac868799eb96a92e0b4ecdc0290e807a0fc6fff6cba924f2270ef0e01204cb8e08e77
|
data/.rubocop_todo.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
-
# on 2014-
|
2
|
+
# on 2014-10-17 09:13:36 -0400 using RuboCop version 0.26.1.
|
3
3
|
# The point is for the user to remove these configuration records
|
4
4
|
# one by one as the offenses are removed from the code base.
|
5
5
|
# Note that changes in the inspected code, or installation of new
|
@@ -8,26 +8,18 @@
|
|
8
8
|
# Offense count: 1
|
9
9
|
# Configuration parameters: CountComments.
|
10
10
|
Metrics/ClassLength:
|
11
|
-
Max:
|
11
|
+
Max: 129
|
12
12
|
|
13
|
-
# Offense count:
|
14
|
-
|
15
|
-
Max: 8
|
16
|
-
|
17
|
-
# Offense count: 39
|
18
|
-
# Configuration parameters: AllowURI.
|
13
|
+
# Offense count: 72
|
14
|
+
# Configuration parameters: AllowURI, URISchemes.
|
19
15
|
Metrics/LineLength:
|
20
|
-
Max:
|
16
|
+
Max: 140
|
21
17
|
|
22
|
-
# Offense count:
|
18
|
+
# Offense count: 3
|
23
19
|
# Configuration parameters: CountComments.
|
24
20
|
Metrics/MethodLength:
|
25
21
|
Max: 14
|
26
22
|
|
27
|
-
# Offense count: 2
|
28
|
-
Metrics/PerceivedComplexity:
|
29
|
-
Max: 9
|
30
|
-
|
31
23
|
# Offense count: 1
|
32
24
|
Style/AsciiComments:
|
33
25
|
Enabled: false
|
@@ -41,11 +33,11 @@ Style/ClassAndModuleChildren:
|
|
41
33
|
Style/Documentation:
|
42
34
|
Enabled: false
|
43
35
|
|
44
|
-
# Offense count:
|
36
|
+
# Offense count: 2
|
45
37
|
Style/DoubleNegation:
|
46
38
|
Enabled: false
|
47
39
|
|
48
|
-
# Offense count:
|
40
|
+
# Offense count: 5
|
49
41
|
Style/Lambda:
|
50
42
|
Enabled: false
|
51
43
|
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
### Next
|
2
|
+
|
3
|
+
* Your contribution here.
|
4
|
+
|
5
|
+
### 0.6.1 (October 17, 2014)
|
6
|
+
|
7
|
+
This version introduces several backwards incompatible changes. See [UPGRADING](UPGRADING.md) for details.
|
8
|
+
|
9
|
+
* [#51](https://github.com/codegram/hyperclient/issues/51), [#75](https://github.com/codegram/hyperclient/pull/75): Added support for setting headers and overriding or extending the default Faraday connection block before a connection is constructed - [@dblock](https://github.com/dblock).
|
10
|
+
* [#41](https://github.com/codegram/hyperclient/issues/41), [#73](https://github.com/codegram/hyperclient/pull/73): All Link HTTP methods now return a Resource, including `_get`, which has been aliased to `_resource`, `_post`, `_put`, `_patch`, `_head` and `_options` - [@dblock](https://github.com/dblock).
|
11
|
+
* [#72](https://github.com/codegram/hyperclient/pull/72): The default Faraday block now uses `Faraday::Response::RaiseError` and will cause HTTP errors to be raised as exceptions - [@dblock](https://github.com/dblock).
|
12
|
+
* [#77](https://github.com/codegram/hyperclient/pull/77): Added support for templated links with all optional arguments - [@dblock](https://github.com/dblock).
|
13
|
+
|
1
14
|
### 0.5.0 (October 1, 2014)
|
2
15
|
|
3
16
|
This version introduces several backwards incompatible changes. See [UPGRADING](UPGRADING.md) for details.
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Hyperclient is a Hypermedia API client written in Ruby. It fully supports [JSON
|
|
8
8
|
|
9
9
|
## Usage
|
10
10
|
|
11
|
-
The examples in this README use the [Splines Demo API](https://github.com/dblock/grape-with-roar) running [here](https://grape-with-roar.herokuapp.com/api).
|
11
|
+
The examples in this README use the [Splines Demo API](https://github.com/dblock/grape-with-roar) running [here](https://grape-with-roar.herokuapp.com/api). If you're upgrading from a previous version, please make sure to read [UPGRADING](UPGRADING.md).
|
12
12
|
|
13
13
|
### API Client
|
14
14
|
|
@@ -20,15 +20,51 @@ require 'hyperclient'
|
|
20
20
|
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
|
21
21
|
```
|
22
22
|
|
23
|
-
By default, Hyperclient adds `application/json` as `Content-Type` and `Accept` headers. It will also send requests as JSON and parse JSON responses. Specify additional headers or authentication if necessary.
|
23
|
+
By default, Hyperclient adds `application/json` as `Content-Type` and `Accept` headers. It will also send requests as JSON and parse JSON responses. Specify additional headers or authentication if necessary.
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
|
27
|
-
|
28
|
-
api.headers.update('Accept-Encoding' => 'deflate, gzip')
|
26
|
+
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api') do |client|
|
27
|
+
client.headers['Access-Token'] = 'token'
|
29
28
|
end
|
30
29
|
```
|
31
30
|
|
31
|
+
Hyperclient constructs a connection using typical [Faraday](http://github.com/lostisland/faraday) middleware for handling JSON requests and responses. You can specify additional Faraday middleware if necessary.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api') do |client|
|
35
|
+
client.connection do |conn|
|
36
|
+
conn.use Faraday::Request::OAuth
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
You can build a new Faraday connection block without inheriting default middleware by specifying `default: false` in the `connection` block.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api') do |client|
|
45
|
+
client.connection(default: false) do |conn|
|
46
|
+
conn.request :json
|
47
|
+
conn.response :json, content_type: /\bjson$/
|
48
|
+
conn.adapter :net_http
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
You can modify headers or specify authentication after a connection has been created. Hyperclient supports Basic, Token or Digest auth as well as many other Faraday extensions.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
|
57
|
+
api.digest_auth('username', 'password')
|
58
|
+
api.headers.update('Accept-Encoding' => 'deflate, gzip')
|
59
|
+
```
|
60
|
+
|
61
|
+
You can access the Faraday connection directly after it has been created and add middleware to it. As an example, you could use the [faraday-http-cache-middleware](https://github.com/plataformatec/faraday-http-cache).
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
|
65
|
+
api.connection.use :http_cache
|
66
|
+
```
|
67
|
+
|
32
68
|
### Resources and Attributes
|
33
69
|
|
34
70
|
Hyperclient will fetch and discover the resources from your API.
|
@@ -58,6 +94,8 @@ puts "Spline #{spline.uuid} is #{spline.reticulated ? 'reticulated' : 'not retic
|
|
58
94
|
|
59
95
|
Invoking `api.spline(uuid: 'uuid').reticulated` is equivalent to `api._links.spline._expand(uuid: 'uuid')._resource._attributes.reticulated`.
|
60
96
|
|
97
|
+
The client is responsible for supplying all the necessary parameters. Templated links don't do any strict parameter name checking and don't support required vs. optional parameters. Parameters not declared by the API will be dropped and will not have any effect when passed to `_expand`.
|
98
|
+
|
61
99
|
### Curies
|
62
100
|
|
63
101
|
Curies are named tokens that you can define in the document and use to express curie relation URIs in a friendlier, more compact fashion. For example, the demo API contains very long links to images that use an "images" curie. Hyperclient handles curies and resolves these into full links automatically.
|
@@ -117,14 +155,35 @@ spline = api.spline(uuid: 'uuid')
|
|
117
155
|
spline._delete
|
118
156
|
```
|
119
157
|
|
120
|
-
|
158
|
+
HTTP methods always return a new instance of Resource.
|
159
|
+
|
160
|
+
## Testing Using Hyperclient
|
121
161
|
|
122
|
-
You can
|
162
|
+
You can combine RSpec, Faraday::Adapter::Rack and Hyperclient to test your HAL API without having to ever examine the raw JSON response.
|
123
163
|
|
124
164
|
```ruby
|
125
|
-
|
165
|
+
describe Acme::Api do
|
166
|
+
def app
|
167
|
+
Acme::App.instance
|
168
|
+
end
|
169
|
+
|
170
|
+
let(:client) do
|
171
|
+
Hyperclient.new('http://example.org/api') do |client|
|
172
|
+
client.connection(default: false) do |conn|
|
173
|
+
conn.response :json
|
174
|
+
conn.use Faraday::Adapter::Rack, app
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'splines returns 3 splines by default' do
|
180
|
+
expect(client.splines.count).to eq 3
|
181
|
+
end
|
182
|
+
end
|
126
183
|
```
|
127
184
|
|
185
|
+
For a complete example refer to [this Splines Demo API test](https://github.com/dblock/grape-with-roar/blob/master/spec/api/splines_endpoint_with_hyperclient_spec.rb).
|
186
|
+
|
128
187
|
## Reference
|
129
188
|
|
130
189
|
[Hyperclient API Reference](http://rubydoc.org/github/codegram/hyperclient/master/frames).
|
data/UPGRADING.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
Upgrading Hyperclient
|
2
2
|
=====================
|
3
3
|
|
4
|
+
### Upgrading to >= 0.6.0
|
5
|
+
|
6
|
+
#### Changes in HTTP Error Handling
|
7
|
+
|
8
|
+
The default Faraday block now uses `Faraday::Response::RaiseError` and will cause HTTP errors to be raised as exceptions. Older versions of Hyperclient swallowed the error and returned an empty resource. If you relied on checking for an HTTP response `status`, rescue `Faraday::ClientError`.
|
9
|
+
|
10
|
+
#### Changes in Values Returned from HTTP Methods
|
11
|
+
|
12
|
+
The `Link#_get` method has been aliased to `_resource`. All HTTP methods, including `_post`, `_put`, `_delete`, `_patch`, `_options` and `_head` now return instances of Resource. Older versions returned a `Faraday::Response`.
|
13
|
+
|
14
|
+
#### Changes in URI Template Expansion
|
15
|
+
|
16
|
+
A `MissingURITemplateVariablesException` exception will no longer be raised when expanding a link with no arguments. The `Link#_expand` method will now also accept zero arguments and default the variables to `{}`. This enables support for templated links with all optional arguments.
|
17
|
+
|
4
18
|
### Upgrading to >= 0.5.0
|
5
19
|
|
6
20
|
#### Remove Navigational Elements
|
data/examples/splines_api.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'hyperclient'
|
2
2
|
|
3
|
+
# create a new client
|
3
4
|
api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
|
4
5
|
|
6
|
+
# enumerate splines
|
5
7
|
api.splines.each do |spline|
|
6
8
|
puts "#{spline.uuid}"
|
7
9
|
puts " reticulated: #{spline.reticulated ? 'yes' : 'no'}"
|
@@ -14,9 +16,22 @@ end
|
|
14
16
|
|
15
17
|
puts '*' * 10
|
16
18
|
|
17
|
-
|
19
|
+
# retrieve an existing spline
|
20
|
+
spline = api.spline(uuid: 123)
|
18
21
|
puts "Spline #{spline.uuid} is #{spline.reticulated ? 'reticulated' : 'not reticulated'}."
|
19
22
|
|
20
23
|
# puts api._links.spline._expand(uuid: 'uuid')._resource._attributes.reticulated
|
21
24
|
|
22
25
|
# spline.to_h
|
26
|
+
|
27
|
+
# create a new spline
|
28
|
+
spline = api.splines._post(reticulated: true)
|
29
|
+
puts "Created a #{spline.reticulated ? 'reticulated' : 'unreticulated'} spline #{spline.uuid}."
|
30
|
+
|
31
|
+
# update an existing spline
|
32
|
+
spline = api.spline(uuid: 123)._put(reticulated: true)
|
33
|
+
puts "Updated spline #{spline.uuid}, now #{spline.reticulated ? 'reticulated' : 'not reticulated'}."
|
34
|
+
|
35
|
+
# delete an existing spline
|
36
|
+
spline = api.spline(uuid: 123)._delete
|
37
|
+
puts "Deleted spline #{spline.uuid}."
|
@@ -11,7 +11,7 @@ class Spinach::Features::DefaultConfig < Spinach::FeatureSteps
|
|
11
11
|
|
12
12
|
step 'I send some data to the API' do
|
13
13
|
stub_request(:post, 'http://api.example.org/posts')
|
14
|
-
assert_equal 200, api._links.posts._post(title: 'My first blog post').status
|
14
|
+
assert_equal 200, api._links.posts._post(title: 'My first blog post')._response.status
|
15
15
|
end
|
16
16
|
|
17
17
|
step 'it should have been encoded as JSON' do
|
data/lib/hyperclient.rb
CHANGED
@@ -3,6 +3,15 @@ require 'faraday_middleware'
|
|
3
3
|
require_relative '../faraday/connection'
|
4
4
|
|
5
5
|
module Hyperclient
|
6
|
+
# Public: Exception that is raised when trying to modify an
|
7
|
+
# already initialized connection.
|
8
|
+
class ConnectionAlreadyInitializedError < StandardError
|
9
|
+
# Public: Returns a String with the exception message.
|
10
|
+
def message
|
11
|
+
'The connection has already been initialized.'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
# Public: The EntryPoint is the main public API for Hyperclient. It is used to
|
7
16
|
# initialize an API client and setup the configuration.
|
8
17
|
#
|
@@ -10,6 +19,13 @@ module Hyperclient
|
|
10
19
|
#
|
11
20
|
# client = Hyperclient::EntryPoint.new('http://my.api.org')
|
12
21
|
#
|
22
|
+
# client = Hyperclient::EntryPoint.new('http://my.api.org') do |entry_point|
|
23
|
+
# entry_point.connection(default: true) do |conn|
|
24
|
+
# conn.use Faraday::Request::OAuth
|
25
|
+
# end
|
26
|
+
# entry_point.headers['Access-Token'] = 'token'
|
27
|
+
# end
|
28
|
+
#
|
13
29
|
class EntryPoint < Link
|
14
30
|
extend Forwardable
|
15
31
|
# Public: Delegates common methods to be used with the Faraday connection.
|
@@ -18,16 +34,64 @@ module Hyperclient
|
|
18
34
|
# Public: Initializes an EntryPoint.
|
19
35
|
#
|
20
36
|
# url - A String with the entry point of your API.
|
21
|
-
def initialize(url)
|
37
|
+
def initialize(url, &_block)
|
22
38
|
@link = { 'href' => url }
|
23
39
|
@entry_point = self
|
40
|
+
yield self if block_given?
|
24
41
|
end
|
25
42
|
|
26
43
|
# Public: A Faraday connection to use as a HTTP client.
|
27
44
|
#
|
45
|
+
# options - A Hash containing additional options.
|
46
|
+
#
|
47
|
+
# default - Set to true to reuse default Faraday connection options.
|
48
|
+
#
|
28
49
|
# Returns a Faraday::Connection.
|
29
|
-
def connection
|
30
|
-
|
50
|
+
def connection(options = { default: true }, &block)
|
51
|
+
if block_given?
|
52
|
+
fail ConnectionAlreadyInitializedError if @connection
|
53
|
+
if options[:default]
|
54
|
+
@faraday_block = lambda do |conn|
|
55
|
+
default_faraday_block.call conn
|
56
|
+
block.call conn
|
57
|
+
end
|
58
|
+
else
|
59
|
+
@faraday_block = block
|
60
|
+
end
|
61
|
+
else
|
62
|
+
@connection ||= Faraday.new(_url, { headers: headers }, &faraday_block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Public: Set headers.
|
67
|
+
#
|
68
|
+
# value - A Hash containing headers to include with every API request.
|
69
|
+
def headers=(value)
|
70
|
+
fail ConnectionAlreadyInitializedError if @connection
|
71
|
+
@headers = value
|
72
|
+
end
|
73
|
+
|
74
|
+
# Public: Headers included with every API request.
|
75
|
+
#
|
76
|
+
# Returns a Hash.
|
77
|
+
def headers
|
78
|
+
return @connection.headers if @connection
|
79
|
+
@headers ||= default_headers
|
80
|
+
end
|
81
|
+
|
82
|
+
# Public: Faraday block used with every API request.
|
83
|
+
#
|
84
|
+
# Returns a Proc.
|
85
|
+
def faraday_block
|
86
|
+
@faraday_block ||= default_faraday_block
|
87
|
+
end
|
88
|
+
|
89
|
+
# Public: Set a Faraday block to use with every API request.
|
90
|
+
#
|
91
|
+
# value - A Proc accepting a Faraday::Connection.
|
92
|
+
def faraday_block=(value)
|
93
|
+
fail ConnectionAlreadyInitializedError if @connection
|
94
|
+
@faraday_block = value
|
31
95
|
end
|
32
96
|
|
33
97
|
private
|
@@ -42,11 +106,12 @@ module Hyperclient
|
|
42
106
|
#
|
43
107
|
# Returns a block.
|
44
108
|
def default_faraday_block
|
45
|
-
lambda do |
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
109
|
+
lambda do |conn|
|
110
|
+
conn.use Faraday::Response::RaiseError
|
111
|
+
conn.use FaradayMiddleware::FollowRedirects
|
112
|
+
conn.request :json
|
113
|
+
conn.response :json, content_type: /\bjson$/
|
114
|
+
conn.adapter :net_http
|
50
115
|
end
|
51
116
|
end
|
52
117
|
|
data/lib/hyperclient/link.rb
CHANGED
@@ -33,19 +33,14 @@ module Hyperclient
|
|
33
33
|
# uri_variables - The Hash with the variables to expand the URITemplate.
|
34
34
|
#
|
35
35
|
# Returns a new Link with the expanded variables.
|
36
|
-
def _expand(uri_variables)
|
36
|
+
def _expand(uri_variables = {})
|
37
37
|
self.class.new(@key, @link, @entry_point, uri_variables)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Public: Returns the url of the Link.
|
41
|
-
#
|
42
|
-
# Raises MissingURITemplateVariables if the Link is templated but there are
|
43
|
-
# no uri variables to expand it.
|
44
41
|
def _url
|
45
42
|
return @link['href'] unless _templated?
|
46
|
-
|
47
|
-
|
48
|
-
@url ||= _uri_template.expand(@uri_variables)
|
43
|
+
@url ||= _uri_template.expand(@uri_variables || {})
|
49
44
|
end
|
50
45
|
|
51
46
|
# Public: Returns an array of variables from the URITemplate.
|
@@ -86,61 +81,74 @@ module Hyperclient
|
|
86
81
|
end
|
87
82
|
|
88
83
|
# Public: Returns the Resource which the Link is pointing to.
|
89
|
-
def
|
90
|
-
@resource
|
91
|
-
response =
|
92
|
-
|
93
|
-
if response.success?
|
94
|
-
Resource.new(response.body, @entry_point, response)
|
95
|
-
else
|
96
|
-
Resource.new(nil, @entry_point, response)
|
84
|
+
def _get
|
85
|
+
@resource = begin
|
86
|
+
response = Futuroscope::Future.new do
|
87
|
+
_connection.get(_url)
|
97
88
|
end
|
89
|
+
Resource.new(response.body, @entry_point, response)
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
101
|
-
def
|
102
|
-
@
|
93
|
+
def _resource
|
94
|
+
@resource || _get
|
103
95
|
end
|
104
96
|
|
105
|
-
def
|
106
|
-
|
107
|
-
_connection.get(_url)
|
108
|
-
end
|
97
|
+
def _connection
|
98
|
+
@entry_point.connection
|
109
99
|
end
|
110
100
|
|
111
101
|
def _options
|
112
|
-
|
113
|
-
|
102
|
+
@resource = begin
|
103
|
+
response = Futuroscope::Future.new do
|
104
|
+
_connection.run_request(:options, _url, nil, nil)
|
105
|
+
end
|
106
|
+
Resource.new(response.body, @entry_point, response)
|
114
107
|
end
|
115
108
|
end
|
116
109
|
|
117
110
|
def _head
|
118
|
-
|
119
|
-
|
111
|
+
@resource = begin
|
112
|
+
response = Futuroscope::Future.new do
|
113
|
+
_connection.head(_url)
|
114
|
+
end
|
115
|
+
Resource.new(response.body, @entry_point, response)
|
120
116
|
end
|
121
117
|
end
|
122
118
|
|
123
119
|
def _delete
|
124
|
-
|
125
|
-
|
120
|
+
@resource = begin
|
121
|
+
response = Futuroscope::Future.new do
|
122
|
+
_connection.delete(_url)
|
123
|
+
end
|
124
|
+
Resource.new(response.body, @entry_point, response)
|
126
125
|
end
|
127
126
|
end
|
128
127
|
|
129
128
|
def _post(params = {})
|
130
|
-
|
131
|
-
|
129
|
+
@resource = begin
|
130
|
+
response = Futuroscope::Future.new do
|
131
|
+
_connection.post(_url, params)
|
132
|
+
end
|
133
|
+
Resource.new(response.body, @entry_point, response)
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
135
137
|
def _put(params = {})
|
136
|
-
|
137
|
-
|
138
|
+
@resource = begin
|
139
|
+
response = Futuroscope::Future.new do
|
140
|
+
_connection.put(_url, params)
|
141
|
+
end
|
142
|
+
Resource.new(response.body, @entry_point, response)
|
138
143
|
end
|
139
144
|
end
|
140
145
|
|
141
146
|
def _patch(params = {})
|
142
|
-
|
143
|
-
|
147
|
+
@resource = begin
|
148
|
+
response = Futuroscope::Future.new do
|
149
|
+
_connection.patch(_url, params)
|
150
|
+
end
|
151
|
+
Resource.new(response.body, @entry_point, response)
|
144
152
|
end
|
145
153
|
end
|
146
154
|
|
@@ -191,13 +199,4 @@ module Hyperclient
|
|
191
199
|
@uri_template ||= URITemplate.new(@link['href'])
|
192
200
|
end
|
193
201
|
end
|
194
|
-
|
195
|
-
# Public: Exception that is raised when building a templated Link without uri
|
196
|
-
# variables.
|
197
|
-
class MissingURITemplateVariablesException < StandardError
|
198
|
-
# Public: Returns a String with the exception message.
|
199
|
-
def message
|
200
|
-
'The URL to this links is templated, but no variables where given.'
|
201
|
-
end
|
202
|
-
end
|
203
202
|
end
|
data/lib/hyperclient/version.rb
CHANGED
@@ -3,8 +3,76 @@ require 'hyperclient/entry_point'
|
|
3
3
|
|
4
4
|
module Hyperclient
|
5
5
|
describe EntryPoint do
|
6
|
+
describe 'default' do
|
7
|
+
let(:entry_point) do
|
8
|
+
EntryPoint.new 'http://my.api.org'
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'connection' do
|
12
|
+
it 'creates a Faraday connection with the entry point url' do
|
13
|
+
entry_point.connection.url_prefix.to_s.must_equal 'http://my.api.org/'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'creates a Faraday connection with the default headers' do
|
17
|
+
entry_point.headers['Content-Type'].must_equal 'application/json'
|
18
|
+
entry_point.headers['Accept'].must_equal 'application/json'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can update headers after a connection has been constructed' do
|
22
|
+
entry_point.connection.must_be_kind_of Faraday::Connection
|
23
|
+
entry_point.headers.update('Content-Type' => 'application/foobar')
|
24
|
+
entry_point.headers['Content-Type'].must_equal 'application/foobar'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can insert additional middleware after a connection has been constructed' do
|
28
|
+
entry_point.connection.must_be_kind_of Faraday::Connection
|
29
|
+
entry_point.connection.use :instrumentation
|
30
|
+
handlers = entry_point.connection.builder.handlers
|
31
|
+
handlers.must_include FaradayMiddleware::Instrumentation
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'creates a Faraday connection with the default block' do
|
35
|
+
handlers = entry_point.connection.builder.handlers
|
36
|
+
handlers.must_include Faraday::Response::RaiseError
|
37
|
+
handlers.must_include FaradayMiddleware::FollowRedirects
|
38
|
+
handlers.must_include FaradayMiddleware::EncodeJson
|
39
|
+
handlers.must_include FaradayMiddleware::ParseJson
|
40
|
+
handlers.must_include Faraday::Adapter::NetHttp
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises a ConnectionAlreadyInitializedError if attempting to modify headers' do
|
44
|
+
entry_point.connection.must_be_kind_of Faraday::Connection
|
45
|
+
lambda { entry_point.headers = {} }.must_raise ConnectionAlreadyInitializedError
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises a ConnectionAlreadyInitializedError if attempting to modify the faraday block' do
|
49
|
+
entry_point.connection.must_be_kind_of Faraday::Connection
|
50
|
+
lambda { entry_point.connection {} }.must_raise ConnectionAlreadyInitializedError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'initialize' do
|
55
|
+
it 'sets a Link with the entry point url' do
|
56
|
+
entry_point._url.must_equal 'http://my.api.org'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'custom' do
|
6
63
|
let(:entry_point) do
|
7
|
-
EntryPoint.new 'http://my.api.org'
|
64
|
+
EntryPoint.new 'http://my.api.org' do |entry_point|
|
65
|
+
entry_point.connection(default: false) do |conn|
|
66
|
+
conn.request :json
|
67
|
+
conn.response :json, content_type: /\bjson$/
|
68
|
+
conn.adapter :net_http
|
69
|
+
end
|
70
|
+
|
71
|
+
entry_point.headers = {
|
72
|
+
'Content-Type' => 'application/foobar',
|
73
|
+
'Accept' => 'application/foobar'
|
74
|
+
}
|
75
|
+
end
|
8
76
|
end
|
9
77
|
|
10
78
|
describe 'connection' do
|
@@ -12,23 +80,51 @@ module Hyperclient
|
|
12
80
|
entry_point.connection.url_prefix.to_s.must_equal 'http://my.api.org/'
|
13
81
|
end
|
14
82
|
|
15
|
-
it 'creates a Faraday connection with
|
16
|
-
entry_point.headers['Content-Type'].must_equal 'application/
|
17
|
-
entry_point.headers['Accept'].must_equal 'application/
|
83
|
+
it 'creates a Faraday connection with non-default headers' do
|
84
|
+
entry_point.headers['Content-Type'].must_equal 'application/foobar'
|
85
|
+
entry_point.headers['Accept'].must_equal 'application/foobar'
|
18
86
|
end
|
19
87
|
|
20
88
|
it 'creates a Faraday connection with the default block' do
|
21
89
|
handlers = entry_point.connection.builder.handlers
|
22
|
-
handlers.
|
90
|
+
handlers.wont_include Faraday::Response::RaiseError
|
91
|
+
handlers.wont_include FaradayMiddleware::FollowRedirects
|
23
92
|
handlers.must_include FaradayMiddleware::EncodeJson
|
24
93
|
handlers.must_include FaradayMiddleware::ParseJson
|
25
94
|
handlers.must_include Faraday::Adapter::NetHttp
|
26
95
|
end
|
27
96
|
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'inherited' do
|
100
|
+
let(:entry_point) do
|
101
|
+
EntryPoint.new 'http://my.api.org' do |entry_point|
|
102
|
+
entry_point.connection(default: true) do |conn|
|
103
|
+
conn.use Faraday::Request::OAuth
|
104
|
+
end
|
105
|
+
entry_point.headers['Access-Token'] = 'token'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'connection' do
|
110
|
+
it 'creates a Faraday connection with the default and additional headers' do
|
111
|
+
entry_point.headers['Content-Type'].must_equal 'application/json'
|
112
|
+
entry_point.headers['Accept'].must_equal 'application/json'
|
113
|
+
entry_point.headers['Access-Token'].must_equal 'token'
|
114
|
+
end
|
28
115
|
|
29
|
-
|
30
|
-
|
31
|
-
|
116
|
+
it 'creates a Faraday connection with the entry point url' do
|
117
|
+
entry_point.connection.url_prefix.to_s.must_equal 'http://my.api.org/'
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'creates a Faraday connection with the default block plus any additional handlers' do
|
121
|
+
handlers = entry_point.connection.builder.handlers
|
122
|
+
handlers.must_include Faraday::Request::OAuth
|
123
|
+
handlers.must_include Faraday::Response::RaiseError
|
124
|
+
handlers.must_include FaradayMiddleware::FollowRedirects
|
125
|
+
handlers.must_include FaradayMiddleware::EncodeJson
|
126
|
+
handlers.must_include FaradayMiddleware::ParseJson
|
127
|
+
handlers.must_include Faraday::Adapter::NetHttp
|
32
128
|
end
|
33
129
|
end
|
34
130
|
end
|
@@ -51,24 +51,38 @@ module Hyperclient
|
|
51
51
|
end
|
52
52
|
|
53
53
|
describe '_expand' do
|
54
|
-
|
55
|
-
|
54
|
+
describe 'required argument' do
|
55
|
+
it 'builds a Link with the templated URI representation' do
|
56
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
57
|
+
link._expand(id: '1')._url.must_equal '/orders/1'
|
58
|
+
end
|
56
59
|
|
57
|
-
|
58
|
-
|
60
|
+
it 'expands an uri template without variables' do
|
61
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
62
|
+
link._expand._url.must_equal '/orders/'
|
63
|
+
link._url.must_equal '/orders/'
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
|
-
|
62
|
-
|
63
|
-
|
67
|
+
describe 'query string argument' do
|
68
|
+
it 'builds a Link with the templated URI representation' do
|
69
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
70
|
+
link._expand(id: '1')._url.must_equal '/orders?id=1'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'expands an uri template without variables' do
|
74
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
75
|
+
link._expand._url.must_equal '/orders'
|
76
|
+
link._url.must_equal '/orders'
|
77
|
+
end
|
64
78
|
end
|
65
79
|
end
|
66
80
|
|
67
81
|
describe '_url' do
|
68
|
-
it '
|
82
|
+
it 'expands an uri template without variables' do
|
69
83
|
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
70
84
|
|
71
|
-
|
85
|
+
link._url.must_equal '/orders'
|
72
86
|
end
|
73
87
|
|
74
88
|
it 'expands an uri template with variables' do
|
@@ -91,23 +105,10 @@ module Hyperclient
|
|
91
105
|
|
92
106
|
describe '_resource' do
|
93
107
|
it 'builds a resource with the link href representation' do
|
94
|
-
|
95
|
-
|
96
|
-
Resource.expects(:new).with({}, entry_point, mock_response)
|
97
|
-
|
98
|
-
link = Link.new('key', { 'href' => '/' }, entry_point)
|
99
|
-
link.expects(:_get).returns(mock_response)
|
100
|
-
|
101
|
-
link._resource
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'has an empty body when the response fails' do
|
105
|
-
mock_response = mock(success?: false)
|
106
|
-
|
107
|
-
Resource.expects(:new).with(nil, entry_point, mock_response)
|
108
|
+
Resource.expects(:new)
|
108
109
|
|
109
110
|
link = Link.new('key', { 'href' => '/' }, entry_point)
|
110
|
-
|
111
|
+
stub_request(:get, 'http://api.example.org/').to_return(body: {})
|
111
112
|
|
112
113
|
link._resource
|
113
114
|
end
|
@@ -123,8 +124,15 @@ module Hyperclient
|
|
123
124
|
it 'sends a GET request with the link url' do
|
124
125
|
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
125
126
|
|
126
|
-
|
127
|
-
link._get.
|
127
|
+
stub_request(:get, 'http://api.example.org/productions/1').to_return(body: nil)
|
128
|
+
link._get.must_be_kind_of Resource
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'raises exceptions by default' do
|
132
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
133
|
+
|
134
|
+
stub_request(:get, 'http://api.example.org/productions/1').to_return(status: 400)
|
135
|
+
lambda { link._get }.must_raise Faraday::ClientError
|
128
136
|
end
|
129
137
|
end
|
130
138
|
|
@@ -132,26 +140,24 @@ module Hyperclient
|
|
132
140
|
it 'sends a OPTIONS request with the link url' do
|
133
141
|
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
134
142
|
|
135
|
-
|
136
|
-
link._options.
|
143
|
+
stub_request(:options, 'http://api.example.org/productions/1').to_return(body: nil)
|
144
|
+
link._options.must_be_kind_of Resource
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
140
148
|
describe '_head' do
|
141
149
|
it 'sends a HEAD request with the link url' do
|
142
150
|
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
143
|
-
|
144
|
-
|
145
|
-
link._head.inspect
|
151
|
+
stub_request(:head, 'http://api.example.org/productions/1').to_return(body: nil)
|
152
|
+
link._head.must_be_kind_of Resource
|
146
153
|
end
|
147
154
|
end
|
148
155
|
|
149
156
|
describe '_delete' do
|
150
157
|
it 'sends a DELETE request with the link url' do
|
151
158
|
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
152
|
-
|
153
|
-
|
154
|
-
link._delete.inspect
|
159
|
+
stub_request(:delete, 'http://api.example.org/productions/1').to_return(body: nil)
|
160
|
+
link._delete.must_be_kind_of Resource
|
155
161
|
end
|
156
162
|
end
|
157
163
|
|
@@ -159,13 +165,13 @@ module Hyperclient
|
|
159
165
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
160
166
|
|
161
167
|
it 'sends a POST request with the link url and params' do
|
162
|
-
|
163
|
-
link._post('foo' => 'bar').
|
168
|
+
stub_request(:post, 'http://api.example.org/productions/1').to_return(body: nil)
|
169
|
+
link._post('foo' => 'bar').must_be_kind_of Resource
|
164
170
|
end
|
165
171
|
|
166
172
|
it 'defaults params to an empty hash' do
|
167
|
-
|
168
|
-
link._post.
|
173
|
+
stub_request(:post, 'http://api.example.org/productions/1').to_return(body: nil)
|
174
|
+
link._post.must_be_kind_of Resource
|
169
175
|
end
|
170
176
|
end
|
171
177
|
|
@@ -173,13 +179,13 @@ module Hyperclient
|
|
173
179
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
174
180
|
|
175
181
|
it 'sends a PUT request with the link url and params' do
|
176
|
-
|
177
|
-
link._put('foo' => 'bar').
|
182
|
+
stub_request(:put, 'http://api.example.org/productions/1').with(body: '{"foo":"bar"}').to_return(body: nil)
|
183
|
+
link._put('foo' => 'bar').must_be_kind_of Resource
|
178
184
|
end
|
179
185
|
|
180
186
|
it 'defaults params to an empty hash' do
|
181
|
-
|
182
|
-
link._put.
|
187
|
+
stub_request(:put, 'http://api.example.org/productions/1').to_return(body: nil)
|
188
|
+
link._put.must_be_kind_of Resource
|
183
189
|
end
|
184
190
|
end
|
185
191
|
|
@@ -187,13 +193,13 @@ module Hyperclient
|
|
187
193
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
188
194
|
|
189
195
|
it 'sends a PATCH request with the link url and params' do
|
190
|
-
|
191
|
-
link._patch('foo' => 'bar').
|
196
|
+
stub_request(:patch, 'http://api.example.org/productions/1').with(body: '{"foo":"bar"}').to_return(body: nil)
|
197
|
+
link._patch('foo' => 'bar').must_be_kind_of Resource
|
192
198
|
end
|
193
199
|
|
194
200
|
it 'defaults params to an empty hash' do
|
195
|
-
|
196
|
-
link._patch.
|
201
|
+
stub_request(:patch, 'http://api.example.org/productions/1').to_return(body: nil)
|
202
|
+
link._patch.must_be_kind_of Resource
|
197
203
|
end
|
198
204
|
end
|
199
205
|
|
data/test/hyperclient_test.rb
CHANGED
@@ -8,5 +8,36 @@ describe Hyperclient do
|
|
8
8
|
|
9
9
|
Hyperclient.new('http://api.example.org')
|
10
10
|
end
|
11
|
+
|
12
|
+
describe 'with an optional block' do
|
13
|
+
let(:client) do
|
14
|
+
Hyperclient.new('http://api.example.org') do |client|
|
15
|
+
client.connection(default: true) do |conn|
|
16
|
+
conn.use Faraday::Request::OAuth
|
17
|
+
end
|
18
|
+
client.headers['Access-Token'] = 'token'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'creates a Faraday connection with the default and additional headers' do
|
23
|
+
client.headers['Content-Type'].must_equal 'application/json'
|
24
|
+
client.headers['Accept'].must_equal 'application/json'
|
25
|
+
client.headers['Access-Token'].must_equal 'token'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'creates a Faraday connection with the entry point url' do
|
29
|
+
client.connection.url_prefix.to_s.must_equal 'http://api.example.org/'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'creates a Faraday connection with the default block plus any additional handlers' do
|
33
|
+
handlers = client.connection.builder.handlers
|
34
|
+
handlers.must_include Faraday::Request::OAuth
|
35
|
+
handlers.must_include Faraday::Response::RaiseError
|
36
|
+
handlers.must_include FaradayMiddleware::FollowRedirects
|
37
|
+
handlers.must_include FaradayMiddleware::EncodeJson
|
38
|
+
handlers.must_include FaradayMiddleware::ParseJson
|
39
|
+
handlers.must_include Faraday::Adapter::NetHttp
|
40
|
+
end
|
41
|
+
end
|
11
42
|
end
|
12
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyperclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oriol Gual
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -188,7 +188,6 @@ files:
|
|
188
188
|
- .gitignore
|
189
189
|
- .rubocop.yml
|
190
190
|
- .rubocop_todo.yml
|
191
|
-
- .rvmrc
|
192
191
|
- .travis.yml
|
193
192
|
- .yardopts
|
194
193
|
- CHANGELOG.md
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm use --create 2.0.0@hyperclient
|