Skip to content

Commit

Permalink
Merge pull request #284 from dblock/master
Browse files Browse the repository at this point in the history
Added a DSL to declare 'error_formatter' in API settings.
  • Loading branch information
dblock committed Dec 1, 2012
2 parents 26ee18f + 479e931 commit 8710c60
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 10 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
* [#265](https://github.com/intridea/grape/issues/264): Fix: Moved `ValidationError` into `Grape::Exceptions` - [@thepumpkin1979](https://github.com/thepumpkin1979).
* [#269](https://github.com/intridea/grape/pull/269): Fix: `LocalJumpError` will not be raised when using explict return in API methods - [@simulacre](https://github.com/simulacre).
* [#86](https://github.com/intridea/grape/issues/275): Fix Path-based versioning not recognizing '/' route - [@walski](https://github.com/walski).
* [#277](https://github.com/intridea/grape/pull/277): Added a DSL to declare `formatter` in API settings - [@tim-vandecasteele](https://github.com/tim-vandecasteele).
* [#273](https://github.com/intridea/grape/pull/273): Disabled formatting via `serializable_hash` and added support for `format :serializable_hash` in API settings - [@dblock](https://github.com/dblock).
* [#277](https://github.com/intridea/grape/pull/277): Added a DSL to declare `formatter` in API settings - [@tim-vandecasteele](https://github.com/tim-vandecasteele).
* [#284](https://github.com/intridea/grape/pull/284): Added a DSL to declare `error_formatter` in API settings - [@dblock](https://github.com/dblock).
* Your contribution here.

0.2.2
Expand Down
27 changes: 25 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,29 @@ class Twitter::API < Grape::API
end
```

Custom error formatters for existing and additional types can be defined with a proc.

``` ruby
class Twitter::API < Grape::API
error_formatter :txt, lambda { |message, backtrace, options| "error: #{message} from #{backtrace}" }
end
```

You can also use a module or class.

``` ruby
module CustomFormatter
def self.call(message, backtrace, options)
{ message: message, backtrace: backtrace }
end
end

class Twitter::API < Grape::API
error_format :custom
error_formatter :custom, CustomFormatter
end
```

You can rescue all exceptions with a code block. The `rack_response` wrapper
automatically sets the default error code and content-type.

Expand Down Expand Up @@ -589,7 +612,7 @@ Serialization takes place automatically.
Your API can declare additional types to support. Response format is determined by the
request's extension, an explicit `format` parameter in the query string, or `Accept` header.

Custom formatters for additional types can be defined with a proc.
Custom formatters for existing and additional types can be defined with a proc.

``` ruby
class Twitter::API < Grape::API
Expand All @@ -613,7 +636,7 @@ class Twitter::API < Grape::API
end
```

You can also set the default format. Available formats are the following.
You can set the default format. Available formats are the following.

* `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
* `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
Expand Down
5 changes: 5 additions & 0 deletions lib/grape/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@ def format(new_format = nil)
new_format ? set(:format, new_format.to_sym) : settings[:format]
end

# Specify a custom formatter for a contnet-type.
def formatter(content_type, new_formatter)
settings.imbue(:formatters, content_type.to_sym => new_formatter)
end

def error_formatter(format, new_formatter)
settings.imbue(:error_formatters, format.to_sym => new_formatter)
end

# Specify the format for error messages.
# May be `:json` or `:txt` (default).
def error_format(new_format = nil)
Expand Down
1 change: 1 addition & 0 deletions lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ def build_middleware
:rescue_all => settings[:rescue_all],
:rescued_errors => aggregate_setting(:rescued_errors),
:format => settings[:error_format] || :txt,
:error_formatters => settings[:error_formatters],
:rescue_options => settings[:rescue_options],
:rescue_handlers => merged_setting(:rescue_handlers)

Expand Down
4 changes: 2 additions & 2 deletions lib/grape/error_formatter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ class << self
}

def formatters(options)
FORMATTERS.merge(options[:formatters] || {})
FORMATTERS.merge(options[:error_formatters] || {})
end

def formatter_for(api_format, options = {})
spec = formatters(options)[api_format]
case spec
when nil
lambda { |obj| obj }
lambda { |message, backtrace, options| message }
when Symbol
method(spec)
else
Expand Down
3 changes: 2 additions & 1 deletion lib/grape/middleware/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def default_options
:default_message => "",
:format => :txt,
:formatters => {},
:error_formatters => {},
:rescue_all => false, # true to rescue all exceptions
:rescue_options => { :backtrace => false }, # true to display backtrace
:rescue_handlers => {}, # rescue handler blocks
Expand Down Expand Up @@ -61,7 +62,7 @@ def rack_response(message, status = options[:default_status], headers = { 'Conte
def format_message(message, backtrace, status)
formatter = Grape::ErrorFormatter::Base.formatter_for(options[:format], options)
throw :error, :status => 406, :message => "The requested format #{options[:format]} is not supported." unless formatter
formatter.send formatter.respond_to?(:encode) ? :encode : :call, message, backtrace, options
formatter.call(message, backtrace, options)
end

end
Expand Down
23 changes: 21 additions & 2 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ class CommunicationError < RuntimeError; end
last_response.body.should eql "rain!"
end

it 'should rescue all errros and return :txt with backtrace' do
it 'should rescue all errors and return :txt with backtrace' do
subject.rescue_from :all, :backtrace => true
subject.error_format :txt
subject.get '/exception' do
Expand All @@ -889,6 +889,25 @@ class CommunicationError < RuntimeError; end
last_response.body.start_with?("rain!\r\n").should be_true
end

context "class" do
before :each do
class CustomErrorFormatter
def self.call(message, backtrace, options)
"message: #{message} @backtrace"
end
end
end
it 'should return a custom error format' do
subject.rescue_from :all, :backtrace => true
subject.error_formatter :txt, CustomErrorFormatter
subject.get '/exception' do
raise "rain!"
end
get '/exception'
last_response.body.should == "message: rain! @backtrace"
end
end

it 'should rescue all errors and return :json' do
subject.rescue_from :all
subject.error_format :json
Expand Down Expand Up @@ -981,7 +1000,7 @@ class CommunicationError < RuntimeError; end
last_response.body.should eql '{"custom_formatter":"hash"}'
end
end
context "custom formatter with a class" do
context "custom formatter class" do
module CustomFormatter
def self.call(object)
"{\"custom_formatter\":\"#{object[:some]}\"}"
Expand Down
6 changes: 4 additions & 2 deletions spec/grape/middleware/exception_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ def app
use Grape::Middleware::Error,
:rescue_all => true,
:format => :custom,
:formatters => {
:custom => lambda { |message, backtrace, options| { :custom_formatter => message }.inspect }
:error_formatters => {
:custom => lambda { |message, backtrace, options|
{ :custom_formatter => message }.inspect
}
}
run ExceptionApp
end
Expand Down

0 comments on commit 8710c60

Please sign in to comment.