Class: ApiValve::Proxy

Inherits:
Object
  • Object
show all
Includes:
ActiveSupport::Callbacks
Defined in:
lib/api_valve/proxy.rb

Constant Summary collapse

FORWARDER_OPTIONS =
%w(endpoint request response permission_handler).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(forwarder) ⇒ Proxy

Returns a new instance of Proxy.



69
70
71
72
73
# File 'lib/api_valve/proxy.rb', line 69

def initialize(forwarder)
  @forwarder = forwarder
  @router = Router.new
  @middlewares = []
end

Instance Attribute Details

#forwarderObject (readonly)

Returns the value of attribute forwarder.



67
68
69
# File 'lib/api_valve/proxy.rb', line 67

def forwarder
  @forwarder
end

#requestObject (readonly)

Returns the value of attribute request.



67
68
69
# File 'lib/api_valve/proxy.rb', line 67

def request
  @request
end

#routerObject (readonly)

Returns the value of attribute router.



67
68
69
# File 'lib/api_valve/proxy.rb', line 67

def router
  @router
end

Class Method Details

.build(config) ⇒ Object

Creates a n instance from a config hash and takes optional block which is executed in scope of the proxy



15
16
17
18
19
20
# File 'lib/api_valve/proxy.rb', line 15

def build(config)
  block = Proc.new if block_given? # capture the yield
  from_hash(config).tap do |proxy|
    proxy.instance_eval(&block) if block
  end
end

.from_config(file_name = nil) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/api_valve/proxy.rb', line 22

def from_config(file_name = nil)
  file_name ||= name.underscore
  path = find_config(file_name)
  raise "Config not found for #{name.underscore}(.yml|.yml.erb) in #{ApiValve.config_paths.inspect}" unless path

  yaml = File.read(path)
  yaml = ERB.new(yaml, nil, '-').result if path.fnmatch? '*.erb'
  from_yaml yaml
end

.from_hash(config) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/api_valve/proxy.rb', line 36

def from_hash(config)
  config = config.with_indifferent_access
  forwarder = Forwarder.new(forwarder_config(config))
  new(forwarder).tap do |proxy|
    Array.wrap(config[:use]).each { |mw| proxy.use mw }
    proxy.build_routes_from_config config[:routes]
  end
end

.from_yaml(string) ⇒ Object



32
33
34
# File 'lib/api_valve/proxy.rb', line 32

def from_yaml(string)
  from_hash YAML.load(string) # rubocop:disable Security/YAMLLoad
end

Instance Method Details

#build_routes_from_config(routes_config) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/api_valve/proxy.rb', line 84

def build_routes_from_config(routes_config)
  return forward_all unless routes_config

  routes_config.each do |route_config|
    method, path_regexp, request_override = *route_config.values_at('method', 'path', 'request')
    method ||= 'any' # no method defined means all methods
    if route_config['raise']
      deny method, path_regexp, with: route_config['raise']
    else
      forward method, path_regexp, request_override
    end
  end
end

#call(env) ⇒ Object



75
76
77
78
79
80
# File 'lib/api_valve/proxy.rb', line 75

def call(env)
  stack = @middlewares.reverse.inject(@router) { |a, e| e.call a }
  stack.call(env)
rescue ApiValve::Error::Client, ApiValve::Error::Server => e
  render_error e
end

#deny(methods, path_regexp = nil, with: 'Error::Forbidden') ⇒ Object



112
113
114
115
116
# File 'lib/api_valve/proxy.rb', line 112

def deny(methods, path_regexp = nil, with: 'Error::Forbidden')
  Array.wrap(methods).each do |method|
    router.public_send(method, path_regexp, ->(*_args) { raise ApiValve.const_get(with) })
  end
end

#forward(methods, path_regexp = nil, request_override = {}) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/api_valve/proxy.rb', line 98

def forward(methods, path_regexp = nil, request_override = {})
  Array.wrap(methods).each do |method|
    router.public_send(method, path_regexp, proc { |request, match_data|
      forwarder.call request, {'match_data' => match_data}.merge(request_override || {})
    })
  end
end

#forward_allObject



106
107
108
109
110
# File 'lib/api_valve/proxy.rb', line 106

def forward_all
  router.any do |request, match_data|
    forwarder.call request, 'match_data' => match_data
  end
end

#use(middleware, *args, &block) ⇒ Object



118
119
120
# File 'lib/api_valve/proxy.rb', line 118

def use(middleware, *args, &block)
  @middlewares << proc { |app| middleware.new(app, *args, &block) }
end