finapps_core 5.0.6 → 5.0.11

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.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +4 -1
  3. data/.github/release-drafter.yml +49 -0
  4. data/.github/workflows/main.yaml +38 -0
  5. data/.github/workflows/release-drafter.yml +15 -0
  6. data/.github/workflows/release.yml +54 -0
  7. data/.github/workflows/verify-pr-labeled.yml +14 -0
  8. data/.rubocop.yml +123 -73
  9. data/.tmuxinator.yml +20 -0
  10. data/.travis.yml +5 -6
  11. data/RELEASES.md +8 -0
  12. data/finapps_core.gemspec +9 -10
  13. data/lib/finapps_core.rb +1 -0
  14. data/lib/finapps_core/middleware/middleware.rb +7 -3
  15. data/lib/finapps_core/middleware/request/accept_json.rb +2 -1
  16. data/lib/finapps_core/middleware/request/user_agent.rb +1 -1
  17. data/lib/finapps_core/middleware/request/x_consumer_id.rb +20 -0
  18. data/lib/finapps_core/middleware/response/raise_error.rb +36 -7
  19. data/lib/finapps_core/rest/base_client.rb +20 -32
  20. data/lib/finapps_core/rest/configuration.rb +17 -4
  21. data/lib/finapps_core/rest/connection.rb +31 -21
  22. data/lib/finapps_core/rest/defaults.rb +1 -1
  23. data/lib/finapps_core/utils/loggeable.rb +1 -1
  24. data/lib/finapps_core/utils/validatable.rb +1 -1
  25. data/lib/finapps_core/version.rb +1 -1
  26. data/spec/core_extensions/object/is_integer_spec.rb +6 -7
  27. data/spec/middleware/request/accept_json_spec.rb +7 -3
  28. data/spec/middleware/request/no_encoding_basic_authentication_spec.rb +15 -6
  29. data/spec/middleware/request/request_id_spec.rb +4 -4
  30. data/spec/middleware/request/tenant_authentication_spec.rb +21 -14
  31. data/spec/middleware/request/user_agent_spec.rb +8 -3
  32. data/spec/middleware/request/x_consumer_id_spec.rb +16 -0
  33. data/spec/middleware/response/raise_error_spec.rb +47 -15
  34. data/spec/rest/base_client_spec.rb +87 -43
  35. data/spec/rest/configuration_spec.rb +25 -18
  36. data/spec/rest/credentials_spec.rb +4 -4
  37. data/spec/rest/defaults_spec.rb +1 -1
  38. data/spec/rest/resources_spec.rb +10 -20
  39. data/spec/spec_helper.rb +3 -3
  40. data/spec/support/fake_api.rb +1 -1
  41. data/spec/utils/validatable_spec.rb +9 -8
  42. metadata +73 -84
