endpoint-flux 1.1.4

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/CONTRIBUTING.md +18 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +37 -0
  6. data/README.md +607 -0
  7. data/circle.yml +14 -0
  8. data/endpoint_flux.gemspec +18 -0
  9. data/lib/endpoint_flux.rb +20 -0
  10. data/lib/endpoint_flux/class_loader.rb +58 -0
  11. data/lib/endpoint_flux/config.rb +85 -0
  12. data/lib/endpoint_flux/config/interceptor.rb +23 -0
  13. data/lib/endpoint_flux/config/middleware.rb +38 -0
  14. data/lib/endpoint_flux/config/rescue_from.rb +28 -0
  15. data/lib/endpoint_flux/endpoint.rb +81 -0
  16. data/lib/endpoint_flux/exceptions.rb +10 -0
  17. data/lib/endpoint_flux/exceptions/base.rb +21 -0
  18. data/lib/endpoint_flux/exceptions/forbidden.rb +12 -0
  19. data/lib/endpoint_flux/exceptions/not_found.rb +12 -0
  20. data/lib/endpoint_flux/exceptions/service_unavailable.rb +12 -0
  21. data/lib/endpoint_flux/exceptions/unauthorized.rb +12 -0
  22. data/lib/endpoint_flux/exceptions/validation.rb +13 -0
  23. data/lib/endpoint_flux/middlewares.rb +8 -0
  24. data/lib/endpoint_flux/middlewares/authenticator/skip.rb +11 -0
  25. data/lib/endpoint_flux/middlewares/authorizator/skip.rb +11 -0
  26. data/lib/endpoint_flux/middlewares/decorator/add_status.rb +12 -0
  27. data/lib/endpoint_flux/middlewares/decorator/skip.rb +11 -0
  28. data/lib/endpoint_flux/middlewares/policy/skip.rb +11 -0
  29. data/lib/endpoint_flux/middlewares/validator/empty.rb +12 -0
  30. data/lib/endpoint_flux/rails/concerns/endpoint_controller.rb +43 -0
  31. data/lib/endpoint_flux/request.rb +17 -0
  32. data/lib/endpoint_flux/response.rb +30 -0
  33. data/lib/endpoint_flux/version.rb +3 -0
  34. data/spec/lib/class_loader_spec.rb +31 -0
  35. data/spec/lib/config/default_middlewares_spec.rb +21 -0
  36. data/spec/lib/config/endpoints_namespace_spec.rb +13 -0
  37. data/spec/lib/config/flow_spec.rb +8 -0
  38. data/spec/lib/config/interceptor_spec.rb +34 -0
  39. data/spec/lib/config/middleware_spec.rb +62 -0
  40. data/spec/lib/config/rescue_from_spec.rb +45 -0
  41. data/spec/lib/endpoint/flow_spec.rb +43 -0
  42. data/spec/lib/endpoint/middlewares_spec.rb +110 -0
  43. data/spec/lib/endpoint/perform_spec.rb +61 -0
  44. data/spec/lib/endpoint/rescue_from_spec.rb +61 -0
  45. data/spec/lib/endpoint_flux/rails/concerns/endpoint_controller_spec.rb +75 -0
  46. data/spec/lib/endpoint_flux/request_spec.rb +44 -0
  47. data/spec/lib/exceptions/forbidden_spec.rb +12 -0
  48. data/spec/lib/exceptions/not_found_spec.rb +12 -0
  49. data/spec/lib/exceptions/service_unavailable_spec.rb +12 -0
  50. data/spec/lib/exceptions/unauthorized_spec.rb +12 -0
  51. data/spec/lib/exceptions/validation_spec.rb +14 -0
  52. data/spec/lib/middlewares/authenticator/skip_spec.rb +5 -0
  53. data/spec/lib/middlewares/authorizator/skip_spec.rb +5 -0
  54. data/spec/lib/middlewares/decorator/add_status_spec.rb +17 -0
  55. data/spec/lib/middlewares/decorator/skip_spec.rb +5 -0
  56. data/spec/lib/middlewares/policy/skip_spec.rb +5 -0
  57. data/spec/lib/middlewares/shared_examples.rb +19 -0
  58. data/spec/lib/middlewares/validator/empty_spec.rb +15 -0
  59. data/spec/lib/response_spec.rb +131 -0
  60. data/spec/spec_helper.rb +52 -0
  61. metadata +157 -0
