api_valve 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c5ecd7703186bfbcd52c8b50d3a643a5c2af56043e92f00e56b8b1863c38fb7
4
- data.tar.gz: 95263987cdf177ce4703955572e28f4540a3c32f47fb7b519fd0233b79506160
3
+ metadata.gz: 3082a9e6ce31e0044de55d718dc95764b9a7bd966b26f2eac1a219b687b1dc90
4
+ data.tar.gz: df5e9392bafe22aa847b603b392ea6d386b4736e9af1fcb991a3a5c3989253e5
5
5
  SHA512:
6
- metadata.gz: a43f1ff0ea8e795a1676bd918b9d849d2404a14793f6ccf93adac8b70c3aa672729822a1e6d516f38201ae3505023e3d0adc46c0a4257497c6c5aaa577bc97fe
7
- data.tar.gz: 2db871a83ee2dc02b2639ba0e6c19a795f765e24421ef0aacc8ec2f4adbefd2b682d7746cb8c99cd0e976d5afe89af70abb87cb2680dbce92c9f45d6458ed467
6
+ metadata.gz: 92fcfc205c9da56bc4a565ede28e87cbf4dd0eb5a5f9a0a705e20d3d74699b32015222930bd028dbe592818a03e6988b34d80a4798601a127dd0a2373883a7ed
7
+ data.tar.gz: 35402f30d4d8ad53792c77d5cc86893e489bdcf5717dc28b7b6dcee1e09a247aad58d4a939e88d13fbdcaaa82bf7845b81808bbfde9932d71d09eb7c41df142c
@@ -0,0 +1,22 @@
1
+ module ApiValve
2
+ class Cascade
3
+ def initialize(*proxies)
4
+ @proxies = proxies
5
+ end
6
+
7
+ def call(env)
8
+ @proxies.each do |proxy|
9
+ return proxy.call env
10
+ rescue Error::NotRouted
11
+ next
12
+ end
13
+ render_error Error::NotFound.new
14
+ end
15
+
16
+ protected
17
+
18
+ def render_error(error)
19
+ self.class.const_get(ApiValve.error_responder).new(error).call
20
+ end
21
+ end
22
+ end
@@ -1,13 +1,27 @@
1
1
  module ApiValve
2
- module Error
3
- class Base < RuntimeError
4
- class_attribute :http_status
5
- self.http_status = :server_error
2
+ class Error < RuntimeError
3
+ class_attribute :http_status, :code, :title, :default_message
4
+ self.http_status = :server_error
5
+
6
+ Client = Class.new(self)
7
+ Server = Class.new(self)
8
+
9
+ def initialize(*args)
10
+ @options = args.extract_options!
11
+ super(args.first || default_message)
6
12
  end
7
13
 
8
14
  Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |sym, code|
9
- next unless code >= 400
10
- const_set sym.to_s.camelize, Class.new(Base) { self.http_status = sym }
15
+ case code
16
+ when 400..499
17
+ const_set sym.to_s.camelize, Class.new(Client) { self.http_status = sym }
18
+ when 500..599
19
+ const_set sym.to_s.camelize, Class.new(Server) { self.http_status = sym }
20
+ end
21
+ end
22
+
23
+ NotRouted = Class.new(self) do
24
+ self.http_status = 404
11
25
  end
12
26
  end
13
27
  end
@@ -7,7 +7,7 @@ module ApiValve
7
7
  def call
8
8
  [
9
9
  status,
10
- {'Content-Type' => 'application/json'},
10
+ {'Content-Type' => 'application/vnd.api+json'},
11
11
  [MultiJson.dump({errors: [json_error]}, mode: :compat)]
12
12
  ]
13
13
  end
@@ -22,19 +22,26 @@ module ApiValve
22
22
 
23
23
  def json_error
24
24
  {
25
- status: status,
26
- code: json_code,
25
+ status: status.to_s,
26
+ code: json_code,
27
+ title: json_title,
27
28
  detail: json_detail,
28
- meta: json_meta
29
+ meta: json_meta
29
30
  }.compact
30
31
  end
31
32
 
32
33
  def json_code
33
- @error.try(:code) || Rack::Utils::HTTP_STATUS_CODES[status]
34
+ @error.try(:code) || @error.class.name.demodulize.underscore
35
+ end
36
+
37
+ def json_title
38
+ @error.try(:title) || Rack::Utils::HTTP_STATUS_CODES[status]
34
39
  end
35
40
 
36
41
  def json_detail
37
- @error.message != @error.class.to_s ? @error.message : nil
42
+ return if json_title == @error.message
43
+ return if @error.message == @error.class.name
44
+ @error.message
38
45
  end
39
46
 
40
47
  def json_meta
@@ -4,6 +4,8 @@ module ApiValve
4
4
  # attributes that can be read or written.
5
5
 
6
6
  class Forwarder::PermissionHandler
7
+ InsufficientPermissions = Class.new(Error::Forbidden)
8
+
7
9
  module RequestIntegration
8
10
  private
9
11
 
@@ -33,7 +35,8 @@ module ApiValve
33
35
 
34
36
  # Tells the request class if the request is allowed
35
37
  # Simple implementation is always true. Override in your implementation.
36
- def request_allowed?
38
+ # Should raise InsufficientPermissions when not allowed
39
+ def check_permissions!
37
40
  true
38
41
  end
39
42
  end
@@ -26,8 +26,8 @@ module ApiValve
26
26
  end
27
27
 
28
28
  # Is the request allowed? If it returns false, Forwarder will raise Error::Forbidden
