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 +4 -4
- data/lib/api_valve/cascade.rb +22 -0
- data/lib/api_valve/error.rb +20 -6
- data/lib/api_valve/error_responder.rb +13 -6
- data/lib/api_valve/forwarder/permission_handler.rb +4 -1
- data/lib/api_valve/forwarder/request.rb +2 -2
- data/lib/api_valve/forwarder.rb +1 -1
- data/lib/api_valve/middleware/error_handling.rb +1 -1
- data/lib/api_valve/middleware/logging.rb +4 -15
- data/lib/api_valve/proxy.rb +9 -3
- data/lib/api_valve/router.rb +1 -1
- data/lib/api_valve.rb +5 -0
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3082a9e6ce31e0044de55d718dc95764b9a7bd966b26f2eac1a219b687b1dc90
|
4
|
+
data.tar.gz: df5e9392bafe22aa847b603b392ea6d386b4736e9af1fcb991a3a5c3989253e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/api_valve/error.rb
CHANGED
@@ -1,13 +1,27 @@
|
|
1
1
|
module ApiValve
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
-
|
10
|
-
|
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:
|
25
|
+
status: status.to_s,
|
26
|
+
code: json_code,
|
27
|
+
title: json_title,
|
27
28
|
detail: json_detail,
|
28
|
-
meta:
|
29
|
+
meta: json_meta
|
29
30
|
}.compact
|
30
31
|
end
|
31
32
|
|
32
33
|
def json_code
|
33
|
-
@error.try(:code) ||
|
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
|
-
|
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
|
-
|
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
|
30
|
-
permission_handler.
|
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.
|
data/lib/api_valve/forwarder.rb
CHANGED
@@ -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
|
-
|
27
|
+
request.check_permissions!
|
28
28
|
response_klass.new(
|
29
29
|
original_request,
|
30
30
|
run_request(request),
|
@@ -91,21 +91,10 @@ module ApiValve::Middleware
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
config_accessor
|
95
|
-
|
96
|
-
|
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
|
data/lib/api_valve/proxy.rb
CHANGED
@@ -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::
|
66
|
-
|
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
|
data/lib/api_valve/router.rb
CHANGED
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.
|
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-
|
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.
|
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.
|
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.
|
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
|