@@ -0,0 +1,8 @@
1
+ ## [5.0.7] - 2020-02-11
2
+
3
+ ### Added
4
+ * X-Consumer-ID header ([#49][i49])
5
+
6
+ [i49]: https://github.com/finapps/ruby-client-core/issues/49
7
+
8
+ [5.0.7]: https://github.com/finapps/ruby-client-core/compare/5.0.6...5.0.7
@@ -1,6 +1,6 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
- lib = File.expand_path('../lib', __FILE__)
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'finapps_core/version'
6
6
  Gem::Specification.new do |spec|
@@ -20,17 +20,16 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = Dir['spec/**/*.rb']
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_runtime_dependency 'faraday', '~> 0.15', '>= 0.15.3'
24
- spec.add_runtime_dependency 'faraday_middleware', '~> 0.12', '>= 0.12.2'
23
+ spec.add_runtime_dependency 'faraday', '~> 1.0', '>= 1.0.1'
24
+ spec.add_runtime_dependency 'faraday_middleware', '~> 1.0', '>= 1.0'
25
25
 
26
- spec.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.2'
26
+ spec.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.2'
27
27
  spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0', '>= 1.0.9'
28
- spec.add_development_dependency 'gem-release', '~> 2.0', '>= 2.0.3'
29
- spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.2'
28
+ spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1'
30
29
  spec.add_development_dependency 'rspec', '~> 3.8', '>= 3.8.0'
31
- spec.add_development_dependency 'rubocop', '~> 0.75', '>= 0.75.0'
32
- spec.add_development_dependency 'rubocop-performance', '~> 1.5', '>= 1.5.0'
33
- spec.add_development_dependency 'rubocop-rspec', '~> 1.36', '>= 1.36.0'
30
+ spec.add_development_dependency 'rubocop', '~> 0.86', '>= 0.86.0'
31
+ spec.add_development_dependency 'rubocop-performance', '~> 1.6', '>= 1.6.1'
32
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.40', '>= 1.40.0'
34
33
  spec.add_development_dependency 'sinatra', '~> 2.0', '>= 2.0.5'
35
34
  spec.add_development_dependency 'webmock', '~> 3.6', '>= 3.6.0'
36
35
 
@@ -17,6 +17,7 @@ require 'finapps_core/middleware/request/no_encoding_basic_authentication'
17
17
  require 'finapps_core/middleware/request/accept_json'
18
18
  require 'finapps_core/middleware/request/user_agent'
19
19
  require 'finapps_core/middleware/request/request_id'
20
+ require 'finapps_core/middleware/request/x_consumer_id'
20
21
  require 'finapps_core/middleware/response/raise_error'
21
22
  require 'finapps_core/middleware/middleware'
22
23
 
@@ -6,9 +6,12 @@ module FinAppsCore
6
6
  module Middleware
7
7
  autoload :AcceptJson, 'finapps_core/middleware/request/accept_json'
8
8
  autoload :UserAgent, 'finapps_core/middleware/request/user_agent'
9
- autoload :NoEncodingBasicAuthentication, 'finapps_core/middleware/request/no_encoding_basic_authentication'
10
- autoload :TenantAuthentication, 'finapps_core/middleware/request/tenant_authentication'
9
+ autoload :NoEncodingBasicAuthentication,
10
+ 'finapps_core/middleware/request/no_encoding_basic_authentication'
11
+ autoload :TenantAuthentication,
12
+ 'finapps_core/middleware/request/tenant_authentication'
11
13
  autoload :RequestId, 'finapps_core/middleware/request/request_id'
14
+ autoload :XConsumerId, 'finapps_core/middleware/request/x_consumer_id'
12
15
 
13
16
  if Faraday::Middleware.respond_to? :register_middleware
14
17
  Faraday::Request.register_middleware \
@@ -16,7 +19,8 @@ module FinAppsCore
16
19
  user_agent: -> { UserAgent },
17
20
  no_encoding_basic_authentication: -> { NoEncodingBasicAuthentication },
18
21
  tenant_authentication: -> { TenantAuthentication },
19
- request_id: -> { RequestId }
22
+ request_id: -> { RequestId },
23
+ x_consumer_id: -> { XConsumerId }
20
24
  end
21
25
  end
22
26
  end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module FinAppsCore
4
4
  module Middleware
5
- # This middleware sets the Accept request-header field to specify JSON as acceptable media type for the response.
5
+ # This middleware sets the Accept request-header field to specify JSON
6
+ # as acceptable media type for the response.
6
7
  class AcceptJson < Faraday::Middleware
7
8
  KEY = 'Accept' unless defined? KEY
8
9
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module FinAppsCore
4
4
  module Middleware
5
- # This middleware sets the User-Agent request-header field to identify thei client.
5
+ # This middleware sets the User-Agent request-header field to identify the client.
6
6
  class UserAgent < Faraday::Middleware
7
7
  KEY = 'User-Agent' unless defined? KEY
8
8
  RUBY = "#{RUBY_ENGINE}/#{RUBY_PLATFORM} #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FinAppsCore
4
+ module Middleware
5
+ # Adds a header to specify consumer to retrieve data for
6
+ class XConsumerId < Faraday::Middleware
7
+ KEY = 'X-Consumer-ID' unless defined? KEY
8
+
9
+ def initialize(app, x_consumer_id)
10
+ super(app)
11
+ @x_consumer_id = x_consumer_id.to_s.strip
12
+ end
13
+
14
+ def call(env)
15
+ env[:request_headers][KEY] ||= @x_consumer_id
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -16,12 +16,7 @@ module FinAppsCore
16
16
  def on_complete(env)
17
17
  return if SUCCESS_STATUSES.include?(env[:status])
18
18
 
19
- raise(FinAppsCore::ApiUnauthenticatedError, 'API Invalid Session') if env[:status] == API_UNAUTHENTICATED
20
- raise(FinAppsCore::ApiSessionTimeoutError, 'API Session Timed out') if env[:status] == API_SESSION_TIMEOUT
21
- raise(FinAppsCore::ConnectionFailedError, 'Connection Failed') if env[:status] == CONNECTION_FAILED_STATUS
22
- raise(FinAppsCore::UserLockoutError, 'User is Locked') if user_is_locked?(env)
23
-
24
- raise(Faraday::ClientError, response_values(env))
19
+ failures env
25
20
  end
26
21
 
27
22
  def response_values(env)
@@ -35,6 +30,39 @@ module FinAppsCore
35
30
 
36
31
  private
37
32
 
33
+ def failures(env)
34
+ api_authentication_fail env
35
+ api_session_timeout_fail env
36
+ locked_user_fail env
37
+ connection_fail env
38
+
39
+ fail(Faraday::ClientError, response_values(env))
40
+ end
41
+
42
+ def locked_user_fail(env)
43
+ return unless user_is_locked?(env)
44
+
45
+ fail(FinAppsCore::UserLockoutError, 'User is Locked')
46
+ end
47
+
48
+ def api_session_timeout_fail(env)
49
+ return unless env[:status] == API_SESSION_TIMEOUT
50
+
51
+ fail(FinAppsCore::ApiSessionTimeoutError, 'API Session Timed out')
52
+ end
53
+
54
+ def connection_fail(env)
55
+ return unless env[:status] == CONNECTION_FAILED_STATUS
56
+
57
+ fail(FinAppsCore::ConnectionFailedError, 'Connection Failed')
58
+ end
59
+
60
+ def api_authentication_fail(env)
61
+ return unless env[:status] == API_UNAUTHENTICATED
62
+
63
+ fail(FinAppsCore::ApiUnauthenticatedError, 'API Invalid Session')
64
+ end
65
+
38
66
  def error_messages(body)
39
67
  return nil if empty?(body)
40
68
 
@@ -59,7 +87,8 @@ module FinAppsCore
59
87
  end
60
88
 
61
89
  def user_is_locked?(env)
62
- env.status == FORBIDDEN && error_messages(env.body)&.[](0)&.downcase == LOCKOUT_MESSAGE
90
+ env.status == FORBIDDEN &&
91
+ error_messages(env.body)&.[](0)&.downcase == LOCKOUT_MESSAGE
63
92
  end
64
93
 
65
94
  def symbolize(obj)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './configuration.rb'
4
- require_relative './connection.rb'
3
+ require_relative './configuration'
4
+ require_relative './connection'
5
5
  require_relative '../utils/loggeable'
6
6
  require_relative '../utils/validatable'
7
7
 
@@ -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, but it can be useful for debugging.
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(path, method, params)
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(path, method, params)
80
- response = nil
81
- errors = []
82
-
83
- begin
84
- response = execute_method path, method, params
85
- rescue FinAppsCore::InvalidArgumentsError,
86
- FinAppsCore::MissingArgumentsError,
87
- Faraday::Error::ConnectionFailed => e
88
- handle_error e
89
- rescue Faraday::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
- raise error
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(path, method, params)
107
- case method
108
- when :get
109
- get(path)
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
- raise FinAppsCore::InvalidArgumentsError, "Invalid argument. {host: #{host}}" unless valid_host?
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.response :json,
26
- content_type: /\bjson$/,
27
- parser_options: { symbolize_names: true }
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
- module_function :faraday
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: { open_timeout: config.timeout,
40
- timeout: config.timeout }
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
@@ -12,7 +12,7 @@ module FinAppsCore
12
12
  host: 'https://api.finclear.io',
13
13
  timeout: 30,
14
14
  proxy: nil,
15
- log_level: Logger::INFO
15
+ log_level: Logger::UNKNOWN
16
16
  }.freeze
17
17
  end
18
18
  end
@@ -7,7 +7,7 @@ module FinAppsCore
7
7
  def logger
8
8
  @logger ||= begin
9
9
  require 'logger'
10
- logger = Logger.new(STDOUT)
10
+ logger = Logger.new($stdout)
11
11
  logger.level = FinAppsCore::REST::Defaults::DEFAULTS[:log_level]
12
12
  logger
13
13
  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
- raise FinAppsCore::MissingArgumentsError, name.nil? ? nil : ": #{name}" if nil_or_empty?(value)
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FinAppsCore
4
- VERSION = '5.0.6'
4
+ VERSION = '5.0.11'
5
5
  end
@@ -2,16 +2,15 @@
2
2
 
3
3
  RSpec.describe ObjectExtensions do
4
4
  context 'when refining Object' do
5
- using ObjectExtensions
5
+ using described_class
6
6
 
7
7
  describe '#integer?' do
8
- context 'for integers' do
9
- subject { rand(1..10) }
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
- context 'for non integers' do
13
- subject { rand }
14
- it { expect(subject.integer?).to eq(false) }
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 { FinAppsCore::Middleware::AcceptJson.new(fake_app) }
7
- env = { request_headers: {} }
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
- expect(subject.call(env)[:request_headers][FinAppsCore::Middleware::AcceptJson::KEY]).to eq('application/json')
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