hyperclient 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://secure.travis-ci.org/codegram/hyperclient.png)](http://travis-ci.org/codegram/hyperclient)
|
3
3
|
[![Dependency Status](https://gemnasium.com/codegram/hyperclient.png)](http://gemnasium.com/codegram/hyperclient)
|
4
|
-
[![Code Climate](https://codeclimate.com/
|
4
|
+
[![Code Climate](https://codeclimate.com/github/codegram/hyperclient.png)](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
|