api_valve 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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