endpoint-flux 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/CONTRIBUTING.md +18 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +37 -0
- data/README.md +607 -0
- data/circle.yml +14 -0
- data/endpoint_flux.gemspec +18 -0
- data/lib/endpoint_flux.rb +20 -0
- data/lib/endpoint_flux/class_loader.rb +58 -0
- data/lib/endpoint_flux/config.rb +85 -0
- data/lib/endpoint_flux/config/interceptor.rb +23 -0
- data/lib/endpoint_flux/config/middleware.rb +38 -0
- data/lib/endpoint_flux/config/rescue_from.rb +28 -0
- data/lib/endpoint_flux/endpoint.rb +81 -0
- data/lib/endpoint_flux/exceptions.rb +10 -0
- data/lib/endpoint_flux/exceptions/base.rb +21 -0
- data/lib/endpoint_flux/exceptions/forbidden.rb +12 -0
- data/lib/endpoint_flux/exceptions/not_found.rb +12 -0
- data/lib/endpoint_flux/exceptions/service_unavailable.rb +12 -0
- data/lib/endpoint_flux/exceptions/unauthorized.rb +12 -0
- data/lib/endpoint_flux/exceptions/validation.rb +13 -0
- data/lib/endpoint_flux/middlewares.rb +8 -0
- data/lib/endpoint_flux/middlewares/authenticator/skip.rb +11 -0
- data/lib/endpoint_flux/middlewares/authorizator/skip.rb +11 -0
- data/lib/endpoint_flux/middlewares/decorator/add_status.rb +12 -0
- data/lib/endpoint_flux/middlewares/decorator/skip.rb +11 -0
- data/lib/endpoint_flux/middlewares/policy/skip.rb +11 -0
- data/lib/endpoint_flux/middlewares/validator/empty.rb +12 -0
- data/lib/endpoint_flux/rails/concerns/endpoint_controller.rb +43 -0
- data/lib/endpoint_flux/request.rb +17 -0
- data/lib/endpoint_flux/response.rb +30 -0
- data/lib/endpoint_flux/version.rb +3 -0
- data/spec/lib/class_loader_spec.rb +31 -0
- data/spec/lib/config/default_middlewares_spec.rb +21 -0
- data/spec/lib/config/endpoints_namespace_spec.rb +13 -0
- data/spec/lib/config/flow_spec.rb +8 -0
- data/spec/lib/config/interceptor_spec.rb +34 -0
- data/spec/lib/config/middleware_spec.rb +62 -0
- data/spec/lib/config/rescue_from_spec.rb +45 -0
- data/spec/lib/endpoint/flow_spec.rb +43 -0
- data/spec/lib/endpoint/middlewares_spec.rb +110 -0
- data/spec/lib/endpoint/perform_spec.rb +61 -0
- data/spec/lib/endpoint/rescue_from_spec.rb +61 -0
- data/spec/lib/endpoint_flux/rails/concerns/endpoint_controller_spec.rb +75 -0
- data/spec/lib/endpoint_flux/request_spec.rb +44 -0
- data/spec/lib/exceptions/forbidden_spec.rb +12 -0
- data/spec/lib/exceptions/not_found_spec.rb +12 -0
- data/spec/lib/exceptions/service_unavailable_spec.rb +12 -0
- data/spec/lib/exceptions/unauthorized_spec.rb +12 -0
- data/spec/lib/exceptions/validation_spec.rb +14 -0
- data/spec/lib/middlewares/authenticator/skip_spec.rb +5 -0
- data/spec/lib/middlewares/authorizator/skip_spec.rb +5 -0
- data/spec/lib/middlewares/decorator/add_status_spec.rb +17 -0
- data/spec/lib/middlewares/decorator/skip_spec.rb +5 -0
- data/spec/lib/middlewares/policy/skip_spec.rb +5 -0
- data/spec/lib/middlewares/shared_examples.rb +19 -0
- data/spec/lib/middlewares/validator/empty_spec.rb +15 -0
- data/spec/lib/response_spec.rb +131 -0
- data/spec/spec_helper.rb +52 -0
- metadata +157 -0
@@ -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,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,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,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
|