bootic_client 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +31 -0
- data/lib/bootic_client/client.rb +12 -13
- data/lib/bootic_client/entity.rb +2 -1
- data/lib/bootic_client/errors.rb +4 -5
- data/lib/bootic_client/relation.rb +5 -1
- data/lib/bootic_client/strategies/authorized.rb +4 -4
- data/lib/bootic_client/strategies/basic_auth.rb +27 -0
- data/lib/bootic_client/strategies/client_credentials.rb +4 -3
- data/lib/bootic_client/strategies/oauth2_strategy.rb +61 -0
- data/lib/bootic_client/strategies/strategy.rb +36 -29
- data/lib/bootic_client/version.rb +1 -1
- data/spec/authorized_strategy_spec.rb +2 -2
- data/spec/basic_auth_strategy_spec.rb +71 -0
- data/spec/client_credentials_strategy_spec.rb +2 -2
- data/spec/client_spec.rb +9 -17
- data/spec/entity_spec.rb +9 -2
- data/spec/relation_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ca933989403d66243755d735272c645458c5575
|
4
|
+
data.tar.gz: bdbdb38d2b417c05634953ffb48395d3f2971301
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c76703781e56dc5ee87eb065355fb8de38daf775f5fc38989e626985abe0a12e3800d94334482405081281ffbdbae295c8e9a66915e6e1f6b2c3f1f0b977b0f4
|
7
|
+
data.tar.gz: b5eac3f968ba339d877a798929c123c25beea50eae2f83e04078935ccbce24b97e57833ad398593d97d1dfbe057619bcc4286a0f5199cf2918968a0fd80c24f8
|
data/README.md
CHANGED
@@ -115,6 +115,20 @@ client = BooticClient.client(:client_credentials, scope: 'admin', access_token:
|
|
115
115
|
end
|
116
116
|
```
|
117
117
|
|
118
|
+
### 3. Basic Auth
|
119
|
+
|
120
|
+
This strategy uses a `username` and `password` against APIs supporting HTTP's Basic Authentication scheme.
|
121
|
+
|
122
|
+
The official Bootic API only supports OAuth2 tokens, but this allows the client to be used against internal APIs or stub APIs on development.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
client = BooticClient.client(:basic_auth, username: 'foo', password: 'bar')
|
126
|
+
|
127
|
+
root = client.root # etc
|
128
|
+
```
|
129
|
+
|
130
|
+
NOTE: `username` and `password` have nothing to do with your Bootic administrative credentials, and will be up to API maintainers to define.
|
131
|
+
|
118
132
|
## Non GET links
|
119
133
|
|
120
134
|
Most resource links lead to `GET` resources, but some will expect `POST`, `PUT`, `DELETE` or others.
|
@@ -186,6 +200,23 @@ BooticClient.configure do |c|
|
|
186
200
|
end
|
187
201
|
```
|
188
202
|
|
203
|
+
## Pre-loaded or custom root resources
|
204
|
+
|
205
|
+
This client is designed to always navigate APIs starting from the root endpoint (the Hypermedia approach), but it's also possible to skip the root and start from a locally defined resource definition.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
messaging_api = client.from_hash(
|
209
|
+
"_links" => {
|
210
|
+
"send_message" => {"href" => 'https://some.api.com/messages', "method" => 'post'},
|
211
|
+
"delete_message" => {"href" => 'https://some.api.com/messages/:id', "method" => 'delete', "templated" => true}
|
212
|
+
}
|
213
|
+
)
|
214
|
+
|
215
|
+
new_message = messaging_api.send_message(title: 'This is a new message')
|
216
|
+
|
217
|
+
messaging_api.delete_message(id: new_message.id)
|
218
|
+
```
|
219
|
+
|
189
220
|
## Contributing
|
190
221
|
|
191
222
|
1. Fork it
|
data/lib/bootic_client/client.rb
CHANGED
@@ -15,7 +15,6 @@ module BooticClient
|
|
15
15
|
|
16
16
|
def initialize(options = {}, &block)
|
17
17
|
@options = {
|
18
|
-
access_token: nil,
|
19
18
|
logging: false
|
20
19
|
}.merge(options.dup)
|
21
20
|
|
@@ -24,32 +23,38 @@ module BooticClient
|
|
24
23
|
conn &block if block_given?
|
25
24
|
end
|
26
25
|
|
27
|
-
def get(href, query = {})
|
26
|
+
def get(href, query = {}, headers = {})
|
28
27
|
validated_request!(:get, href) do |req|
|
28
|
+
req.headers.update headers
|
29
29
|
req.params.update(query)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def post(href, payload = {})
|
33
|
+
def post(href, payload = {}, headers = {})
|
34
34
|
validated_request!(:post, href) do |req|
|
35
|
+
req.headers.update headers
|
35
36
|
req.body = JSON.dump(payload)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
def put(href, payload = {})
|
40
|
+
def put(href, payload = {}, headers = {})
|
40
41
|
validated_request!(:put, href) do |req|
|
42
|
+
req.headers.update headers
|
41
43
|
req.body = JSON.dump(payload)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
def patch(href, payload = {})
|
47
|
+
def patch(href, payload = {}, headers = {})
|
46
48
|
validated_request!(:patch, href) do |req|
|
49
|
+
req.headers.update headers
|
47
50
|
req.body = JSON.dump(payload)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
|
-
def delete(href,
|
52
|
-
validated_request!(:delete, href)
|
54
|
+
def delete(href, headers = {})
|
55
|
+
validated_request!(:delete, href) do |req|
|
56
|
+
req.headers.update headers
|
57
|
+
end
|
53
58
|
end
|
54
59
|
|
55
60
|
protected
|
@@ -69,7 +74,6 @@ module BooticClient
|
|
69
74
|
|
70
75
|
def request_headers
|
71
76
|
{
|
72
|
-
'Authorization' => "Bearer #{options[:access_token]}",
|
73
77
|
'User-Agent' => USER_AGENT,
|
74
78
|
'Accept' => JSON_MIME,
|
75
79
|
'Content-Type' => JSON_MIME
|
@@ -77,7 +81,6 @@ module BooticClient
|
|
77
81
|
end
|
78
82
|
|
79
83
|
def validated_request!(verb, href, &block)
|
80
|
-
validate_request!
|
81
84
|
resp = conn.send(verb) do |req|
|
82
85
|
req.url href
|
83
86
|
req.headers.update request_headers
|
@@ -88,10 +91,6 @@ module BooticClient
|
|
88
91
|
resp
|
89
92
|
end
|
90
93
|
|
91
|
-
def validate_request!
|
92
|
-
raise NoAccessTokenError, "Missing access token" unless options[:access_token]
|
93
|
-
end
|
94
|
-
|
95
94
|
def raise_if_invalid!(resp)
|
96
95
|
raise ServerError, "Server Error" if resp.status > 499
|
97
96
|
raise NotFoundError, "Not Found" if resp.status == 404
|
data/lib/bootic_client/entity.rb
CHANGED
data/lib/bootic_client/errors.rb
CHANGED
@@ -2,8 +2,7 @@ module BooticClient
|
|
2
2
|
class TransportError < StandardError; end
|
3
3
|
class ServerError < TransportError; end
|
4
4
|
class NotFoundError < ServerError; end
|
5
|
-
class
|
6
|
-
class UnauthorizedError <
|
7
|
-
class AccessForbiddenError <
|
8
|
-
|
9
|
-
end
|
5
|
+
class AuthorizationError < ServerError; end
|
6
|
+
class UnauthorizedError < AuthorizationError; end
|
7
|
+
class AccessForbiddenError < AuthorizationError; end
|
8
|
+
end
|
@@ -45,7 +45,11 @@ module BooticClient
|
|
45
45
|
|
46
46
|
def run(opts = {})
|
47
47
|
if templated?
|
48
|
-
|
48
|
+
uri_vars = uri.variables
|
49
|
+
payload = opts.each_with_object({}) do |(k,v),memo|
|
50
|
+
memo[k] = v unless uri_vars.include?(k.to_s)
|
51
|
+
end
|
52
|
+
client.request_and_wrap transport_method.to_sym, uri.expand(opts), wrapper_class, payload
|
49
53
|
else
|
50
54
|
client.request_and_wrap transport_method.to_sym, href, wrapper_class, opts
|
51
55
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require 'bootic_client/strategies/
|
1
|
+
require 'bootic_client/strategies/oauth2_strategy'
|
2
2
|
|
3
3
|
module BooticClient
|
4
4
|
module Strategies
|
5
5
|
|
6
|
-
class Authorized <
|
6
|
+
class Authorized < Oauth2Strategy
|
7
7
|
protected
|
8
8
|
|
9
|
-
def validate!
|
10
|
-
raise "options MUST include access_token" unless options[:access_token]
|
9
|
+
def validate!
|
10
|
+
raise ArgumentError, "options MUST include access_token" unless options[:access_token]
|
11
11
|
end
|
12
12
|
|
13
13
|
def get_token
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'bootic_client/strategies/strategy'
|
2
|
+
|
3
|
+
module BooticClient
|
4
|
+
module Strategies
|
5
|
+
class BasicAuth < Strategy
|
6
|
+
|
7
|
+
def inspect
|
8
|
+
%(#<#{self.class.name} root: #{config.api_root} username: #{options[:username]}>)
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def validate!
|
14
|
+
raise ArgumentError, "options MUST include username" unless options[:username]
|
15
|
+
raise ArgumentError, "options MUST include password" unless options[:password]
|
16
|
+
end
|
17
|
+
|
18
|
+
def client
|
19
|
+
@client ||= Client.new(options) do |c|
|
20
|
+
c.request :basic_auth, options[:username], options[:password]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
strategies[:basic_auth] = Strategies::BasicAuth
|
27
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
|
-
require 'bootic_client/strategies/
|
1
|
+
require 'bootic_client/strategies/oauth2_strategy'
|
2
2
|
|
3
3
|
module BooticClient
|
4
4
|
module Strategies
|
5
5
|
|
6
|
-
class ClientCredentials <
|
6
|
+
class ClientCredentials < Oauth2Strategy
|
7
7
|
protected
|
8
|
+
|
8
9
|
def get_token
|
9
10
|
opts = {}
|
10
11
|
opts['scope'] = options.delete(:scope) if options[:scope]
|
@@ -16,4 +17,4 @@ module BooticClient
|
|
16
17
|
end
|
17
18
|
|
18
19
|
strategies[:client_credentials] = Strategies::ClientCredentials
|
19
|
-
end
|
20
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
require 'bootic_client/strategies/strategy'
|
3
|
+
|
4
|
+
module BooticClient
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
class Oauth2Strategy < Strategy
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
%(#<#{self.class.name} cid: #{config.client_id} root: #{config.api_root} auth: #{config.auth_host}>)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def validate!
|
16
|
+
raise ArgumentError, "MUST include client_id" unless config.client_id
|
17
|
+
raise ArgumentError, "MUST include client_secret" unless config.client_secret
|
18
|
+
raise ArgumentError, "MUST include api_root" unless config.api_root
|
19
|
+
end
|
20
|
+
|
21
|
+
def pre_flight
|
22
|
+
update_token! unless options[:access_token]
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_headers
|
26
|
+
{
|
27
|
+
'Authorization' => "Bearer #{options[:access_token]}"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def retryable(&block)
|
32
|
+
begin
|
33
|
+
yield
|
34
|
+
rescue AuthorizationError => e
|
35
|
+
update_token!
|
36
|
+
yield
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_token!
|
41
|
+
new_token = get_token
|
42
|
+
options[:access_token] = new_token
|
43
|
+
on_new_token.call new_token
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_token
|
47
|
+
raise "Implement this in subclasses"
|
48
|
+
end
|
49
|
+
|
50
|
+
def auth
|
51
|
+
@auth ||= OAuth2::Client.new(
|
52
|
+
config.client_id,
|
53
|
+
config.client_secret,
|
54
|
+
site: config.auth_host
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'oauth2'
|
2
|
-
|
3
1
|
module BooticClient
|
4
2
|
module Strategies
|
5
3
|
class Strategy
|
@@ -8,11 +6,7 @@ module BooticClient
|
|
8
6
|
|
9
7
|
def initialize(config, client_opts = {}, &on_new_token)
|
10
8
|
@config, @options, @on_new_token = config, client_opts, (on_new_token || Proc.new{})
|
11
|
-
|
12
|
-
raise "MUST include client_secret" unless config.client_secret
|
13
|
-
raise "MUST include api_root" unless config.api_root
|
14
|
-
validate! @options
|
15
|
-
reset!
|
9
|
+
validate!
|
16
10
|
end
|
17
11
|
|
18
12
|
def root
|
@@ -24,43 +18,56 @@ module BooticClient
|
|
24
18
|
end
|
25
19
|
|
26
20
|
def request_and_wrap(request_method, href, wrapper_class, payload = {})
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
new_token = get_token
|
31
|
-
options[:access_token] = new_token
|
32
|
-
reset!
|
33
|
-
on_new_token.call new_token
|
34
|
-
wrapper_class.new client.send(request_method, href, payload).body, self
|
21
|
+
pre_flight
|
22
|
+
retryable do
|
23
|
+
wrapper_class.new client.send(request_method, href, payload, request_headers).body, self
|
35
24
|
end
|
36
25
|
end
|
37
26
|
|
38
27
|
def inspect
|
39
|
-
%(#<#{self.class.name}
|
28
|
+
%(#<#{self.class.name} root: #{config.api_root}>)
|
40
29
|
end
|
41
30
|
|
42
31
|
protected
|
43
32
|
|
44
|
-
attr_reader :config, :on_new_token
|
33
|
+
attr_reader :config, :on_new_token
|
34
|
+
|
35
|
+
def validate!
|
36
|
+
# Overwrite in sub classes
|
37
|
+
# to raise ArgumentErrors on
|
38
|
+
# missing config attributes of options values.
|
39
|
+
end
|
45
40
|
|
46
|
-
def
|
47
|
-
|
41
|
+
def pre_flight
|
42
|
+
# Runs before every request
|
43
|
+
# Overwrite in sub classes to run checks
|
44
|
+
# (ie authorisation status, missing options, expired token refresh)
|
48
45
|
end
|
49
46
|
|
50
|
-
|
51
|
-
|
47
|
+
# Noop.
|
48
|
+
# Overwrite in sub classes to implement retryable requests.
|
49
|
+
# Example:
|
50
|
+
#
|
51
|
+
# def retryable(&block)
|
52
|
+
# begin
|
53
|
+
# yield # issue request
|
54
|
+
# rescue SomeException => e
|
55
|
+
# fix_cause_of_exception
|
56
|
+
# yield # try again
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
def retryable(&block)
|
61
|
+
yield
|
52
62
|
end
|
53
63
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
config.client_secret,
|
58
|
-
site: config.auth_host
|
59
|
-
)
|
64
|
+
# Noop. Merge these headers into every request.
|
65
|
+
def request_headers
|
66
|
+
{}
|
60
67
|
end
|
61
68
|
|
62
|
-
def
|
63
|
-
@client
|
69
|
+
def client
|
70
|
+
@client ||= Client.new(options)
|
64
71
|
end
|
65
72
|
end
|
66
73
|
end
|
@@ -55,7 +55,7 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
55
55
|
it 'raises error' do
|
56
56
|
expect{
|
57
57
|
BooticClient.client(:authorized)
|
58
|
-
}.to raise_error
|
58
|
+
}.to raise_error(ArgumentError)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -63,7 +63,7 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
63
63
|
it 'raises error' do
|
64
64
|
expect{
|
65
65
|
BooticClient.client(:authorized)
|
66
|
-
}.to raise_error
|
66
|
+
}.to raise_error(ArgumentError)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'BooticClient::Strategies::BasicAuth' do
|
4
|
+
require 'webmock/rspec'
|
5
|
+
|
6
|
+
let(:root_data) {
|
7
|
+
{
|
8
|
+
'_links' => {
|
9
|
+
'a_product' => {'href' => 'https://api.bootic.net/v1/products/1'}
|
10
|
+
},
|
11
|
+
'message' => "Hello!"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
let(:product_data) {
|
16
|
+
{'title' => 'iPhone 6 Plus'}
|
17
|
+
}
|
18
|
+
|
19
|
+
let(:client) { BooticClient.client(:basic_auth, username: 'foo', password: 'bar') }
|
20
|
+
|
21
|
+
describe '#inspect' do
|
22
|
+
it 'is informative' do
|
23
|
+
expect(client.inspect).to eql %(#<BooticClient::Strategies::BasicAuth root: https://api.bootic.net/v1 username: foo>)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with missing credentials' do
|
28
|
+
it 'raises error' do
|
29
|
+
expect{
|
30
|
+
BooticClient.client(:basic_auth)
|
31
|
+
}.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with invalid BasicAuth credentials' do
|
36
|
+
let!(:root_request) do
|
37
|
+
stub_request(:get, 'https://foo:bar@api.bootic.net/v1')
|
38
|
+
.to_return(status: 401, body: JSON.dump(root_data))
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises an Unauthorized error' do
|
42
|
+
expect{ client.root }.to raise_error(BooticClient::UnauthorizedError)
|
43
|
+
expect(root_request).to have_been_requested
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with valid BasicAuth credentials' do
|
48
|
+
let!(:root_request) do
|
49
|
+
stub_request(:get, 'https://foo:bar@api.bootic.net/v1')
|
50
|
+
.to_return(status: 200, body: JSON.dump(root_data))
|
51
|
+
end
|
52
|
+
|
53
|
+
let!(:product_request) do
|
54
|
+
stub_request(:get, 'https://foo:bar@api.bootic.net/v1/products/1')
|
55
|
+
.to_return(status: 200, body: JSON.dump(product_data))
|
56
|
+
end
|
57
|
+
|
58
|
+
let!(:root) { client.root }
|
59
|
+
|
60
|
+
it 'includes Basic Auth credentials in request' do
|
61
|
+
expect(root_request).to have_been_requested
|
62
|
+
expect(root.message).to eql('Hello!')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'follows links as normal, including Basic Auth in every request' do
|
66
|
+
product = root.a_product
|
67
|
+
expect(product_request).to have_been_requested
|
68
|
+
expect(product.title).to eql 'iPhone 6 Plus'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -18,7 +18,7 @@ describe 'BooticClient::Strategies::ClientCredentials' do
|
|
18
18
|
BooticClient.client_id = nil
|
19
19
|
expect{
|
20
20
|
BooticClient.client(:client_credentials, scope: 'admin')
|
21
|
-
}.to raise_error
|
21
|
+
}.to raise_error(ArgumentError)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -33,7 +33,7 @@ describe 'BooticClient::Strategies::ClientCredentials' do
|
|
33
33
|
def stub_api_root(access_token, status, body)
|
34
34
|
stub_request(:get, "https://api.bootic.net/v1").
|
35
35
|
with(headers: {'Accept'=>'application/json', 'Authorization'=>"Bearer #{access_token}"}).
|
36
|
-
to_return(status: status, :
|
36
|
+
to_return(status: status, body: JSON.dump(body))
|
37
37
|
end
|
38
38
|
|
39
39
|
before do
|
data/spec/client_spec.rb
CHANGED
@@ -6,9 +6,9 @@ describe BooticClient::Client do
|
|
6
6
|
|
7
7
|
describe 'valid response' do
|
8
8
|
let(:root_url) { 'https://api.bootic.net/v1' }
|
9
|
-
let(:client) { BooticClient::Client.new
|
9
|
+
let(:client) { BooticClient::Client.new }
|
10
10
|
let(:request_headers) {
|
11
|
-
{'
|
11
|
+
{'Authorization' => "Bearer xxx"}
|
12
12
|
}
|
13
13
|
let(:response_headers) {
|
14
14
|
{
|
@@ -35,7 +35,7 @@ describe BooticClient::Client do
|
|
35
35
|
.to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
|
36
36
|
end
|
37
37
|
|
38
|
-
let!(:response) { client.get(root_url) }
|
38
|
+
let!(:response) { client.get(root_url, {}, request_headers) }
|
39
39
|
|
40
40
|
it 'returns parsed Faraday response' do
|
41
41
|
expect(response).to be_kind_of(Faraday::Response)
|
@@ -53,7 +53,7 @@ describe BooticClient::Client do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'returns cached response' do
|
56
|
-
r = client.get(root_url)
|
56
|
+
r = client.get(root_url, {}, request_headers)
|
57
57
|
expect(@cached_request).to have_been_requested
|
58
58
|
|
59
59
|
expect(r.status).to eql(200)
|
@@ -71,7 +71,7 @@ describe BooticClient::Client do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'returns cached response' do
|
74
|
-
r = client.get(root_url)
|
74
|
+
r = client.get(root_url, {}, request_headers)
|
75
75
|
expect(@cached_request).to have_been_requested
|
76
76
|
|
77
77
|
expect(r.status).to eql(200)
|
@@ -83,14 +83,6 @@ describe BooticClient::Client do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
context 'errors' do
|
86
|
-
describe 'no access token' do
|
87
|
-
it 'raises error' do
|
88
|
-
expect{
|
89
|
-
BooticClient::Client.new.get(root_url)
|
90
|
-
}.to raise_error(BooticClient::NoAccessTokenError)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
86
|
describe '500 Server error' do
|
95
87
|
before do
|
96
88
|
stub_request(:get, root_url)
|
@@ -156,7 +148,7 @@ describe BooticClient::Client do
|
|
156
148
|
end
|
157
149
|
|
158
150
|
it 'GETs response' do
|
159
|
-
expect(client.get(root_url, foo: 'bar').body['message']).to eql('Hello!')
|
151
|
+
expect(client.get(root_url, {foo: 'bar'}, request_headers).body['message']).to eql('Hello!')
|
160
152
|
end
|
161
153
|
end
|
162
154
|
|
@@ -168,7 +160,7 @@ describe BooticClient::Client do
|
|
168
160
|
end
|
169
161
|
|
170
162
|
it 'POSTs request and parses response' do
|
171
|
-
expect(client.post(root_url, foo: 'bar').body['message']).to eql('Hello!')
|
163
|
+
expect(client.post(root_url, {foo: 'bar'}, request_headers).body['message']).to eql('Hello!')
|
172
164
|
end
|
173
165
|
end
|
174
166
|
|
@@ -181,7 +173,7 @@ describe BooticClient::Client do
|
|
181
173
|
end
|
182
174
|
|
183
175
|
it "#{verb.to_s.upcase}s request and parses response" do
|
184
|
-
expect(client.send(verb, root_url, foo: 'bar').body['message']).to eql('Hello!')
|
176
|
+
expect(client.send(verb, root_url, {foo: 'bar'}, request_headers).body['message']).to eql('Hello!')
|
185
177
|
end
|
186
178
|
end
|
187
179
|
end
|
@@ -194,7 +186,7 @@ describe BooticClient::Client do
|
|
194
186
|
end
|
195
187
|
|
196
188
|
it 'DELETEs request and parses response' do
|
197
|
-
expect(client.send(:delete, root_url).status).to eql(200)
|
189
|
+
expect(client.send(:delete, root_url, request_headers).status).to eql(200)
|
198
190
|
expect(@delete_requst).to have_been_requested
|
199
191
|
end
|
200
192
|
end
|
data/spec/entity_spec.rb
CHANGED
@@ -29,6 +29,7 @@ describe BooticClient::Entity do
|
|
29
29
|
{
|
30
30
|
'title' => 'iPhone 4',
|
31
31
|
'price' => 12345,
|
32
|
+
'published' => false,
|
32
33
|
'_links' => {
|
33
34
|
'self' => {href: '/products/iphone4'},
|
34
35
|
'btc:delete_product' => {'href' => '/products/12345'}
|
@@ -43,6 +44,7 @@ describe BooticClient::Entity do
|
|
43
44
|
{
|
44
45
|
'title' => 'iPhone 5',
|
45
46
|
'price' => 12342,
|
47
|
+
'published' => true,
|
46
48
|
'_links' => {
|
47
49
|
'self' => {href: '/products/iphone5'}
|
48
50
|
},
|
@@ -52,7 +54,7 @@ describe BooticClient::Entity do
|
|
52
54
|
}
|
53
55
|
}
|
54
56
|
}
|
55
|
-
|
57
|
+
|
56
58
|
] # / items
|
57
59
|
}
|
58
60
|
}
|
@@ -118,6 +120,11 @@ describe BooticClient::Entity do
|
|
118
120
|
expect(shop.name).to eql('Acme')
|
119
121
|
end
|
120
122
|
end
|
123
|
+
|
124
|
+
it 'includes FALSE values' do
|
125
|
+
expect(entity.items.first.published).to be false
|
126
|
+
expect(entity.items.last.published).to be true
|
127
|
+
end
|
121
128
|
end #/ embedded entities
|
122
129
|
|
123
130
|
describe 'link relations' do
|
@@ -161,7 +168,7 @@ describe BooticClient::Entity do
|
|
161
168
|
end
|
162
169
|
|
163
170
|
it 'takes optional URI parameters' do
|
164
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/search?q=foo', BooticClient::Entity, {
|
171
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/search?q=foo', BooticClient::Entity, {}).and_return next_page
|
165
172
|
entity.search(q: 'foo').tap do |next_entity|
|
166
173
|
expect(next_entity).to be_kind_of(BooticClient::Entity)
|
167
174
|
expect(next_entity.page).to eql(2)
|
data/spec/relation_spec.rb
CHANGED
@@ -48,8 +48,8 @@ describe BooticClient::Relation do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'interpolates tokens' do
|
51
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=2', BooticClient::Entity, {
|
52
|
-
expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
|
51
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=2', BooticClient::Entity, {other: 'other'}).and_return entity
|
52
|
+
expect(relation.run(id: 2, q: 'test', page: 2, other: 'other')).to eql(entity)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -62,9 +62,9 @@ describe BooticClient::Relation do
|
|
62
62
|
client.stub(:request_and_wrap).with(:post, '/foo/bars', BooticClient::Entity, {}).and_return entity
|
63
63
|
expect(relation.run).to eql(entity)
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
it 'interpolates templated URLs' do
|
67
|
-
client.stub(:request_and_wrap).with(:post, '/foo/123', BooticClient::Entity, {foo: 'bar'
|
67
|
+
client.stub(:request_and_wrap).with(:post, '/foo/123', BooticClient::Entity, {foo: 'bar'}).and_return entity
|
68
68
|
expect(relation_templated.run(bars: 123, foo: 'bar')).to eql(entity)
|
69
69
|
end
|
70
70
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootic_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ismael Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -186,10 +186,13 @@ files:
|
|
186
186
|
- lib/bootic_client/relation.rb
|
187
187
|
- lib/bootic_client/stores/memcache.rb
|
188
188
|
- lib/bootic_client/strategies/authorized.rb
|
189
|
+
- lib/bootic_client/strategies/basic_auth.rb
|
189
190
|
- lib/bootic_client/strategies/client_credentials.rb
|
191
|
+
- lib/bootic_client/strategies/oauth2_strategy.rb
|
190
192
|
- lib/bootic_client/strategies/strategy.rb
|
191
193
|
- lib/bootic_client/version.rb
|
192
194
|
- spec/authorized_strategy_spec.rb
|
195
|
+
- spec/basic_auth_strategy_spec.rb
|
193
196
|
- spec/bootic_client_spec.rb
|
194
197
|
- spec/client_credentials_strategy_spec.rb
|
195
198
|
- spec/client_spec.rb
|
@@ -223,6 +226,7 @@ specification_version: 4
|
|
223
226
|
summary: Official Ruby client for the Bootic API
|
224
227
|
test_files:
|
225
228
|
- spec/authorized_strategy_spec.rb
|
229
|
+
- spec/basic_auth_strategy_spec.rb
|
226
230
|
- spec/bootic_client_spec.rb
|
227
231
|
- spec/client_credentials_strategy_spec.rb
|
228
232
|
- spec/client_spec.rb
|