29
- def allowed?
30
- permission_handler.request_allowed?
29
+ def check_permissions!
30
+ permission_handler.check_permissions!
31
31
  end
32
32
 
33
33
  # HTTP method to use when forwarding. Must return sym.
@@ -24,7 +24,7 @@ module ApiValve
24
24
  # request and response.
25
25
  def call(original_request, local_options = {})
26
26
  request = request_klass.new(original_request, request_options.deep_merge(local_options))
27
- raise Error::Forbidden unless request.allowed?
27
+ request.check_permissions!
28
28
  response_klass.new(
29
29
  original_request,
30
30
  run_request(request),
@@ -9,7 +9,7 @@ module ApiValve
9
9
  @app.call(env)
10
10
  rescue Exception => e # rubocop:disable Lint/RescueException
11
11
  log_error e
12
- ErrorResponder.new(e).call
12
+ self.class.const_get(ApiValve.error_responder).new(e).call
13
13
  end
14
14
 
15
15
  private
@@ -91,21 +91,10 @@ module ApiValve::Middleware
91
91
  end
92
92
  end
93
93
 
94
- config_accessor :log_request_headers do
95
- false
96
- end
97
-
98
- config_accessor :log_request_body do
99
- false
100
- end
101
-
102
- config_accessor :log_response_headers do
103
- false
104
- end
105
-
106
- config_accessor :log_response_body do
107
- false
108
- end
94
+ config_accessor(:log_request_headers) { false }
95
+ config_accessor(:log_request_body) { false }
96
+ config_accessor(:log_response_headers) { false }
97
+ config_accessor(:log_response_body) { false }
109
98
 
110
99
  def initialize(app)
111
100
  @app = app
@@ -62,8 +62,8 @@ module ApiValve
62
62
  def call(env)
63
63
  @request = Rack::Request.new(env)
64
64
  run_callbacks(:call) { @router.call(@request) }
65
- rescue ApiValve::Error::Base => e
66
- ErrorResponder.new(e).call
65
+ rescue ApiValve::Error::Client, ApiValve::Error::Server => e
66
+ render_error e
67
67
  end
68
68
 
69
69
  delegate :add_route, to: :router
@@ -78,7 +78,7 @@ module ApiValve
78
78
  forward method, path_regexp, request_override
79
79
  end
80
80
  end
81
- forward_all
81
+ forward_all unless config['routes']
82
82
  end
83
83
 
84
84
  def forward(methods, path_regexp = nil, request_override = {})
@@ -100,5 +100,11 @@ module ApiValve
100
100
  router.public_send(method, path_regexp, ->(*_args) { raise ApiValve.const_get(with) })
101
101
  end
102
102
  end
103
+
104
+ protected
105
+
106
+ def render_error(error)
107
+ self.class.const_get(ApiValve.error_responder).new(error).call
108
+ end
103
109
  end
104
110
  end
@@ -68,7 +68,7 @@ module ApiValve
68
68
  return route.call request, match_data
69
69
  end
70
70
  end
71
- raise Error::NotFound, 'Endpoint not found'
71
+ raise Error::NotRouted, 'Endpoint not found'
72
72
  end
73
73
  end
74
74
  end
data/lib/api_valve.rb CHANGED
@@ -13,6 +13,7 @@ require 'logger'
13
13
 
14
14
  module ApiValve
15
15
  autoload :Benchmarking, 'api_valve/benchmarking'
16
+ autoload :Cascade, 'api_valve/cascade'
16
17
  autoload :Error, 'api_valve/error'
17
18
  autoload :ErrorResponder, 'api_valve/error_responder'
18
19
  autoload :Forwarder, 'api_valve/forwarder'
@@ -31,6 +32,10 @@ module ApiValve
31
32
  Logger.new(STDOUT)
32
33
  end
33
34
 
35
+ config_accessor :error_responder do
36
+ 'ApiValve::ErrorResponder'
37
+ end
38
+
34
39
  config_accessor :expose_backtraces do
35
40
  false
36
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_valve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mkon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-16 00:00:00.000000000 Z
11
+ date: 2018-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '2'
75
+ - !ruby/object:Gem::Dependency
76
+ name: json_spec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.1'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.1'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: rack-test
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +120,14 @@ dependencies:
106
120
  requirements:
107
121
  - - '='
108
122
  - !ruby/object:Gem::Version
109
- version: 0.56.0
123
+ version: 0.58.2
110
124
  type: :development
111
125
  prerelease: false
112
126
  version_requirements: !ruby/object:Gem::Requirement
113
127
  requirements:
114
128
  - - '='
115
129
  - !ruby/object:Gem::Version
116
- version: 0.56.0
130
+ version: 0.58.2
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: rubocop-rspec
119
133
  requirement: !ruby/object:Gem::Requirement
@@ -180,6 +194,7 @@ files:
180
194
  - README.md
181
195
  - lib/api_valve.rb
182
196
  - lib/api_valve/benchmarking.rb
197
+ - lib/api_valve/cascade.rb
183
198
  - lib/api_valve/error.rb
184
199
  - lib/api_valve/error_responder.rb
185
200
  - lib/api_valve/forwarder.rb
@@ -211,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
226
  version: '0'
212
227
  requirements: []
213
228
  rubyforge_project:
214
- rubygems_version: 2.7.6
229
+ rubygems_version: 2.7.7
215
230
  signing_key:
216
231
  specification_version: 4
217
232
  summary: Lightweight ruby/rack API reverse proxy or gateway