Skip to content

Commit 883295c

Browse files
author
Michael Bleigh
committed
Merging in from master.
2 parents 925087b + 4ffafb4 commit 883295c

File tree

5 files changed

+77
-4
lines changed

5 files changed

+77
-4
lines changed

README.markdown

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ class Twitter::API < Grape::API
168168
end
169169
```
170170

171+
class Twitter::API < Grape::API
172+
rescue_from ArgumentError do |e|
173+
Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
174+
end
175+
rescue_from NotImplementedError do |e|
176+
Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
177+
end
178+
end
179+
171180
## Writing Tests
172181

173182
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

lib/grape/middleware/base.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'multi_json'
2+
require 'multi_xml'
23

34
module Grape
45
module Middleware
@@ -54,9 +55,11 @@ module Formats
5455
FORMATTERS = {
5556
:json => :encode_json,
5657
:txt => :encode_txt,
58+
:xml => :encode_xml
5759
}
5860
PARSERS = {
59-
:json => :decode_json
61+
:json => :decode_json,
62+
:xml => :decode_xml
6063
}
6164

6265
def formatters
@@ -120,6 +123,14 @@ def encode_json(object)
120123
def encode_txt(object)
121124
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
122125
end
126+
127+
def decode_xml(object)
128+
MultiXml.parse(object)
129+
end
130+
131+
def encode_xml(object)
132+
object.respond_to?(:to_xml) ? object.to_xml : object.to_s
133+
end
123134
end
124135

125136
end

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|

spec/grape/middleware/formatter_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ def serializable_hash
3535

3636
subject.call({'PATH_INFO' => '/somewhere'}).last.each{|b| b.should == '{"abc":"def"}'}
3737
end
38+
39+
it 'should call #to_xml if the content type is xml' do
40+
@body = "string"
41+
@body.instance_eval do
42+
def to_xml
43+
"<bar/>"
44+
end
45+
end
46+
47+
subject.call({'PATH_INFO' => '/somewhere.xml'}).last.each{|b| b.should == '<bar/>'}
48+
end
3849
end
3950

4051
context 'detection' do
@@ -130,6 +141,10 @@ def serializable_hash
130141
subject.env['rack.request.form_hash']['is_boolean'].should be_true
131142
subject.env['rack.request.form_hash']['string'].should == 'thing'
132143
end
144+
it 'should parse the body from an xml POST/PUT and put the contents into rack.request.from_hash' do
145+
subject.call({'PATH_INFO' => '/info.xml', 'Accept' => 'application/xml', 'rack.input' => StringIO.new('<thing><name>Test</name></thing>')})
146+
subject.env['rack.request.form_hash']['thing']['name'].should == 'Test'
147+
end
133148
it 'should be able to fail gracefully if the body is regular POST content' do
134149
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json', 'rack.input' => StringIO.new('name=Other+Test+Thing')})
135150
subject.env['rack.request.form_hash'].should be_nil

0 commit comments

Comments
 (0)