Skip to content

Commit 4ffafb4

Browse files
author
Michael Bleigh
committed
Merge pull request ruby-grape#66 from dblock/rescue-from
fixed rescue_from, broken when trying to rescue multiple specific exceptions
2 parents 5f96caf + 43df0cc commit 4ffafb4

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

README.markdown

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Grape is a REST-like API micro-framework for Ruby. It is built to complement exi
88
Grape is available as a gem, to install it just install the gem:
99

1010
gem install grape
11-
11+
1212
## Basic Usage
1313

1414
Grape APIs are Rack applications that are created by subclassing `Grape::API`. Below is a simple example showing some of the more common features of Grape in the context of recreating parts of the Twitter API.
@@ -57,20 +57,20 @@ Grape APIs are Rack applications that are created by subclassing `Grape::API`. B
5757
end
5858
end
5959
end
60-
60+
6161
This would create a Rack application that could be used like so (in a Rackup config.ru file):
6262

6363
run Twitter::API
64-
64+
6565
And would respond to the following routes:
6666

6767
GET /1/statuses/public_timeline(.json)
6868
GET /1/statuses/home_timeline(.json)
6969
GET /1/statuses/show/:id(.json)
7070
POST /1/statuses/update(.json)
71-
71+
7272
Serialization takes place automatically. For more detailed usage information, please visit the [Grape Wiki](http://github.com/intridea/grape/wiki).
73-
73+
7474
## Raising Errors
7575

7676
You can raise errors explicitly.
@@ -117,6 +117,15 @@ You can also rescue specific exceptions with a code block and handle the Rack re
117117
end
118118
end
119119

120+
class Twitter::API < Grape::API
121+
rescue_from ArgumentError do |e|
122+
Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
123+
end
124+
rescue_from NotImplementedError do |e|
125+
Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
126+
end
127+
end
128+
120129
## Writing Tests
121130

122131
You can test a Grape API with RSpec. Tests make HTTP requests, therefore they must go into the `spec/request` group. You may want your API code to go into `app/api` - you can match that layout under `spec` by adding the following in `spec/spec_helper.rb`.

lib/grape/api.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ def set(key, value)
5252
@settings.last[key.to_sym] = value
5353
end
5454

55+
# Add to a configuration value for this
56+
# namespace.
57+
#
58+
# @param key [Symbol] The key of the configuration variable.
59+
# @param value [Object] The value to which to set the configuration variable.
60+
def add(key, value)
61+
current = @settings.last[key.to_sym]
62+
if current.is_a?(Array)
63+
current.concat(value)
64+
elsif current.is_a?(Hash)
65+
current.merge!(value)
66+
else
67+
@settings.last[key.to_sym] = value
68+
end
69+
end
70+
5571
# Define a root URL prefix for your entire
5672
# API.
5773
def prefix(prefix = nil)
@@ -122,12 +138,12 @@ def default_error_status(new_status = nil)
122138
def rescue_from(*args, &block)
123139
if block_given?
124140
args.each do |arg|
125-
set(:rescue_handlers, { arg => block })
141+
add(:rescue_handlers, { arg => block })
126142
end
127143
end
128-
set(:rescue_options, args.pop) if args.last.is_a?(Hash)
144+
add(:rescue_options, args.pop) if args.last.is_a?(Hash)
129145
set(:rescue_all, true) and return if args.include?(:all)
130-
set(:rescued_errors, args)
146+
add(:rescued_errors, args)
131147
end
132148

133149
# Add helper methods that will be accessible from any

spec/grape/api_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,28 @@ class ConnectionError < RuntimeError; end
743743
last_response.status.should eql 500
744744
last_response.body.should == 'rescued from ConnectionError'
745745
end
746+
it 'should rescue multiple specific errors' do
747+
class ConnectionError < RuntimeError; end
748+
class DatabaseError < RuntimeError; end
749+
subject.rescue_from ConnectionError do |e|
750+
rack_response("rescued from #{e.class.name}", 500)
751+
end
752+
subject.rescue_from DatabaseError do |e|
753+
rack_response("rescued from #{e.class.name}", 500)
754+
end
755+
subject.get '/connection' do
756+
raise ConnectionError
757+
end
758+
subject.get '/database' do
759+
raise DatabaseError
760+
end
761+
get '/connection'
762+
last_response.status.should eql 500
763+
last_response.body.should == 'rescued from ConnectionError'
764+
get '/database'
765+
last_response.status.should eql 500
766+
last_response.body.should == 'rescued from DatabaseError'
767+
end
746768
it 'should not rescue a different error' do
747769
class CommunicationError < RuntimeError; end
748770
subject.rescue_from RuntimeError do |e|

0 commit comments

Comments
 (0)