diff --git a/README.markdown b/README.markdown index 091837682..6bfda2493 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ Grape is a REST-like API micro-framework for Ruby. It is built to complement exi Grape is available as a gem, to install it just install the gem: gem install grape - + ## Basic Usage 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 end end end - + This would create a Rack application that could be used like so (in a Rackup config.ru file): run Twitter::API - + And would respond to the following routes: GET /1/statuses/public_timeline(.json) GET /1/statuses/home_timeline(.json) GET /1/statuses/show/:id(.json) POST /1/statuses/update(.json) - + Serialization takes place automatically. For more detailed usage information, please visit the [Grape Wiki](http://github.com/intridea/grape/wiki). - + ## Raising Errors You can raise errors explicitly. @@ -117,6 +117,15 @@ You can also rescue specific exceptions with a code block and handle the Rack re end end + class Twitter::API < Grape::API + rescue_from ArgumentError do |e| + Rack::Response.new([ "ArgumentError: #{e.message}" ], 500) + end + rescue_from NotImplementedError do |e| + Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500) + end + end + ## Writing Tests 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`. diff --git a/lib/grape/api.rb b/lib/grape/api.rb index 3b12a9046..848af05b9 100644 --- a/lib/grape/api.rb +++ b/lib/grape/api.rb @@ -52,6 +52,22 @@ def set(key, value) @settings.last[key.to_sym] = value end + # Add to a configuration value for this + # namespace. + # + # @param key [Symbol] The key of the configuration variable. + # @param value [Object] The value to which to set the configuration variable. + def add(key, value) + current = @settings.last[key.to_sym] + if current.is_a?(Array) + current.concat(value) + elsif current.is_a?(Hash) + current.merge!(value) + else + @settings.last[key.to_sym] = value + end + end + # Define a root URL prefix for your entire # API. def prefix(prefix = nil) @@ -122,12 +138,12 @@ def default_error_status(new_status = nil) def rescue_from(*args, &block) if block_given? args.each do |arg| - set(:rescue_handlers, { arg => block }) + add(:rescue_handlers, { arg => block }) end end - set(:rescue_options, args.pop) if args.last.is_a?(Hash) + add(:rescue_options, args.pop) if args.last.is_a?(Hash) set(:rescue_all, true) and return if args.include?(:all) - set(:rescued_errors, args) + add(:rescued_errors, args) end # Add helper methods that will be accessible from any diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 619f78d15..1658d1eea 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -743,6 +743,28 @@ class ConnectionError < RuntimeError; end last_response.status.should eql 500 last_response.body.should == 'rescued from ConnectionError' end + it 'should rescue multiple specific errors' do + class ConnectionError < RuntimeError; end + class DatabaseError < RuntimeError; end + subject.rescue_from ConnectionError do |e| + rack_response("rescued from #{e.class.name}", 500) + end + subject.rescue_from DatabaseError do |e| + rack_response("rescued from #{e.class.name}", 500) + end + subject.get '/connection' do + raise ConnectionError + end + subject.get '/database' do + raise DatabaseError + end + get '/connection' + last_response.status.should eql 500 + last_response.body.should == 'rescued from ConnectionError' + get '/database' + last_response.status.should eql 500 + last_response.body.should == 'rescued from DatabaseError' + end it 'should not rescue a different error' do class CommunicationError < RuntimeError; end subject.rescue_from RuntimeError do |e|