rack-api 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/examples/helpers.rb +25 -0
- data/examples/rescue_from.rb +33 -0
- data/lib/rack/api/app.rb +22 -0
- data/lib/rack/api/runner.rb +21 -5
- data/lib/rack/api/version.rb +2 -2
- data/spec/rack-api/method_delegation_spec.rb +1 -0
- data/spec/rack-api/rescue_from_spec.rb +103 -0
- data/spec/rack-api/runner_spec.rb +1 -1
- metadata +6 -2
data/Gemfile.lock
CHANGED
data/examples/helpers.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.push(File.dirname(__FILE__) + "/../lib")
|
2
|
+
|
3
|
+
# Just run `ruby examples/basic_auth.rb` and then use something like
|
4
|
+
# `curl http://localhost:2345/api/v1/` or
|
5
|
+
# `curl http://localhost:2345/api/v1/This%20is%20so%20cool`.
|
6
|
+
|
7
|
+
require "rack/api"
|
8
|
+
|
9
|
+
Rack::API.app do
|
10
|
+
prefix "api"
|
11
|
+
|
12
|
+
helper do
|
13
|
+
def default_message
|
14
|
+
"Hello from Rack API"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
version :v1 do
|
19
|
+
get "/(:message)" do
|
20
|
+
{:message => params.fetch(:message, default_message)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Rack::Handler::Thin.run Rack::API, :Port => 2345
|
@@ -0,0 +1,33 @@
|
|
1
|
+
$:.push(File.dirname(__FILE__) + "/../lib")
|
2
|
+
|
3
|
+
# Just run `ruby examples/simple.rb` and then use something like
|
4
|
+
# `curl http://localhost:2345/api/v1/`.
|
5
|
+
|
6
|
+
require "rack/api"
|
7
|
+
require "logger"
|
8
|
+
|
9
|
+
$logger = Logger.new(STDOUT)
|
10
|
+
|
11
|
+
# Simulate ActiveRecord's exception.
|
12
|
+
module ActiveRecord
|
13
|
+
class RecordNotFound < StandardError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Rack::API.app do
|
18
|
+
prefix "api"
|
19
|
+
|
20
|
+
rescue_from ActiveRecord::RecordNotFound, :status => 404
|
21
|
+
rescue_from Exception do |error|
|
22
|
+
$logger.error error.message
|
23
|
+
[500, {"Content-Type" => "text/plain"}, []]
|
24
|
+
end
|
25
|
+
|
26
|
+
version :v1 do
|
27
|
+
get "/" do
|
28
|
+
raise "Oh no! Something is really wrong!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Rack::Handler::Thin.run Rack::API, :Port => 2345
|
data/lib/rack/api/app.rb
CHANGED
@@ -48,6 +48,11 @@ module Rack
|
|
48
48
|
#
|
49
49
|
attr_accessor :url_options
|
50
50
|
|
51
|
+
# Hold handlers, that will wrap exceptions
|
52
|
+
# into a normalized response.
|
53
|
+
#
|
54
|
+
attr_accessor :rescuers
|
55
|
+
|
51
56
|
def initialize(options)
|
52
57
|
options.each do |name, value|
|
53
58
|
instance_variable_set("@#{name}", value)
|
@@ -158,6 +163,8 @@ module Rack
|
|
158
163
|
end
|
159
164
|
|
160
165
|
response.respond_to?(:to_rack) ? response.to_rack : response
|
166
|
+
rescue Exception => exception
|
167
|
+
handle_exception exception
|
161
168
|
end
|
162
169
|
|
163
170
|
# Return response content type based on extension.
|
@@ -229,6 +236,21 @@ module Rack
|
|
229
236
|
throw :error, Response.new(:status => 406, :message => "Unknown format")
|
230
237
|
end
|
231
238
|
end
|
239
|
+
|
240
|
+
def handle_exception(error) # :nodoc:
|
241
|
+
rescuer = rescuers.find do |r|
|
242
|
+
error_class = eval("::#{r[:class_name]}") rescue nil
|
243
|
+
error_class && error.kind_of?(error_class)
|
244
|
+
end
|
245
|
+
|
246
|
+
raise error unless rescuer
|
247
|
+
|
248
|
+
if rescuer[:block]
|
249
|
+
instance_exec(error, &rescuer[:block])
|
250
|
+
else
|
251
|
+
[rescuer[:options].fetch(:status, 500), {"Content-Type" => "text/plain"}, []]
|
252
|
+
end
|
253
|
+
end
|
232
254
|
end
|
233
255
|
end
|
234
256
|
end
|
data/lib/rack/api/runner.rb
CHANGED
@@ -4,7 +4,7 @@ module Rack
|
|
4
4
|
HTTP_METHODS = %w[get post put delete head]
|
5
5
|
|
6
6
|
DELEGATE_METHODS = %w[
|
7
|
-
version use prefix basic_auth
|
7
|
+
version use prefix basic_auth rescue_from
|
8
8
|
helper respond_to default_url_options
|
9
9
|
]
|
10
10
|
|
@@ -14,11 +14,13 @@ module Rack
|
|
14
14
|
@settings = {
|
15
15
|
:middlewares => [],
|
16
16
|
:helpers => [],
|
17
|
+
:rescuers => [],
|
17
18
|
:global => {
|
18
|
-
:prefix
|
19
|
-
:formats
|
19
|
+
:prefix => "/",
|
20
|
+
:formats => %w[json jsonp],
|
20
21
|
:middlewares => [],
|
21
|
-
:helpers
|
22
|
+
:helpers => [],
|
23
|
+
:rescuers => []
|
22
24
|
}
|
23
25
|
}
|
24
26
|
end
|
@@ -234,6 +236,19 @@ module Rack
|
|
234
236
|
RUBY
|
235
237
|
end
|
236
238
|
|
239
|
+
# Rescue from the specified exception.
|
240
|
+
#
|
241
|
+
# rescue_from ActiveRecord::RecordNotFound, :status => 404
|
242
|
+
# rescue_from Exception, :status => 500
|
243
|
+
# rescue_from Exception do
|
244
|
+
# $logger.error error.inspect
|
245
|
+
# [500, {"Content-Type" => "text/plain"}, []]
|
246
|
+
# end
|
247
|
+
#
|
248
|
+
def rescue_from(exception, options = {}, &block)
|
249
|
+
set :rescuers, {:class_name => exception.name, :options => options, :block => block}, :append
|
250
|
+
end
|
251
|
+
|
237
252
|
private
|
238
253
|
def mount_path(path) # :nodoc:
|
239
254
|
Rack::Mount::Utils.normalize_path([option(:prefix), settings[:version], path].join("/"))
|
@@ -249,7 +264,8 @@ module Rack
|
|
249
264
|
:default_format => default_format,
|
250
265
|
:version => option(:version),
|
251
266
|
:prefix => option(:prefix),
|
252
|
-
:url_options => option(:url_options)
|
267
|
+
:url_options => option(:url_options),
|
268
|
+
:rescuers => option(:rescuers, :merge).reverse
|
253
269
|
})
|
254
270
|
|
255
271
|
builder = Rack::Builder.new
|
data/lib/rack/api/version.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rack::API, "Rescue from exceptions" do
|
4
|
+
class NotFound < StandardError; end
|
5
|
+
|
6
|
+
it "rescues from NotFound exception" do
|
7
|
+
Rack::API.app do
|
8
|
+
rescue_from NotFound, :status => 404
|
9
|
+
|
10
|
+
version :v1 do
|
11
|
+
get("/404") { raise NotFound }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
get "/v1/404"
|
16
|
+
last_response.headers["Content-Type"].should == "text/plain"
|
17
|
+
last_response.body.should == ""
|
18
|
+
last_response.status.should == 404
|
19
|
+
end
|
20
|
+
|
21
|
+
it "rescues from all exceptions" do
|
22
|
+
Rack::API.app do
|
23
|
+
rescue_from Exception
|
24
|
+
|
25
|
+
version :v1 do
|
26
|
+
get("/500") { raise "Oops!" }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
get "/v1/500"
|
31
|
+
last_response.headers["Content-Type"].should == "text/plain"
|
32
|
+
last_response.body.should == ""
|
33
|
+
last_response.status.should == 500
|
34
|
+
end
|
35
|
+
|
36
|
+
it "rescues from exception by using a block" do
|
37
|
+
Rack::API.app do
|
38
|
+
rescue_from Exception do
|
39
|
+
[501, {"Content-Type" => "application/json"}, [{:error => true}.to_json]]
|
40
|
+
end
|
41
|
+
|
42
|
+
version :v1 do
|
43
|
+
get("/501") { raise "Oops!" }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
get "/v1/501"
|
48
|
+
last_response.headers["Content-Type"].should == "application/json"
|
49
|
+
last_response.body.should == {:error => true}.to_json
|
50
|
+
last_response.status.should == 501
|
51
|
+
end
|
52
|
+
|
53
|
+
it "rescues from exception by using inner handler" do
|
54
|
+
Rack::API.app do
|
55
|
+
rescue_from Exception
|
56
|
+
|
57
|
+
version :v1 do
|
58
|
+
rescue_from Exception do
|
59
|
+
[500, {"Content-Type" => "text/plain"}, ["inner handler"]]
|
60
|
+
end
|
61
|
+
|
62
|
+
get("/500") { raise "Oops!" }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
get "/v1/500"
|
67
|
+
last_response.body.should == "inner handler"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "rescues from exception in app's context" do
|
71
|
+
Rack::API.app do
|
72
|
+
rescue_from Exception
|
73
|
+
|
74
|
+
version :v1 do
|
75
|
+
rescue_from Exception do
|
76
|
+
[500, {"Content-Type" => "text/plain"}, [self.class.name]]
|
77
|
+
end
|
78
|
+
|
79
|
+
get("/500") { raise "Oops!" }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
get "/v1/500"
|
84
|
+
last_response.body.should == "Rack::API::App"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "yields the exception object" do
|
88
|
+
Rack::API.app do
|
89
|
+
rescue_from Exception
|
90
|
+
|
91
|
+
version :v1 do
|
92
|
+
rescue_from Exception do |error|
|
93
|
+
[500, {"Content-Type" => "text/plain"}, [error.message]]
|
94
|
+
end
|
95
|
+
|
96
|
+
get("/500") { raise "Oops!" }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
get "/v1/500"
|
101
|
+
last_response.body.should == "Oops!"
|
102
|
+
end
|
103
|
+
end
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe Rack::API::Runner do
|
4
4
|
specify "sanity check for delegate methods" do
|
5
5
|
# remember to update spec/method_delegation_spec.rb
|
6
|
-
Rack::API::Runner::DELEGATE_METHODS.size.should ==
|
6
|
+
Rack::API::Runner::DELEGATE_METHODS.size.should == 8
|
7
7
|
end
|
8
8
|
|
9
9
|
it "responds to http methods" do
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: rack-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.3.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Nando Vieira
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-09 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -110,9 +110,11 @@ files:
|
|
110
110
|
- examples/custom_format.rb
|
111
111
|
- examples/custom_headers.rb
|
112
112
|
- examples/formats.rb
|
113
|
+
- examples/helpers.rb
|
113
114
|
- examples/middleware.rb
|
114
115
|
- examples/multiple_versions.rb
|
115
116
|
- examples/params.rb
|
117
|
+
- examples/rescue_from.rb
|
116
118
|
- examples/simple.rb
|
117
119
|
- lib/rack/api.rb
|
118
120
|
- lib/rack/api/app.rb
|
@@ -138,6 +140,7 @@ files:
|
|
138
140
|
- spec/rack-api/middlewares_spec.rb
|
139
141
|
- spec/rack-api/params_spec.rb
|
140
142
|
- spec/rack-api/paths_spec.rb
|
143
|
+
- spec/rack-api/rescue_from_spec.rb
|
141
144
|
- spec/rack-api/runner_spec.rb
|
142
145
|
- spec/rack-api/settings_spec.rb
|
143
146
|
- spec/rack-api/short_circuit_spec.rb
|
@@ -188,6 +191,7 @@ test_files:
|
|
188
191
|
- spec/rack-api/middlewares_spec.rb
|
189
192
|
- spec/rack-api/params_spec.rb
|
190
193
|
- spec/rack-api/paths_spec.rb
|
194
|
+
- spec/rack-api/rescue_from_spec.rb
|
191
195
|
- spec/rack-api/runner_spec.rb
|
192
196
|
- spec/rack-api/settings_spec.rb
|
193
197
|
- spec/rack-api/short_circuit_spec.rb
|