finapps_core 5.0.5 → 5.0.10
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/.codeclimate.yml +9 -8
- data/.rubocop.yml +131 -74
- data/.tmuxinator.yml +20 -0
- data/.travis.yml +5 -6
- data/RELEASES.md +8 -0
- data/finapps_core.gemspec +10 -10
- data/lib/finapps_core.rb +1 -0
- data/lib/finapps_core/middleware/middleware.rb +7 -3
- data/lib/finapps_core/middleware/request/accept_json.rb +2 -1
- data/lib/finapps_core/middleware/request/user_agent.rb +1 -1
- data/lib/finapps_core/middleware/request/x_consumer_id.rb +20 -0
- data/lib/finapps_core/middleware/response/raise_error.rb +36 -7
- data/lib/finapps_core/rest/base_client.rb +18 -30
- data/lib/finapps_core/rest/configuration.rb +17 -4
- data/lib/finapps_core/rest/connection.rb +31 -21
- data/lib/finapps_core/rest/defaults.rb +1 -1
- data/lib/finapps_core/utils/validatable.rb +1 -1
- data/lib/finapps_core/version.rb +1 -1
- data/spec/core_extensions/object/is_integer_spec.rb +6 -7
- data/spec/middleware/request/accept_json_spec.rb +7 -3
- data/spec/middleware/request/no_encoding_basic_authentication_spec.rb +15 -6
- data/spec/middleware/request/request_id_spec.rb +4 -4
- data/spec/middleware/request/tenant_authentication_spec.rb +21 -14
- data/spec/middleware/request/user_agent_spec.rb +8 -3
- data/spec/middleware/request/x_consumer_id_spec.rb +16 -0
- data/spec/middleware/response/raise_error_spec.rb +47 -15
- data/spec/rest/base_client_spec.rb +87 -43
- data/spec/rest/configuration_spec.rb +25 -18
- data/spec/rest/credentials_spec.rb +4 -4
- data/spec/rest/defaults_spec.rb +1 -1
- data/spec/rest/resources_spec.rb +10 -20
- data/spec/spec_helper.rb +3 -3
- data/spec/utils/validatable_spec.rb +9 -8
- metadata +69 -64
@@ -31,7 +31,8 @@ module FinAppsCore
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# Performs HTTP GET, POST, UPDATE and DELETE requests.
|
34
|
-
# You shouldn't need to use this method directly,
|
34
|
+
# You shouldn't need to use this method directly,
|
35
|
+
# but it can be useful for debugging.
|
35
36
|
# Returns a hash obtained from parsing the JSON object in the response body.
|
36
37
|
#
|
37
38
|
# @param [String] path
|
@@ -42,7 +43,7 @@ module FinAppsCore
|
|
42
43
|
not_blank(path, :path)
|
43
44
|
not_blank(method, :method)
|
44
45
|
|
45
|
-
response, error_messages = execute_request(
|
46
|
+
response, error_messages = execute_request(method, path, params)
|
46
47
|
result = block_given? ? yield(response) : response_body(response)
|
47
48
|
|
48
49
|
[result, error_messages]
|
@@ -76,26 +77,19 @@ module FinAppsCore
|
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
79
|
-
def execute_request(
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
Faraday::Error::ConnectionFailed => e
|
88
|
-
handle_error e
|
89
|
-
rescue Faraday::Error::ClientError => e
|
90
|
-
errors = handle_client_error(e)
|
91
|
-
end
|
92
|
-
|
93
|
-
[response, errors]
|
80
|
+
def execute_request(method, path, params)
|
81
|
+
[send(method, path, params), []]
|
82
|
+
rescue FinAppsCore::InvalidArgumentsError,
|
83
|
+
FinAppsCore::MissingArgumentsError,
|
84
|
+
Faraday::ConnectionFailed => e
|
85
|
+
[nil, handle_error(e)]
|
86
|
+
rescue Faraday::ClientError => e
|
87
|
+
[nil, handle_client_error(e)]
|
94
88
|
end
|
95
89
|
|
96
90
|
def handle_error(error)
|
97
91
|
logger.fatal "#{self.class}##{__method__} => #{error}"
|
98
|
-
|
92
|
+
fail error
|
99
93
|
end
|
100
94
|
|
101
95
|
def handle_client_error(error)
|
@@ -103,19 +97,13 @@ module FinAppsCore
|
|
103
97
|
error.response && error.response[:error_messages] ? error.response[:error_messages] : [error.message]
|
104
98
|
end
|
105
99
|
|
106
|
-
def execute_method(
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
when :post
|
111
|
-
post(path, params)
|
112
|
-
when :put
|
113
|
-
put(path, params)
|
114
|
-
when :delete
|
115
|
-
delete(path, params)
|
116
|
-
else
|
117
|
-
raise FinAppsCore::UnsupportedHttpMethodError, "Method not supported: #{method}."
|
100
|
+
def execute_method(method, path, params)
|
101
|
+
unless %i(get post put delete).include?(method)
|
102
|
+
fail FinAppsCore::UnsupportedHttpMethodError,
|
103
|
+
"Method not supported: #{method}."
|
118
104
|
end
|
105
|
+
|
106
|
+
send(method, path, params)
|
119
107
|
end
|
120
108
|
end
|
121
109
|
end
|
@@ -8,14 +8,13 @@ module FinAppsCore
|
|
8
8
|
|
9
9
|
attr_accessor :tenant_token, :user_identifier, :user_token,
|
10
10
|
:host, :proxy, :timeout, :retry_limit, :rashify,
|
11
|
-
:log_level, :request_id
|
11
|
+
:log_level, :request_id, :consumer_id
|
12
12
|
|
13
13
|
def initialize(options = {})
|
14
14
|
FinAppsCore::REST::Defaults::DEFAULTS.merge(remove_empty_options(options))
|
15
15
|
.each {|key, value| public_send("#{key}=", value) }
|
16
|
-
|
17
|
-
|
18
|
-
raise FinAppsCore::InvalidArgumentsError, "Invalid argument. {timeout: #{timeout}}" unless timeout.integer?
|
16
|
+
fail_invalid_host
|
17
|
+
fail_invalid_timeout
|
19
18
|
end
|
20
19
|
|
21
20
|
def valid_user_credentials?
|
@@ -24,6 +23,20 @@ module FinAppsCore
|
|
24
23
|
|
25
24
|
private
|
26
25
|
|
26
|
+
def fail_invalid_host
|
27
|
+
return if valid_host?
|
28
|
+
|
29
|
+
fail FinAppsCore::InvalidArgumentsError,
|
30
|
+
"Invalid argument. {host: #{host}}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def fail_invalid_timeout
|
34
|
+
return if timeout.integer?
|
35
|
+
|
36
|
+
fail FinAppsCore::InvalidArgumentsError,
|
37
|
+
"Invalid argument. {timeout: #{timeout}}"
|
38
|
+
end
|
39
|
+
|
27
40
|
def valid_host?
|
28
41
|
host.start_with?('http://', 'https://')
|
29
42
|
end
|
@@ -8,39 +8,49 @@ module FinAppsCore
|
|
8
8
|
options = connection_options config
|
9
9
|
|
10
10
|
Faraday.new(options) do |conn|
|
11
|
-
conn.request :accept_json
|
12
|
-
conn.request :user_agent
|
13
|
-
if config.valid_user_credentials?
|
14
|
-
conn.request :no_encoding_basic_authentication, config.user_token
|
15
|
-
else
|
16
|
-
conn.request :tenant_authentication, config.tenant_token
|
17
|
-
end
|
18
|
-
conn.request :json
|
19
|
-
conn.request :retry
|
20
|
-
conn.request :multipart
|
21
|
-
conn.request :url_encoded
|
22
|
-
conn.request :request_id, config.request_id if config.request_id
|
23
|
-
|
24
11
|
conn.use FinAppsCore::Middleware::RaiseError
|
25
|
-
conn
|
26
|
-
|
27
|
-
|
28
|
-
conn.response :logger, logger, bodies: true
|
12
|
+
init_connection_request conn, config
|
13
|
+
init_connection_response conn, logger
|
14
|
+
init_connection_auth conn, config
|
29
15
|
|
30
16
|
# Adapter (ensure that the adapter is always last.)
|
31
17
|
conn.adapter Faraday.default_adapter
|
32
18
|
end
|
33
19
|
end
|
34
|
-
|
20
|
+
|
21
|
+
def init_connection_response(conn, logger)
|
22
|
+
conn.response :logger, logger, bodies: true
|
23
|
+
conn.response :json,
|
24
|
+
content_type: /\bjson$/,
|
25
|
+
parser_options: {symbolize_names: true}
|
26
|
+
end
|
27
|
+
|
28
|
+
def init_connection_request(conn, config)
|
29
|
+
conn.request :accept_json
|
30
|
+
conn.request :user_agent
|
31
|
+
conn.request :x_consumer_id, config.consumer_id if config.consumer_id
|
32
|
+
conn.request :json
|
33
|
+
conn.request :retry
|
34
|
+
conn.request :multipart
|
35
|
+
conn.request :url_encoded
|
36
|
+
conn.request :request_id, config.request_id if config.request_id
|
37
|
+
end
|
38
|
+
|
39
|
+
def init_connection_auth(conn, config)
|
40
|
+
if config.valid_user_credentials?
|
41
|
+
conn.request :no_encoding_basic_authentication, config.user_token
|
42
|
+
else
|
43
|
+
conn.request :tenant_authentication, config.tenant_token
|
44
|
+
end
|
45
|
+
end
|
35
46
|
|
36
47
|
def connection_options(config)
|
37
48
|
{
|
38
49
|
url: "#{config.host}/v#{Defaults::API_VERSION}/",
|
39
|
-
request: {
|
40
|
-
|
50
|
+
request: {open_timeout: config.timeout,
|
51
|
+
timeout: config.timeout}
|
41
52
|
}
|
42
53
|
end
|
43
|
-
module_function :connection_options
|
44
54
|
end
|
45
55
|
end
|
46
56
|
end
|
@@ -8,7 +8,7 @@ module FinAppsCore
|
|
8
8
|
# Adds validation capabilities when included into other classes
|
9
9
|
module Validatable
|
10
10
|
def not_blank(value, name = nil)
|
11
|
-
|
11
|
+
fail FinAppsCore::MissingArgumentsError, name.nil? ? nil : ": #{name}" if nil_or_empty?(value)
|
12
12
|
end
|
13
13
|
|
14
14
|
def nil_or_empty?(value)
|
data/lib/finapps_core/version.rb
CHANGED
@@ -2,16 +2,15 @@
|
|
2
2
|
|
3
3
|
RSpec.describe ObjectExtensions do
|
4
4
|
context 'when refining Object' do
|
5
|
-
using
|
5
|
+
using described_class
|
6
6
|
|
7
7
|
describe '#integer?' do
|
8
|
-
context '
|
9
|
-
|
10
|
-
it { expect(subject.integer?).to eq(true) }
|
8
|
+
context 'with integers' do
|
9
|
+
it { expect(rand(1..10).integer?).to eq(true) }
|
11
10
|
end
|
12
|
-
|
13
|
-
|
14
|
-
it { expect(
|
11
|
+
|
12
|
+
context 'with non integers' do
|
13
|
+
it { expect(rand.integer?).to eq(false) }
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -2,12 +2,16 @@
|
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::AcceptJson do
|
4
4
|
let(:fake_app) { proc {|env| env } }
|
5
|
+
|
5
6
|
describe '#call' do
|
6
|
-
subject {
|
7
|
-
|
7
|
+
subject(:accept_json) { described_class.new(fake_app) }
|
8
|
+
|
9
|
+
env = {request_headers: {}}
|
8
10
|
|
9
11
|
it('generates a UserAgent header') do
|
10
|
-
|
12
|
+
header_key = FinAppsCore::Middleware::AcceptJson::KEY
|
13
|
+
expect(accept_json.call(env)[:request_headers][header_key])
|
14
|
+
.to eq('application/json')
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
@@ -7,22 +7,31 @@ RSpec.describe FinAppsCore::Middleware::NoEncodingBasicAuthentication do
|
|
7
7
|
app = proc {|env| env }
|
8
8
|
|
9
9
|
context 'when credentials were provided' do
|
10
|
-
let(:middleware) {
|
10
|
+
let(:middleware) { described_class.new(app, :token) }
|
11
11
|
let(:expected_header_value) { 'Bearer token' }
|
12
12
|
|
13
13
|
context 'when header was not previously set' do
|
14
|
-
let(:request_env) { { request_headers: {} } }
|
15
14
|
subject(:result) { middleware.call(request_env) }
|
16
15
|
|
17
|
-
|
16
|
+
let(:request_env) { {request_headers: {}} }
|
17
|
+
|
18
|
+
it('generates a header') {
|
19
|
+
expect(result[:request_headers][key]).to eq(expected_header_value)
|
20
|
+
}
|
18
21
|
end
|
19
22
|
|
20
23
|
context 'when header was previously set' do
|
21
|
-
let(:request_env) { { request_headers: { key => 'foo' } } }
|
22
24
|
subject(:result) { middleware.call(request_env) }
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
+
let(:request_env) { {request_headers: {key => 'foo'}} }
|
27
|
+
|
28
|
+
it('does not override existing header') {
|
29
|
+
expect(result[:request_headers][key]).to eq('foo')
|
30
|
+
}
|
31
|
+
|
32
|
+
it('does not generate a header') {
|
33
|
+
expect(result[:request_headers][key]).not_to eq(expected_header_value)
|
34
|
+
}
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::RequestId do
|
4
|
-
let(:key) { FinAppsCore::Middleware::RequestId::KEY }
|
5
4
|
let(:id) { 'request_id' }
|
6
5
|
let(:fake_app) { proc {|env| env } }
|
7
|
-
let(:env) { {
|
6
|
+
let(:env) { {request_headers: {}} }
|
8
7
|
|
9
8
|
describe '#call' do
|
10
|
-
subject {
|
9
|
+
subject(:request_id) { described_class.new(fake_app, id) }
|
11
10
|
|
12
11
|
it('generates a X-Request-Id header') do
|
13
|
-
|
12
|
+
key = FinAppsCore::Middleware::RequestId::KEY
|
13
|
+
expect(request_id.call(env)[:request_headers][key]).to eq(id)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::TenantAuthentication do
|
4
|
-
let(:valid_tenant_options) { VALID_CREDENTIALS }
|
5
|
-
let(:key) { FinAppsCore::Middleware::TenantAuthentication::KEY }
|
6
|
-
|
7
4
|
describe '#call' do
|
8
|
-
|
5
|
+
subject(:actual_header) do
|
6
|
+
middleware.call(request_env)[:request_headers][key]
|
7
|
+
end
|
9
8
|
|
10
9
|
context 'when company credentials were provided' do
|
11
|
-
let(:
|
12
|
-
let(:
|
10
|
+
let(:key) { FinAppsCore::Middleware::TenantAuthentication::KEY }
|
11
|
+
let(:middleware) do
|
12
|
+
fake_app = proc {|env| env }
|
13
|
+
described_class.new(fake_app, VALID_CREDENTIALS[:token])
|
14
|
+
end
|
15
|
+
let(:expected_header) { VALID_CREDENTIALS[:token] }
|
13
16
|
|
14
17
|
context 'when header was not previously set' do
|
15
|
-
let(:request_env) { {
|
16
|
-
subject(:actual_header) { middleware.call(request_env)[:request_headers][key] }
|
18
|
+
let(:request_env) { {request_headers: {}} }
|
17
19
|
|
18
|
-
it('generates a Tenant Authentication header') {
|
20
|
+
it('generates a Tenant Authentication header') {
|
21
|
+
expect(actual_header).to eq(expected_header)
|
22
|
+
}
|
19
23
|
end
|
20
24
|
|
21
25
|
context 'when header was previously set' do
|
22
|
-
let(:
|
23
|
-
|
24
|
-
|
26
|
+
let(:request_env) { {request_headers: {key => 'foo'}} }
|
27
|
+
|
28
|
+
it('does not override existing Tenant Authentication header') {
|
29
|
+
expect(actual_header).to eq('foo')
|
30
|
+
}
|
25
31
|
|
26
|
-
it('does not
|
27
|
-
|
32
|
+
it('does not generate a Tenant Authentication header') {
|
33
|
+
expect(actual_header).not_to eq(expected_header)
|
34
|
+
}
|
28
35
|
end
|
29
36
|
end
|
30
37
|
end
|
@@ -2,12 +2,17 @@
|
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::UserAgent do
|
4
4
|
let(:fake_app) { proc {|env| env } }
|
5
|
+
|
5
6
|
describe '#call' do
|
6
|
-
subject {
|
7
|
-
|
7
|
+
subject(:user_agent) { described_class.new(fake_app) }
|
8
|
+
|
9
|
+
let(:key) { FinAppsCore::Middleware::UserAgent::KEY }
|
10
|
+
|
11
|
+
env = {request_headers: {}}
|
8
12
|
|
9
13
|
it('generates a UserAgent header') do
|
10
|
-
expect(
|
14
|
+
expect(user_agent.call(env)[:request_headers][key])
|
15
|
+
.to start_with('finapps-ruby')
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe FinAppsCore::Middleware::XConsumerId do
|
4
|
+
let(:id) { 'valid_consumer_id' }
|
5
|
+
let(:fake_app) { proc {|env| env } }
|
6
|
+
let(:env) { {request_headers: {}} }
|
7
|
+
|
8
|
+
describe '#call' do
|
9
|
+
subject(:x_consumer_id) { described_class.new(fake_app, id) }
|
10
|
+
|
11
|
+
it('generates an X-Consumer-ID header') do
|
12
|
+
key = FinAppsCore::Middleware::XConsumerId::KEY
|
13
|
+
expect(x_consumer_id.call(env)[:request_headers][key]).to eq(id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -2,39 +2,71 @@
|
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::RaiseError do
|
4
4
|
let(:fake_app) { proc {|env| env } }
|
5
|
-
|
5
|
+
|
6
|
+
before do
|
7
|
+
stub_const('Env', Struct.new(:status, :response_headers, :body))
|
8
|
+
end
|
6
9
|
|
7
10
|
describe '#on_complete' do
|
8
|
-
subject {
|
11
|
+
subject(:error_raiser) { described_class.new(fake_app) }
|
9
12
|
|
10
|
-
context '
|
13
|
+
context 'with successful requests' do
|
11
14
|
let(:env) { Env.new(200) }
|
12
|
-
|
15
|
+
|
16
|
+
it { expect { error_raiser.on_complete(env) }.not_to raise_error }
|
13
17
|
end
|
14
|
-
|
15
|
-
|
18
|
+
|
19
|
+
context 'with invalid session errors' do
|
20
|
+
let(:env) do
|
21
|
+
body = '{"messages":["Invalid User Identifier or Credentials"]}'
|
22
|
+
Env.new(401, {}, body)
|
23
|
+
end
|
24
|
+
|
16
25
|
error_message = 'API Invalid Session'
|
17
|
-
it {
|
26
|
+
it {
|
27
|
+
expect { error_raiser.on_complete(env) }
|
28
|
+
.to raise_error(FinAppsCore::ApiUnauthenticatedError, error_message)
|
29
|
+
}
|
18
30
|
end
|
19
|
-
|
31
|
+
|
32
|
+
context 'with client errors' do
|
20
33
|
let(:env) { Env.new(404, {}, '{"messages":["Resource Not Found"]}') }
|
34
|
+
|
21
35
|
error_message = 'the server responded with status 404'
|
22
|
-
it {
|
36
|
+
it {
|
37
|
+
expect { error_raiser.on_complete(env) }
|
38
|
+
.to raise_error(Faraday::ClientError, error_message)
|
39
|
+
}
|
23
40
|
end
|
24
|
-
|
41
|
+
|
42
|
+
context 'with connection failed error' do
|
25
43
|
let(:env) { Env.new(407) }
|
44
|
+
|
26
45
|
error_message = 'Connection Failed'
|
27
|
-
it {
|
46
|
+
it {
|
47
|
+
expect { error_raiser.on_complete(env) }
|
48
|
+
.to raise_error(FinAppsCore::ConnectionFailedError, error_message)
|
49
|
+
}
|
28
50
|
end
|
29
|
-
|
51
|
+
|
52
|
+
context 'with session timeout error' do
|
30
53
|
let(:env) { Env.new(419) }
|
54
|
+
|
31
55
|
error_message = 'API Session Timed out'
|
32
|
-
it {
|
56
|
+
it {
|
57
|
+
expect { error_raiser.on_complete(env) }
|
58
|
+
.to raise_error(FinAppsCore::ApiSessionTimeoutError, error_message)
|
59
|
+
}
|
33
60
|
end
|
34
|
-
|
61
|
+
|
62
|
+
context 'with user lockout error' do
|
35
63
|
let(:env) { Env.new(403, {}, '{"messages":["Account is locked"]}') }
|
64
|
+
|
36
65
|
error_message = 'User is Locked'
|
37
|
-
it {
|
66
|
+
it {
|
67
|
+
expect { error_raiser.on_complete(env) }
|
68
|
+
.to raise_error(FinAppsCore::UserLockoutError, error_message)
|
69
|
+
}
|
38
70
|
end
|
39
71
|
end
|
40
72
|
end
|