hyperclient 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +0 -1
- data/.rvmrc +1 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +96 -0
- data/Guardfile +7 -0
- data/Rakefile +5 -1
- data/Readme.md +19 -9
- data/features/api_navigation.feature +23 -0
- data/features/default_config.feature +19 -0
- data/features/steps/api_navigation.rb +33 -0
- data/features/steps/default_config.rb +29 -0
- data/features/support/api.rb +24 -0
- data/features/support/env.rb +4 -0
- data/features/support/fixtures.rb +43 -0
- data/hyperclient.gemspec +9 -7
- data/lib/faraday/connection.rb +17 -0
- data/lib/faraday/request/digest_authentication.rb +83 -0
- data/lib/hyperclient/attributes.rb +5 -1
- data/lib/hyperclient/collection.rb +7 -1
- data/lib/hyperclient/entry_point.rb +37 -27
- data/lib/hyperclient/link.rb +41 -16
- data/lib/hyperclient/link_collection.rb +1 -0
- data/lib/hyperclient/resource.rb +8 -3
- data/lib/hyperclient/version.rb +1 -1
- data/lib/hyperclient.rb +11 -3
- data/test/faraday/connection_test.rb +29 -0
- data/test/faraday/digest_authentication_test.rb +41 -0
- data/test/hyperclient/entry_point_test.rb +15 -32
- data/test/hyperclient/link_test.rb +93 -12
- data/test/hyperclient_test.rb +12 -0
- data/test/test_helper.rb +1 -1
- metadata +119 -67
- data/lib/hyperclient/http.rb +0 -165
- data/test/hyperclient/http_test.rb +0 -214
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use --create 1.9.3
|
1
|
+
rvm use --create 1.9.3@hyperclient
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/rubyworks/yard-tomdoc
|
3
|
+
revision: caee83fb8b068fef81068e00dc8d1245354536f1
|
4
|
+
specs:
|
5
|
+
yard-tomdoc (0.5.0)
|
6
|
+
tomparse
|
7
|
+
yard
|
8
|
+
|
9
|
+
PATH
|
10
|
+
remote: .
|
11
|
+
specs:
|
12
|
+
hyperclient (0.3.0)
|
13
|
+
faraday (~> 0.8)
|
14
|
+
faraday_middleware (~> 0.9)
|
15
|
+
net-http-digest_auth (~> 1.2)
|
16
|
+
uri_template (~> 0.5)
|
17
|
+
|
18
|
+
GEM
|
19
|
+
remote: https://rubygems.org/
|
20
|
+
specs:
|
21
|
+
addressable (2.2.8)
|
22
|
+
ansi (1.4.2)
|
23
|
+
coderay (1.0.6)
|
24
|
+
colorize (0.5.8)
|
25
|
+
crack (0.3.1)
|
26
|
+
faraday (0.8.4)
|
27
|
+
multipart-post (~> 1.1)
|
28
|
+
faraday_middleware (0.9.0)
|
29
|
+
faraday (>= 0.7.4, < 0.9)
|
30
|
+
ffi (1.0.11)
|
31
|
+
gherkin-ruby (0.2.1)
|
32
|
+
growl (1.0.3)
|
33
|
+
guard (1.0.3)
|
34
|
+
ffi (>= 0.5.0)
|
35
|
+
thor (>= 0.14.6)
|
36
|
+
guard-minitest (0.5.0)
|
37
|
+
guard (>= 0.4)
|
38
|
+
guard-spinach (0.0.1.1)
|
39
|
+
guard
|
40
|
+
spinach
|
41
|
+
metaclass (0.0.1)
|
42
|
+
method_source (0.7.1)
|
43
|
+
minitest (3.4.0)
|
44
|
+
mocha (0.13.1)
|
45
|
+
metaclass (~> 0.0.1)
|
46
|
+
multi_json (1.3.6)
|
47
|
+
multipart-post (1.1.5)
|
48
|
+
net-http-digest_auth (1.2.1)
|
49
|
+
pry (0.9.9.6)
|
50
|
+
coderay (~> 1.0.5)
|
51
|
+
method_source (~> 0.7.1)
|
52
|
+
slop (>= 2.4.4, < 3)
|
53
|
+
rack (1.4.1)
|
54
|
+
rack-test (0.6.2)
|
55
|
+
rack (>= 1.0)
|
56
|
+
rake (0.9.2.2)
|
57
|
+
redcarpet (2.1.1)
|
58
|
+
simplecov (0.6.4)
|
59
|
+
multi_json (~> 1.0)
|
60
|
+
simplecov-html (~> 0.5.3)
|
61
|
+
simplecov-html (0.5.3)
|
62
|
+
slop (2.4.4)
|
63
|
+
spinach (0.7.0)
|
64
|
+
colorize
|
65
|
+
gherkin-ruby (~> 0.2.0)
|
66
|
+
thor (0.15.2)
|
67
|
+
tomparse (0.2.1)
|
68
|
+
turn (0.9.5)
|
69
|
+
ansi
|
70
|
+
uri_template (0.5.1)
|
71
|
+
webmock (1.8.7)
|
72
|
+
addressable (>= 2.2.7)
|
73
|
+
crack (>= 0.1.7)
|
74
|
+
yard (0.8.2.1)
|
75
|
+
|
76
|
+
PLATFORMS
|
77
|
+
ruby
|
78
|
+
|
79
|
+
DEPENDENCIES
|
80
|
+
growl
|
81
|
+
guard
|
82
|
+
guard-minitest
|
83
|
+
guard-spinach
|
84
|
+
hyperclient!
|
85
|
+
minitest (~> 3.4.0)
|
86
|
+
mocha (~> 0.13)
|
87
|
+
pry
|
88
|
+
rack-test (~> 0.6)
|
89
|
+
rake
|
90
|
+
redcarpet
|
91
|
+
simplecov
|
92
|
+
spinach
|
93
|
+
turn (~> 0.9)
|
94
|
+
webmock (~> 1.8)
|
95
|
+
yard (~> 0.8)
|
96
|
+
yard-tomdoc!
|
data/Guardfile
CHANGED
@@ -4,3 +4,10 @@ guard 'minitest' do
|
|
4
4
|
watch(%r|^(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
|
5
5
|
watch(%r|^test/test_helper\.rb|) { "test" }
|
6
6
|
end
|
7
|
+
|
8
|
+
guard 'spinach' do
|
9
|
+
watch(%r|^features/(.*)\.feature|)
|
10
|
+
watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m|
|
11
|
+
"features/#{m[1]}#{m[2]}.feature"
|
12
|
+
end
|
13
|
+
end
|
data/Rakefile
CHANGED
data/Readme.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Hyperclient
|
2
2
|
[](http://travis-ci.org/codegram/hyperclient)
|
3
3
|
[](http://gemnasium.com/codegram/hyperclient)
|
4
|
-
[](https://codeclimate.com/github/codegram/hyperclient)
|
5
5
|
|
6
6
|
Hyperclient is a Ruby Hypermedia API client written in Ruby.
|
7
7
|
|
@@ -14,14 +14,15 @@ Hyperclient is a Ruby Hypermedia API client written in Ruby.
|
|
14
14
|
Example API client:
|
15
15
|
|
16
16
|
````ruby
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
api = Hyperclient::EntryPoint.new('http://myapp.com/api', options)
|
17
|
+
api = Hyperclient.new('http://myapp.com/api').tap do |api|
|
18
|
+
api.digest_auth('user', 'password')
|
19
|
+
api.headers.merge({'accept-encoding' => 'deflate, gzip'})
|
20
|
+
end
|
23
21
|
````
|
24
22
|
|
23
|
+
By default, Hyperclient adds `application/json` as `Content-Type` and `Accept`
|
24
|
+
headers. It will also sent requests as JSON and parse JSON responses.
|
25
|
+
|
25
26
|
[More examples][examples]
|
26
27
|
|
27
28
|
## HAL
|
@@ -96,7 +97,7 @@ api.embedded.posts.first.attributes
|
|
96
97
|
OK, navigating an API is really cool, but you may want to actually do something
|
97
98
|
with it, right?
|
98
99
|
|
99
|
-
Hyperclient uses [
|
100
|
+
Hyperclient uses [Faraday][faraday] under the hood to perform HTTP calls. You can
|
100
101
|
call any valid HTTP method on any Resource:
|
101
102
|
|
102
103
|
````ruby
|
@@ -104,6 +105,7 @@ post = api.embedded.posts.first
|
|
104
105
|
post.get
|
105
106
|
post.head
|
106
107
|
post.put({title: 'New title'})
|
108
|
+
post.patch({title: 'New title'})
|
107
109
|
post.delete
|
108
110
|
post.options
|
109
111
|
|
@@ -118,6 +120,14 @@ api.links.post.expand(:id => 3).first
|
|
118
120
|
# => #<Resource ...>
|
119
121
|
````
|
120
122
|
|
123
|
+
You can access the Faraday connection (to add middlewares or do whatever
|
124
|
+
you want) by calling `connection` on the entry point. As an example, you could use the [faraday-http-cache-middleware](https://github.com/plataformatec/faraday-http-cache)
|
125
|
+
:
|
126
|
+
|
127
|
+
````ruby
|
128
|
+
api.connection.use :http_cache
|
129
|
+
````
|
130
|
+
|
121
131
|
## Other
|
122
132
|
|
123
133
|
There's also a PHP library named [HyperClient](https://github.com/FoxyCart/HyperClient), if that's what you were looking for :)
|
@@ -151,7 +161,7 @@ MIT License. Copyright 2012 [Codegram Technologies][codegram]
|
|
151
161
|
[contributors]: https://github.com/codegram/hyperclient/contributors
|
152
162
|
[codegram]: http://codegram.com
|
153
163
|
[documentup]: http://codegram.github.com/hyperclient
|
154
|
-
[
|
164
|
+
[faraday]: http://github.com/lostisland/faraday
|
155
165
|
[examples]: http://github.com/codegram/hyperclient/tree/master/examples
|
156
166
|
[enumerable]: http://ruby-doc.org/core-1.9.3/Enumerable.html
|
157
167
|
[rdoc]: http://rubydoc.org/github/codegram/hyperclient/master/frames
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Feature: API navigation
|
2
|
+
In order to get the data from my API
|
3
|
+
As a user
|
4
|
+
I want to navigate through the API
|
5
|
+
|
6
|
+
Scenario: Links
|
7
|
+
When I connect to the API
|
8
|
+
Then I should be able to navigate to posts and authors
|
9
|
+
|
10
|
+
Scenario: Templated links
|
11
|
+
Given I connect to the API
|
12
|
+
When I search for a post with a templated link
|
13
|
+
Then the API should receive the request with all the params
|
14
|
+
|
15
|
+
Scenario: Attributes
|
16
|
+
Given I connect to the API
|
17
|
+
When I load a single post
|
18
|
+
Then I should be able to access it's title and body
|
19
|
+
|
20
|
+
Scenario: Embedded resources
|
21
|
+
Given I connect to the API
|
22
|
+
When I load a single post
|
23
|
+
Then I should also be able to access it's embedded comments
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Default config
|
2
|
+
In order to use HAL JSON apis
|
3
|
+
As a user
|
4
|
+
I want to make sure the default config is working
|
5
|
+
|
6
|
+
Scenario: JSON headers
|
7
|
+
Given I use the default hyperclient config
|
8
|
+
When I connect to the API
|
9
|
+
Then the request should have been sent with the correct JSON headers
|
10
|
+
|
11
|
+
Scenario: Send JSON data
|
12
|
+
Given I use the default hyperclient config
|
13
|
+
When I send some data to the API
|
14
|
+
Then it should have been encoded as JSON
|
15
|
+
|
16
|
+
Scenario: Parse JSON data
|
17
|
+
Given I use the default hyperclient config
|
18
|
+
When I get some data from the API
|
19
|
+
Then it should have been parsed as JSON
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Spinach::Features::ApiNavigation < Spinach::FeatureSteps
|
2
|
+
include API
|
3
|
+
|
4
|
+
step 'I should be able to navigate to posts and authors' do
|
5
|
+
api.links.posts.resource
|
6
|
+
api.links['api:authors'].resource
|
7
|
+
|
8
|
+
assert_requested :get, 'http://api.example.org/posts'
|
9
|
+
assert_requested :get, 'http://api.example.org/authors'
|
10
|
+
end
|
11
|
+
|
12
|
+
step 'I search for a post with a templated link' do
|
13
|
+
api.links.search.expand(q: 'something').resource
|
14
|
+
end
|
15
|
+
|
16
|
+
step 'the API should receive the request with all the params' do
|
17
|
+
assert_requested :get, 'http://api.example.org/search?q=something'
|
18
|
+
end
|
19
|
+
|
20
|
+
step 'I load a single post' do
|
21
|
+
@post = api.links.posts.links.last_post
|
22
|
+
end
|
23
|
+
|
24
|
+
step 'I should be able to access it\'s title and body' do
|
25
|
+
@post.attributes.title.wont_equal nil
|
26
|
+
@post.attributes.body.wont_equal nil
|
27
|
+
end
|
28
|
+
|
29
|
+
step 'I should also be able to access it\'s embedded comments' do
|
30
|
+
comment = @post.embedded.comments.first
|
31
|
+
comment.attributes.title.wont_equal nil
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Spinach::Features::DefaultConfig < Spinach::FeatureSteps
|
2
|
+
include API
|
3
|
+
|
4
|
+
step 'I use the default hyperclient config' do
|
5
|
+
@api = Hyperclient.new('http://api.example.org')
|
6
|
+
end
|
7
|
+
|
8
|
+
step 'the request should have been sent with the correct JSON headers' do
|
9
|
+
assert_requested :get, 'api.example.org', headers: {'Content-Type' => 'application/json', 'Accept' => 'application/json'}
|
10
|
+
end
|
11
|
+
|
12
|
+
step 'I send some data to the API' do
|
13
|
+
stub_request(:post, "http://api.example.org/posts")
|
14
|
+
api.links.posts.post({title: 'My first blog post'})
|
15
|
+
end
|
16
|
+
|
17
|
+
step 'it should have been encoded as JSON' do
|
18
|
+
assert_requested :post, 'api.example.org/posts', body: '{"title":"My first blog post"}'
|
19
|
+
end
|
20
|
+
|
21
|
+
step 'I get some data from the API' do
|
22
|
+
@posts = api.links.posts
|
23
|
+
end
|
24
|
+
|
25
|
+
step 'it should have been parsed as JSON' do
|
26
|
+
@posts.attributes.total_posts.to_i.must_equal 9
|
27
|
+
@posts.attributes['total_posts'].to_i.must_equal 9
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'fixtures'
|
2
|
+
module API
|
3
|
+
include Spinach::DSL
|
4
|
+
include WebMock::API
|
5
|
+
include Spinach::Fixtures
|
6
|
+
|
7
|
+
before do
|
8
|
+
stub_request(:any, %r{api.example.org*}).to_return(body: root_response, headers:{'Content-Type' => 'application/json'})
|
9
|
+
stub_request(:get, 'api.example.org/posts').to_return(body: posts_response, headers: {'Content-Type' => 'application/json'})
|
10
|
+
stub_request(:get, 'api.example.org/posts/1').to_return(body: post_response, headers: {'Content-Type' => 'application/json'})
|
11
|
+
end
|
12
|
+
|
13
|
+
def api
|
14
|
+
@api ||= Hyperclient.new('http://api.example.org')
|
15
|
+
end
|
16
|
+
|
17
|
+
step 'I connect to the API' do
|
18
|
+
api.links
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
WebMock.reset!
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Spinach
|
4
|
+
module Fixtures
|
5
|
+
def root_response
|
6
|
+
'{
|
7
|
+
"_links": {
|
8
|
+
"self": { "href": "/" },
|
9
|
+
"posts": { "href": "/posts" },
|
10
|
+
"search": { "href": "/search{?q}", "templated": true },
|
11
|
+
"api:authors": { "href": "/authors" }
|
12
|
+
}
|
13
|
+
}'
|
14
|
+
end
|
15
|
+
|
16
|
+
def posts_response
|
17
|
+
'{
|
18
|
+
"_links": {
|
19
|
+
"self": { "href": "/posts" },
|
20
|
+
"last_post": {"href": "/posts/1"}
|
21
|
+
},
|
22
|
+
"total_posts": "9"
|
23
|
+
}'
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_response
|
27
|
+
'{
|
28
|
+
"_links": {
|
29
|
+
"self": { "href": "/posts/1" }
|
30
|
+
},
|
31
|
+
"title": "My first blog post",
|
32
|
+
"body": "Lorem ipsum dolor sit amet",
|
33
|
+
"_embedded": {
|
34
|
+
"comments": [
|
35
|
+
{
|
36
|
+
"title": "Some comment"
|
37
|
+
}
|
38
|
+
]
|
39
|
+
}
|
40
|
+
}'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/hyperclient.gemspec
CHANGED
@@ -14,13 +14,15 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.require_paths = ["lib"]
|
15
15
|
gem.version = Hyperclient::VERSION
|
16
16
|
|
17
|
-
gem.add_dependency 'faraday'
|
18
|
-
gem.add_dependency '
|
19
|
-
gem.add_dependency '
|
17
|
+
gem.add_dependency 'faraday', '~> 0.8'
|
18
|
+
gem.add_dependency 'faraday_middleware', '~> 0.9'
|
19
|
+
gem.add_dependency 'uri_template', '~> 0.5'
|
20
|
+
gem.add_dependency 'net-http-digest_auth', '~> 1.2'
|
20
21
|
|
21
22
|
gem.add_development_dependency 'minitest', '~> 3.4.0'
|
22
|
-
gem.add_development_dependency 'turn'
|
23
|
-
gem.add_development_dependency 'webmock'
|
24
|
-
gem.add_development_dependency 'mocha'
|
25
|
-
gem.add_development_dependency 'rack-test'
|
23
|
+
gem.add_development_dependency 'turn', '~> 0.9'
|
24
|
+
gem.add_development_dependency 'webmock', '~> 1.8'
|
25
|
+
gem.add_development_dependency 'mocha', '~> 0.13'
|
26
|
+
gem.add_development_dependency 'rack-test', '~> 0.6'
|
27
|
+
gem.add_development_dependency 'spinach'
|
26
28
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require_relative 'request/digest_authentication'
|
3
|
+
|
4
|
+
module Faraday
|
5
|
+
# Reopen Faraday::Connection to add a helper to set the digest auth data.
|
6
|
+
class Connection
|
7
|
+
# Public: Adds the digest auth middleware at the top and sets the user and
|
8
|
+
# password.
|
9
|
+
#
|
10
|
+
# user - A String with the user.
|
11
|
+
# password - A String with the password.
|
12
|
+
#
|
13
|
+
def digest_auth(user, password)
|
14
|
+
self.builder.insert(0, Faraday::Request::DigestAuth, user, password)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'net/http/digest_auth'
|
3
|
+
|
4
|
+
module Faraday
|
5
|
+
# Public: A Faraday middleware to use digest authentication. Since order of
|
6
|
+
# middlewares do care, it should be the first one of the Request middlewares
|
7
|
+
# in order to work properly (due to how digest authentication works).
|
8
|
+
#
|
9
|
+
# If some requests using the connection don't need to use digest auth you
|
10
|
+
# don't have to worry, the middleware will do nothing.
|
11
|
+
#
|
12
|
+
# It uses Net::HTTP::DigestAuth to generate the authorization header but it
|
13
|
+
# should work with any adapter.
|
14
|
+
#
|
15
|
+
# Examples:
|
16
|
+
#
|
17
|
+
# connection = Faraday.new(...) do |connection|
|
18
|
+
# connection.request :digest, USER, PASSWORD
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # You can also use it later with a connection:
|
22
|
+
# connection.digest_auth('USER', 'PASSWORD')
|
23
|
+
#
|
24
|
+
class Request::DigestAuth < Faraday::Middleware
|
25
|
+
|
26
|
+
# Public: Initializes a DigestAuth.
|
27
|
+
#
|
28
|
+
# app - The Faraday app.
|
29
|
+
# user - A String with the user to authentication the connection.
|
30
|
+
# password - A String with the password to authentication the connection.
|
31
|
+
def initialize(app, user, password)
|
32
|
+
super(app)
|
33
|
+
@user, @password = user, password
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Sends a first request with an empty body to get the
|
37
|
+
# authentication headers and then send the same request with the body and
|
38
|
+
# authorization header.
|
39
|
+
#
|
40
|
+
# env - A Hash with the request environment.
|
41
|
+
#
|
42
|
+
# Returns a Faraday::Response.
|
43
|
+
def call(env)
|
44
|
+
response = handshake(env)
|
45
|
+
return response unless response.status == 401
|
46
|
+
|
47
|
+
env[:request_headers]['Authorization'] = header(response)
|
48
|
+
@app.call(env)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
# Internal: Sends the the request with an empry body.
|
53
|
+
#
|
54
|
+
# env - A Hash with the request environment.
|
55
|
+
#
|
56
|
+
# Returns a Faraday::Response.
|
57
|
+
def handshake(env)
|
58
|
+
env_without_body = env.dup
|
59
|
+
env_without_body.delete(:body)
|
60
|
+
|
61
|
+
@app.call(env_without_body)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Internal: Builds the authorization header with the authentication data.
|
65
|
+
#
|
66
|
+
# response - A Faraday::Response with the authenticate headers.
|
67
|
+
#
|
68
|
+
# Returns a String with the DigestAuth header.
|
69
|
+
def header(response)
|
70
|
+
uri = response.env[:url]
|
71
|
+
uri.user = @user
|
72
|
+
uri.password = @password
|
73
|
+
|
74
|
+
realm = response.headers['www-authenticate']
|
75
|
+
method = response.env[:method].to_s.upcase
|
76
|
+
|
77
|
+
Net::HTTP::DigestAuth.new.auth_header(uri, realm, method)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Register the middleware as a Request middleware with the name :digest
|
83
|
+
Faraday.register_middleware :request, digest: Faraday::Request::DigestAuth
|
@@ -14,7 +14,11 @@ module Hyperclient
|
|
14
14
|
# representation - The hash with the HAL representation of the Resource.
|
15
15
|
#
|
16
16
|
def initialize(representation)
|
17
|
-
@collection = representation.
|
17
|
+
@collection = if representation.is_a?(Hash)
|
18
|
+
representation.delete_if {|key, value| key =~ /^_/}
|
19
|
+
else
|
20
|
+
representation
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
@@ -41,6 +41,10 @@ module Hyperclient
|
|
41
41
|
@collection.to_hash
|
42
42
|
end
|
43
43
|
|
44
|
+
def to_s
|
45
|
+
to_hash
|
46
|
+
end
|
47
|
+
|
44
48
|
# Public: Provides method access to the collection values.
|
45
49
|
#
|
46
50
|
# It allows accessing a value as `collection.name` instead of
|
@@ -48,7 +52,9 @@ module Hyperclient
|
|
48
52
|
#
|
49
53
|
# Returns an Object.
|
50
54
|
def method_missing(method_name, *args, &block)
|
51
|
-
@collection.fetch(method_name.to_s)
|
55
|
+
@collection.fetch(method_name.to_s) do
|
56
|
+
raise "Could not find `#{method_name.to_s}` in #{self.class.name}"
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
# Internal: Accessory method to allow the collection respond to the
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'hyperclient/link'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require_relative '../faraday/connection'
|
2
4
|
|
3
5
|
module Hyperclient
|
4
6
|
# Public: The EntryPoint is the main public API for Hyperclient. It is used to
|
@@ -6,44 +8,52 @@ module Hyperclient
|
|
6
8
|
#
|
7
9
|
# Examples
|
8
10
|
#
|
9
|
-
#
|
10
|
-
# options[:headers] = {'accept-encoding' => 'deflate, gzip'}
|
11
|
-
# options[:auth] = {type: 'digest', user: 'foo', password: 'secret'}
|
12
|
-
# options[:debug] = true
|
11
|
+
# client = Hyperclient::EntryPoint.new('http://my.api.org')
|
13
12
|
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# Public: Returns the Hash with the configuration.
|
19
|
-
attr_accessor :config
|
13
|
+
class EntryPoint < Link
|
14
|
+
extend Forwardable
|
15
|
+
# Public: Delegates common methods to be used with the Faraday connection.
|
16
|
+
def_delegators :connection, :basic_auth, :digest_auth, :token_auth, :headers, :headers=, :params, :params=
|
20
17
|
|
21
18
|
# Public: Initializes an EntryPoint.
|
22
19
|
#
|
23
20
|
# url - A String with the entry point of your API.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@config = config.update(base_uri: url)
|
28
|
-
@entry = Link.new({'href' => url}, self).resource
|
21
|
+
def initialize(url)
|
22
|
+
@link = {'href' => url}
|
23
|
+
@entry_point = self
|
29
24
|
end
|
30
25
|
|
31
|
-
#
|
26
|
+
# Public: A Faraday connection to use as a HTTP client.
|
32
27
|
#
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
# Returns a Faraday::Connection.
|
29
|
+
def connection
|
30
|
+
@connection ||= Faraday.new(url, {headers: default_headers}, &default_faraday_block)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
# Internal: Returns a block to initialize the Faraday connection. The
|
35
|
+
# default block includes a middleware to encode requests as JSON, a
|
36
|
+
# response middleware to parse JSON responses and sets the adapter as
|
37
|
+
# NetHttp.
|
38
|
+
#
|
39
|
+
# These middleware can always be changed by accessing the Faraday
|
40
|
+
# connection.
|
41
|
+
#
|
42
|
+
# Returns a block.
|
43
|
+
def default_faraday_block
|
44
|
+
lambda do |faraday|
|
45
|
+
faraday.request :json
|
46
|
+
faraday.response :json, content_type: /\bjson$/
|
47
|
+
faraday.adapter :net_http
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
|
-
# Internal:
|
44
|
-
#
|
45
|
-
|
46
|
-
|
51
|
+
# Internal: Returns the default headers to initialize the Faraday connection.
|
52
|
+
# The default headers et the Content-Type and Accept to application/json.
|
53
|
+
#
|
54
|
+
# Returns a Hash.
|
55
|
+
def default_headers
|
56
|
+
{'Content-Type' => 'application/json', 'Accept' => 'application/json'}
|
47
57
|
end
|
48
58
|
end
|
49
59
|
end
|