@@ -0,0 +1,12 @@
1
+ module EndpointFlux
2
+ module Exceptions
3
+ class Unauthorized < EndpointFlux::Exceptions::Base
4
+ def to_hash
5
+ {
6
+ status: 401,
7
+ message: 'Unauthorized'
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module EndpointFlux
2
+ module Exceptions
3
+ class Validation < EndpointFlux::Exceptions::Base
4
+ def to_hash
5
+ {
6
+ status: 422,
7
+ message: 'validation errors',
8
+ errors: @messages
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Middlewares
2
+ require_relative 'middlewares/authenticator/skip'
3
+ require_relative 'middlewares/authorizator/skip'
4
+ require_relative 'middlewares/decorator/skip'
5
+ require_relative 'middlewares/decorator/add_status'
6
+ require_relative 'middlewares/policy/skip'
7
+ require_relative 'middlewares/validator/empty'
8
+ end
@@ -0,0 +1,11 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Authenticator
4
+ module Skip
5
+ def self.perform(*args, _options)
6
+ args
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Authorizator
4
+ module Skip
5
+ def self.perform(*args, _opts)
6
+ args
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Decorator
4
+ module AddStatus
5
+ def self.perform(request, response, status)
6
+ response.body[:status] = status
7
+ [request, response]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Decorator
4
+ module Skip
5
+ def self.perform(*args, _options)
6
+ args
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Policy
4
+ module Skip
5
+ def self.perform(*args, _options)
6
+ args
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module EndpointFlux
2
+ module Middlewares
3
+ module Validator
4
+ module Empty
5
+ def self.perform(request, response, _options)
6
+ request.params = {}
7
+ [request, response]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ module EndpointFlux
2
+ module Rails
3
+ module Concerns
4
+ module EndpointController
5
+ extend ActiveSupport::Concern
6
+
7
+ def present(namespace)
8
+ _, response = endpoint_for(namespace).perform(request_object)
9
+
10
+ headers.merge! response.headers
11
+ render json: response.body
12
+ end
13
+
14
+ def endpoint_for(namespace)
15
+ return namespace unless ::EndpointFlux.config.endpoints_namespace
16
+ (::EndpointFlux.config.endpoints_namespace + '/' + namespace).camelize.constantize
17
+ end
18
+
19
+ def request_object
20
+ ::EndpointFlux::Request.new(
21
+ headers: headers.merge('Authorization' => request.headers['authorization']),
22
+ remote_ip: remote_ip,
23
+ params: endpoint_params
24
+ )
25
+ end
26
+
27
+ def endpoint_params
28
+ params.permit!.except(:controller, :action, :format).to_h.deep_symbolize_keys
29
+ end
30
+
31
+ def remote_ip
32
+ ip = request.remote_ip.to_s
33
+
34
+ if ip == '127.0.0.1'
35
+ ip = request.env['HTTP_X_FORWARDED_FOR']
36
+ end
37
+
38
+ ip
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ module EndpointFlux
2
+ class Request
3
+ def initialize(headers: {}, remote_ip: '', params: {}, namespace: nil)
4
+ @headers = headers
5
+ @remote_ip = remote_ip
6
+ @params = params
7
+ @namespace = namespace
8
+ end
9
+
10
+ attr_accessor :params
11
+ attr_accessor :headers
12
+ attr_accessor :remote_ip
13
+ attr_accessor :namespace
14
+ attr_accessor :endpoint
15
+ attr_accessor :scope
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ module EndpointFlux
2
+ class Response
3
+ def initialize(headers: {}, body: {})
4
+ @body = body
5
+ @headers = headers
6
+ end
7
+
8
+ attr_accessor :body, :headers
9
+
10
+ def success?
11
+ body[:status] && body[:status].between?(200, 209)
12
+ end
13
+
14
+ def invalid?
15
+ body[:status] == 422
16
+ end
17
+
18
+ def forbidden?
19
+ body[:status] == 403
20
+ end
21
+
22
+ def unauthorized?
23
+ body[:status] == 401
24
+ end
25
+
26
+ def not_found?
27
+ body[:status] == 404
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module EndpointFlux
2
+ VERSION = '1.1.4'.freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::ClassLoader do
4
+ describe '#string_to_class_name' do
5
+ it 'converts string to class name' do
6
+ expect(subject.string_to_class_name('hey/bey/cey')).to eq('Hey::Bey::Cey')
7
+ end
8
+ end
9
+
10
+ describe '#load_class!' do
11
+ context 'when wrong params given' do
12
+ it 'fails if the class is not existing' do
13
+ expect { subject.load_class!('hey/bey') }
14
+ .to raise_error('The [hey/bey] should be a string representing a class')
15
+ end
16
+
17
+ it 'fails if the class name is invalid' do
18
+ expect { subject.load_class!('111/bey') }
19
+ .to raise_error('The [111/bey] should be a string representing a class')
20
+ end
21
+ end
22
+
23
+ context 'when valid params given' do
24
+ let(:sample_class) { stub_const 'SampleClass::SecondLevel', Class.new }
25
+
26
+ it 'returns the class back' do
27
+ expect(subject.load_class!(sample_class)).to be(sample_class)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config do
4
+ describe '#default_middlewares' do
5
+ before do
6
+ stub_const('EndpointFlux::Middlewares::Authenticator::Sample', Class.new)
7
+ EndpointFlux::Middlewares::Authenticator::Sample.class_eval do
8
+ def self.perform(_, headers, response)
9
+ [{}, headers, response]
10
+ end
11
+ end
12
+
13
+ subject.default_middlewares :authenticator, 'sample'
14
+ end
15
+ let(:middleware) { subject.default_middlewares[:authenticator].first }
16
+
17
+ it 'sets default middleware' do
18
+ expect(middleware.klass).to be(EndpointFlux::Middlewares::Authenticator::Sample)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config do
4
+ describe '#endpoints_namespace' do
5
+ it 'sets default endpoints namespace' do
6
+ stub_const 'Some::Sample', Class.new
7
+
8
+ subject.endpoints_namespace 'some/sample'
9
+
10
+ expect(subject.endpoints_namespace).to be == 'some/sample'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config do
4
+ it 'sets flow' do
5
+ subject.flow %i[hey bey]
6
+ expect(subject.flow).to eq(%i[hey bey])
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config::Interceptor do
4
+ describe '#add' do
5
+ context 'when wrong params given' do
6
+ it 'fails when no block given' do
7
+ expect { subject.add() }.to raise_error('Block not given')
8
+ end
9
+ end
10
+
11
+ context 'when valid params given' do
12
+ let(:block) { proc {} }
13
+
14
+ it 'adds the handler' do
15
+ subject.add(&block)
16
+
17
+ expect(subject.handlers).to include(block)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#run' do
23
+ let(:sample_exception) { stub_const 'SampleException', Class.new(Exception) }
24
+ let(:block) { proc { raise SampleException } }
25
+
26
+ context 'when valid params given' do
27
+ it 'runs the handler' do
28
+ subject.add(&block)
29
+ expect { subject.run('attrs') }
30
+ .to raise_error(sample_exception)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config::Middleware do
4
+ let(:block) { proc { raise BlockException, 'bla bla' } }
5
+ let(:options) { { option: :option } }
6
+
7
+ before do
8
+ stub_const 'BlockException', Class.new(Exception)
9
+ stub_const 'PerformException', Class.new(Exception)
10
+ stub_const 'MiddlewareSample', Class.new
11
+
12
+ MiddlewareSample.class_eval do
13
+ def self.perform(*)
14
+ raise PerformException, 'bla bla'
15
+ end
16
+ end
17
+ end
18
+
19
+ context 'when wrong params given' do
20
+ it 'fails when there is no params given' do
21
+ expect { described_class.new }.to raise_error('You must provide block or existing klass')
22
+ end
23
+
24
+ it 'fails when there is no perform method' do
25
+ stub_const 'NoPerformMiddlewareSample', Class.new
26
+
27
+ expect do
28
+ described_class.new(NoPerformMiddlewareSample)
29
+ end.to raise_error('The [NoPerformMiddlewareSample] class should define perform class method')
30
+ end
31
+ end
32
+
33
+ context 'when valid params given' do
34
+ let(:subject) { described_class.new(MiddlewareSample, options, &block) }
35
+
36
+ it 'creates middleware instance with class' do
37
+ expect(subject.klass).to be(MiddlewareSample)
38
+ end
39
+
40
+ it 'creates middleware instance with handler' do
41
+ expect(subject.handler).to be(block)
42
+ end
43
+
44
+ it 'creates middleware instance with options' do
45
+ expect(subject.options).to be(options)
46
+ end
47
+ end
48
+
49
+ describe '#run' do
50
+ it 'runs klass perform when it is given' do
51
+ middleware = described_class.new(MiddlewareSample)
52
+
53
+ expect { middleware.run({}) }.to raise_error(PerformException)
54
+ end
55
+
56
+ it 'runs klass handler when it is given' do
57
+ middleware = described_class.new(&block)
58
+
59
+ expect { middleware.run({}) }.to raise_error(BlockException)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Config::RescueFrom do
4
+ describe '#add' do
5
+ let(:sample_exception) { stub_const 'SampleException', Class.new(Exception) }
6
+
7
+ context 'when wrong params given' do
8
+ it 'fails when no block given' do
9
+ expect { subject.add(sample_exception) }.to raise_error('Block not given')
10
+ end
11
+ end
12
+
13
+ context 'when valid params given' do
14
+ let(:block) { proc {} }
15
+
16
+ it 'adds the exception handler' do
17
+ subject.add(sample_exception, &block)
18
+
19
+ expect(subject.exceptions).to include(sample_exception)
20
+ expect(subject.handlers.values).to include(block)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#run' do
26
+ let(:sample_exception) { stub_const 'SampleException', Class.new(Exception) }
27
+ let(:block_exception) { stub_const 'BlockException', Class.new(Exception) }
28
+ let(:block) { proc { raise BlockException } }
29
+
30
+ context 'when wrong params given' do
31
+ it 'fails when handler not given' do
32
+ expect { subject.run('name', 'attrs', sample_exception.new) }
33
+ .to raise_error('No handler given')
34
+ end
35
+ end
36
+
37
+ context 'when valid params given' do
38
+ it 'runs the handler' do
39
+ subject.add(sample_exception, &block)
40
+ expect { subject.run('name', 'attrs', sample_exception.new) }
41
+ .to raise_error(block_exception)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EndpointFlux::Endpoint do
4
+ let(:klass) { stub_const 'Sample', Class.new }
5
+
6
+ before do
7
+ klass.include EndpointFlux::Endpoint
8
+ end
9
+
10
+ describe '#flow' do
11
+ let(:params) { { some: :val } }
12
+ let(:middleware_request) { EndpointFlux::Request.new(headers: {}, params: params) }
13
+ let(:middleware_response) { EndpointFlux::Response.new }
14
+
15
+ before do
16
+ stub_const('EndpointFlux::Middlewares::Validator::Sample', Class.new)
17
+ EndpointFlux::Middlewares::Validator::Sample.class_eval do
18
+ def self.perform(request, response, _)
19
+ request.params = {}
20
+ [request, response]
21
+ end
22
+ end
23
+
24
+ stub_const('EndpointFlux::Middlewares::Decorator::Sample', Class.new)
25
+ EndpointFlux::Middlewares::Decorator::Sample.class_eval do
26
+ def self.perform(request, _response, _)
27
+ [request, EndpointFlux::Response.new(headers: {}, body: {})]
28
+ end
29
+ end
30
+
31
+ klass.flow %i[validator decorator]
32
+
33
+ EndpointFlux.config.default_middlewares :validator, :sample
34
+ EndpointFlux.config.default_middlewares :decorator, 'sample'
35
+ end
36
+
37
+ it 'uses default middleware if not defined' do
38
+ request, response = klass.perform(middleware_request)
39
+ expect(request.params).to eq({})
40
+ expect(response.body).to eq({})
41
+ end
42
+ end
43
+ end