api_client 0.5.24-java → 0.5.25-java
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/api_client/base.rb +77 -0
- data/lib/api_client/connection/abstract.rb +81 -0
- data/lib/api_client/connection/basic.rb +129 -0
- data/lib/api_client/connection/json.rb +14 -0
- data/lib/api_client/connection/middlewares/request/json.rb +34 -0
- data/lib/api_client/connection/middlewares/request/logger.rb +64 -0
- data/lib/api_client/connection/middlewares/request/oauth.rb +22 -0
- data/lib/api_client/connection/oauth.rb +18 -0
- data/lib/api_client/errors.rb +31 -0
- data/lib/api_client/mixins/configuration.rb +24 -0
- data/lib/api_client/mixins/connection_hooks.rb +24 -0
- data/lib/api_client/mixins/delegation.rb +23 -0
- data/lib/api_client/mixins/inheritance.rb +19 -0
- data/lib/api_client/mixins/instantiation.rb +29 -0
- data/lib/api_client/mixins/scoping.rb +49 -0
- data/lib/api_client/resource/base.rb +67 -0
- data/lib/api_client/resource/name_resolver.rb +37 -0
- data/lib/api_client/resource/scope.rb +73 -0
- data/lib/api_client/scope.rb +125 -0
- data/lib/api_client/utils.rb +18 -0
- data/lib/api_client/version.rb +3 -0
- data/spec/api_client/base/connection_hook_spec.rb +18 -0
- data/spec/api_client/base/delegation_spec.rb +15 -0
- data/spec/api_client/base/inheritance_spec.rb +44 -0
- data/spec/api_client/base/instantiation_spec.rb +55 -0
- data/spec/api_client/base/marshalling_spec.rb +33 -0
- data/spec/api_client/base/parsing_spec.rb +38 -0
- data/spec/api_client/base/scoping_spec.rb +60 -0
- data/spec/api_client/base_spec.rb +107 -0
- data/spec/api_client/connection/abstract_spec.rb +21 -0
- data/spec/api_client/connection/basic_spec.rb +191 -0
- data/spec/api_client/connection/oauth_spec.rb +27 -0
- data/spec/api_client/connection/request/json_spec.rb +30 -0
- data/spec/api_client/connection/request/logger_spec.rb +18 -0
- data/spec/api_client/connection/request/oauth_spec.rb +26 -0
- data/spec/api_client/resource/base_spec.rb +97 -0
- data/spec/api_client/resource/name_spec.rb +19 -0
- data/spec/api_client/resource/scope_spec.rb +122 -0
- data/spec/api_client/scope_spec.rb +204 -0
- data/spec/api_client/utils_spec.rb +32 -0
- data/spec/support/matchers.rb +5 -0
- metadata +62 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6aee99219c58bf02f29e11548ea72dd56ad18fba534f326626147053148f81b
|
4
|
+
data.tar.gz: 767a054b03b9ea36501f7dbdd71bc898d65d5db26b09962dbb1d4e4283c60203
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae82881334deac2a7d458e4618d6c7502580e4a070202e04836b8166603a42bba48d6abe047efda1eaff153f540993c1ccb0109a275eebffcf35e38a01985abb
|
7
|
+
data.tar.gz: 78193bbf66f1e8c8d961f83b39ed86a23348cca2c56c235e1f896ae8b19ec676aaa0f678602c00b5a239e4c0555814d7b1b3a6b9432a3d3bc3414dda1d5ad834
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
module ApiClient
|
2
|
+
|
3
|
+
class Base < Hashie::Mash
|
4
|
+
|
5
|
+
extend ApiClient::Mixins::Inheritance
|
6
|
+
extend ApiClient::Mixins::Instantiation
|
7
|
+
extend ApiClient::Mixins::Scoping
|
8
|
+
extend ApiClient::Mixins::ConnectionHooks
|
9
|
+
|
10
|
+
class << self
|
11
|
+
extend ApiClient::Mixins::Delegation
|
12
|
+
extend ApiClient::Mixins::Configuration
|
13
|
+
|
14
|
+
delegate :fetch, :get, :put, :post, :patch, :delete, :headers, :endpoint, :options, :adapter, :params, :raw, :to => :scope
|
15
|
+
|
16
|
+
dsl_accessor :format, :namespace
|
17
|
+
|
18
|
+
def subkey_class
|
19
|
+
Hashie::Mash
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(response)
|
23
|
+
if response.is_a?(Faraday::Response)
|
24
|
+
return nil if response.status == 204
|
25
|
+
response = response.body
|
26
|
+
end
|
27
|
+
|
28
|
+
if self.format == :json
|
29
|
+
MultiJson.load(response)
|
30
|
+
elsif self.format == :xml
|
31
|
+
MultiXml.parse(response)
|
32
|
+
else
|
33
|
+
response
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# Defaults
|
40
|
+
self.format :json
|
41
|
+
|
42
|
+
def id
|
43
|
+
self['id']
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
attributes = []
|
48
|
+
attr_keys = self.keys - ['id']
|
49
|
+
attributes.push "id: #{self.id}" if self.id
|
50
|
+
attr_keys.each do |key|
|
51
|
+
attributes.push("#{key}: #{self[key].inspect}")
|
52
|
+
end
|
53
|
+
"#<#{self.class} #{attributes.join(', ')}>"
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def method_missing(method_name, *args, &blk)
|
58
|
+
if respond_to?(method_name) || has_special_ending?(method_name)
|
59
|
+
super
|
60
|
+
elsif use_strict_reader?(method_name)
|
61
|
+
fetch(method_name)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def use_strict_reader?(method_name)
|
68
|
+
respond_to?(:strict_attr_reader?) &&
|
69
|
+
self.strict_attr_reader? &&
|
70
|
+
method_name != :to_ary
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_special_ending?(name)
|
74
|
+
name.to_s =~ /[?=]$/
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ApiClient
|
2
|
+
|
3
|
+
module Connection
|
4
|
+
|
5
|
+
class Abstract
|
6
|
+
|
7
|
+
attr_accessor :endpoint, :handler, :options
|
8
|
+
|
9
|
+
def initialize(endpoint, options = {})
|
10
|
+
raise "Cannot instantiate abstract class" if self.class == ApiClient::Connection::Abstract
|
11
|
+
@endpoint = endpoint
|
12
|
+
@options = options
|
13
|
+
create_handler
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_handler
|
17
|
+
end
|
18
|
+
|
19
|
+
#### ApiClient::Connection::Abstract#get
|
20
|
+
# Performs a GET request
|
21
|
+
# Accepts three parameters:
|
22
|
+
#
|
23
|
+
# * path - the path the request should go to
|
24
|
+
# * data - (optional) the query, passed as a hash and converted into query params
|
25
|
+
# * headers - (optional) headers sent along with the request
|
26
|
+
#
|
27
|
+
def get(path, data = {}, headers = {})
|
28
|
+
end
|
29
|
+
|
30
|
+
#### ApiClient::Connection::Abstract#post
|
31
|
+
# Performs a POST request
|
32
|
+
# Accepts three parameters:
|
33
|
+
#
|
34
|
+
# * path - the path request should go to
|
35
|
+
# * data - (optional) data sent in the request
|
36
|
+
# * headers - (optional) headers sent along in the request
|
37
|
+
#
|
38
|
+
def post(path, data = {}, headers = {})
|
39
|
+
end
|
40
|
+
|
41
|
+
#### ApiClient::Connection::Abstract#patch
|
42
|
+
# Performs a PATCH request
|
43
|
+
# Accepts three parameters:
|
44
|
+
#
|
45
|
+
# * path - the path request should go to
|
46
|
+
# * data - (optional) data sent in the request
|
47
|
+
# * headers - (optional) headers sent along in the request
|
48
|
+
#
|
49
|
+
def patch(path, data = {}, headers = {})
|
50
|
+
end
|
51
|
+
|
52
|
+
#### ApiClient::Connection::Abstract#put
|
53
|
+
# Performs a PUT request
|
54
|
+
# Accepts three parameters:
|
55
|
+
#
|
56
|
+
# * path - the path request should go to
|
57
|
+
# * data - (optional) data sent in the request
|
58
|
+
# * headers - (optional) headers sent along in the request
|
59
|
+
#
|
60
|
+
def put(path, data = {}, headers = {})
|
61
|
+
end
|
62
|
+
|
63
|
+
#### FS::Connection#delete
|
64
|
+
# Performs a DELETE request
|
65
|
+
# Accepts three parameters:
|
66
|
+
#
|
67
|
+
# * path - the path request should go to
|
68
|
+
# * data - (optional) the query, passed as a hash and converted into query params
|
69
|
+
# * headers - (optional) headers sent along in the request
|
70
|
+
#
|
71
|
+
def delete(path, data = {}, headers = {})
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
"#<#{self.class} endpoint: \"#{endpoint}\">"
|
76
|
+
end
|
77
|
+
alias :to_s :inspect
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module ApiClient
|
2
|
+
|
3
|
+
module Connection
|
4
|
+
|
5
|
+
class Basic < Abstract
|
6
|
+
|
7
|
+
def create_handler
|
8
|
+
# Create and memoize the connection object
|
9
|
+
# The empty block is necessary as we don't want Faraday to
|
10
|
+
# initialize itself, we build our own stack in finalize_handler
|
11
|
+
@handler = Faraday.new(@endpoint, @options[:faraday] || {}) do end
|
12
|
+
finalize_handler
|
13
|
+
end
|
14
|
+
|
15
|
+
def finalize_handler
|
16
|
+
@handler.use Middlewares::Request::Logger, ApiClient.logger if ApiClient.logger
|
17
|
+
@handler.use Faraday::Request::UrlEncoded
|
18
|
+
@handler.adapter Faraday.default_adapter
|
19
|
+
end
|
20
|
+
|
21
|
+
#### ApiClient::Connection::Abstract#get
|
22
|
+
# Performs a GET request
|
23
|
+
# Accepts three parameters:
|
24
|
+
#
|
25
|
+
# * path - the path the request should go to
|
26
|
+
# * data - (optional) the query, passed as a hash and converted into query params
|
27
|
+
# * headers - (optional) headers sent along with the request
|
28
|
+
#
|
29
|
+
def get(path, data = {}, headers = {})
|
30
|
+
exec_request(:get, path, data, headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
#### ApiClient::Connection::Abstract#post
|
34
|
+
# Performs a POST request
|
35
|
+
# Accepts three parameters:
|
36
|
+
#
|
37
|
+
# * path - the path request should go to
|
38
|
+
# * data - (optional) data sent in the request
|
39
|
+
# * headers - (optional) headers sent along in the request
|
40
|
+
#
|
41
|
+
# This method automatically adds the application token header
|
42
|
+
def post(path, data = {}, headers = {})
|
43
|
+
exec_request(:post, path, data, headers)
|
44
|
+
end
|
45
|
+
|
46
|
+
#### ApiClient::Connection::Abstract#patch
|
47
|
+
# Performs a PATCH request
|
48
|
+
# Accepts three parameters:
|
49
|
+
#
|
50
|
+
# * path - the path request should go to
|
51
|
+
# * data - (optional) data sent in the request
|
52
|
+
# * headers - (optional) headers sent along in the request
|
53
|
+
#
|
54
|
+
# This method automatically adds the application token header
|
55
|
+
def patch(path, data = {}, headers = {})
|
56
|
+
exec_request(:patch, path, data, headers)
|
57
|
+
end
|
58
|
+
|
59
|
+
#### ApiClient::Connection::Abstract#put
|
60
|
+
# Performs a PUT request
|
61
|
+
# Accepts three parameters:
|
62
|
+
#
|
63
|
+
# * path - the path request should go to
|
64
|
+
# * data - (optional) data sent in the request
|
65
|
+
# * headers - (optional) headers sent along in the request
|
66
|
+
#
|
67
|
+
# This method automatically adds the application token header
|
68
|
+
def put(path, data = {}, headers = {})
|
69
|
+
exec_request(:put, path, data, headers)
|
70
|
+
end
|
71
|
+
|
72
|
+
#### FS::Connection#delete
|
73
|
+
# Performs a DELETE request
|
74
|
+
# Accepts three parameters:
|
75
|
+
#
|
76
|
+
# * path - the path request should go to
|
77
|
+
# * data - (optional) the query, passed as a hash and converted into query params
|
78
|
+
# * headers - (optional) headers sent along in the request
|
79
|
+
#
|
80
|
+
# This method automatically adds the application token header
|
81
|
+
def delete(path, data = {}, headers = {})
|
82
|
+
exec_request(:delete, path, data, headers)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def exec_request(method, path, data, headers)
|
88
|
+
response = @handler.send(method, path, data, headers)
|
89
|
+
request = { :method => method, :path => path, :data => data}
|
90
|
+
handle_response(request, response)
|
91
|
+
rescue Faraday::Error::ConnectionFailed => e
|
92
|
+
raise ApiClient::Errors::ConnectionFailed.new(e.message, request, response)
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle_response(request, response)
|
96
|
+
raise ApiClient::Errors::ConnectionFailed.new(nil, request, response) unless response
|
97
|
+
case response.status
|
98
|
+
when 401
|
99
|
+
raise ApiClient::Errors::Unauthorized.new(nil, request, response)
|
100
|
+
when 403
|
101
|
+
raise ApiClient::Errors::Forbidden.new(nil, request, response)
|
102
|
+
when 404
|
103
|
+
raise ApiClient::Errors::NotFound.new(nil, request, response)
|
104
|
+
when 400
|
105
|
+
raise ApiClient::Errors::BadRequest.new(nil, request, response)
|
106
|
+
when 406
|
107
|
+
raise ApiClient::Errors::Unsupported.new(nil, request, response)
|
108
|
+
when 409
|
109
|
+
raise ApiClient::Errors::Conflict.new(nil, request, response)
|
110
|
+
when 410
|
111
|
+
raise ApiClient::Errors::Gone.new(nil, request, response)
|
112
|
+
when 422
|
113
|
+
raise ApiClient::Errors::UnprocessableEntity.new(response.body, request, response)
|
114
|
+
when 423
|
115
|
+
raise ApiClient::Errors::Locked.new(response.body, request, response)
|
116
|
+
when 429
|
117
|
+
raise ApiClient::Errors::TooManyRequests.new(response.body, request, response)
|
118
|
+
when 300..399
|
119
|
+
raise ApiClient::Errors::Redirect.new(response['Location'], request, response)
|
120
|
+
when 500..599
|
121
|
+
raise ApiClient::Errors::ServerError.new(nil, request, response)
|
122
|
+
else
|
123
|
+
response
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Exactly like Basic, but uses JSON encoding for request body
|
2
|
+
# if applicable
|
3
|
+
module ApiClient
|
4
|
+
module Connection
|
5
|
+
class Json < Basic
|
6
|
+
def finalize_handler
|
7
|
+
@handler.use Middlewares::Request::Logger, ApiClient.logger if ApiClient.logger
|
8
|
+
@handler.use Middlewares::Request::Json
|
9
|
+
@handler.use Faraday::Request::UrlEncoded
|
10
|
+
@handler.adapter Faraday.default_adapter
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class ApiClient::Connection::Middlewares::Request::Json < Faraday::Middleware
|
2
|
+
CONTENT_TYPE = "Content-Type".freeze
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :mime_type
|
6
|
+
end
|
7
|
+
self.mime_type = "application/json".freeze
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
match_content_type(env) do |data|
|
11
|
+
params = Faraday::Utils::ParamsHash[data]
|
12
|
+
env[:body] = MultiJson.dump(params)
|
13
|
+
end
|
14
|
+
@app.call env
|
15
|
+
end
|
16
|
+
|
17
|
+
def match_content_type(env)
|
18
|
+
if process_request?(env)
|
19
|
+
env[:request_headers][CONTENT_TYPE] ||= self.class.mime_type
|
20
|
+
yield env[:body] unless env[:body].respond_to?(:to_str)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_request?(env)
|
25
|
+
type = request_type(env)
|
26
|
+
env[:body] and (type.empty? or type == self.class.mime_type)
|
27
|
+
end
|
28
|
+
|
29
|
+
def request_type(env)
|
30
|
+
type = env[:request_headers][CONTENT_TYPE].to_s
|
31
|
+
type = type.split(";", 2).first if type.index(";")
|
32
|
+
type
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
class ApiClient::Connection::Middlewares::Request::Logger < Faraday::Middleware
|
4
|
+
def call(env)
|
5
|
+
debug_lines = []
|
6
|
+
should_log_details = @logger.level <= ::Logger::DEBUG
|
7
|
+
|
8
|
+
gather_request_debug_lines(env, debug_lines) if should_log_details
|
9
|
+
|
10
|
+
start = CurrentTimestamp.milis
|
11
|
+
response = @app.call(env)
|
12
|
+
taken_sec = (CurrentTimestamp.milis - start) / 1000.0
|
13
|
+
|
14
|
+
gather_response_debug_lines(response, taken_sec, debug_lines) if response && should_log_details
|
15
|
+
|
16
|
+
if should_log_details
|
17
|
+
debug_lines.each { |line| line.encode!("UTF-8", invalid: :replace, undef: :replace) }
|
18
|
+
@logger.debug { debug_lines.join("\n") }
|
19
|
+
else
|
20
|
+
@logger.info { "#{env[:method].to_s.upcase} #{env[:url]}: #{"%.4f" % taken_sec} seconds" }
|
21
|
+
end
|
22
|
+
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(app, logger = nil)
|
27
|
+
@logger = logger || ::Logger.new(STDOUT)
|
28
|
+
@app = app
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def gather_request_debug_lines(env, debug_lines)
|
34
|
+
debug_lines << "> #{env[:method].to_s.upcase} #{env[:url]}"
|
35
|
+
env[:request_headers].each { |k, v| debug_lines << "> #{k}: #{v}" }
|
36
|
+
debug_lines << "> "
|
37
|
+
debug_lines << "> #{env[:body]}\n> " if env[:body] && env[:body] != ""
|
38
|
+
debug_lines
|
39
|
+
end
|
40
|
+
|
41
|
+
def gather_response_debug_lines(response, taken_sec, debug_lines)
|
42
|
+
debug_lines << "< responded in #{"%.4f" % taken_sec} seconds with HTTP #{response.status}"
|
43
|
+
response.headers.each { |k, v| debug_lines << "< #{k}: #{v}" }
|
44
|
+
debug_lines << "< "
|
45
|
+
debug_lines << "< #{response.body}\n> " if response.body && response.body != ""
|
46
|
+
debug_lines
|
47
|
+
end
|
48
|
+
|
49
|
+
class CurrentTimestamp
|
50
|
+
class << self
|
51
|
+
version = RUBY_VERSION.split('.').map(&:to_i)
|
52
|
+
|
53
|
+
if (version[0] < 2) || (version[0] == 2 && version[1] < 2)
|
54
|
+
def milis
|
55
|
+
(Time.now.to_f * 1000).to_i
|
56
|
+
end
|
57
|
+
else
|
58
|
+
def milis
|
59
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Borrowed from https://github.com/pengwynn/faraday_middleware/blob/master/lib/faraday/request/oauth.rb
|
2
|
+
class ApiClient::Connection::Middlewares::Request::OAuth < Faraday::Middleware
|
3
|
+
|
4
|
+
dependency 'simple_oauth'
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
params = env[:body] || {}
|
8
|
+
signature_params = params.reject{ |k,v| v.respond_to?(:content_type) }
|
9
|
+
|
10
|
+
header = SimpleOAuth::Header.new(env[:method], env[:url], signature_params, @options || {})
|
11
|
+
|
12
|
+
env[:request_headers]['Authorization'] = header.to_s
|
13
|
+
env[:request_headers]['User-Agent'] = "ApiClient gem v#{ApiClient::VERSION}"
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(app, options = {})
|
19
|
+
@app, @options = app, options
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|