Skip to content

Commit da3bbea

Browse files
author
Jan Xie
committed
fix content type of error response, refactor format handling
1 parent 7874d52 commit da3bbea

File tree

4 files changed

+85
-63
lines changed

4 files changed

+85
-63
lines changed

lib/grape/middleware/base.rb

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Grape
22
module Middleware
33
class Base
44
attr_reader :app, :env, :options
5-
5+
66
# @param [Rack Application] app The standard argument for a Rack middleware.
77
# @param [Hash] options A hash of options, simply stored for use by subclasses.
88
def initialize(app, options = {})
@@ -38,6 +38,52 @@ def request
3838
def response
3939
Rack::Response.new(@app_response)
4040
end
41+
42+
43+
module Formats
44+
45+
CONTENT_TYPES = {
46+
:xml => 'application/xml',
47+
:json => 'application/json',
48+
:atom => 'application/atom+xml',
49+
:rss => 'application/rss+xml',
50+
:txt => 'text/plain'
51+
}
52+
FORMATTERS = {
53+
:json => :encode_json,
54+
:txt => :encode_txt,
55+
}
56+
57+
def formatters
58+
FORMATTERS.merge(options[:formatters] || {})
59+
end
60+
61+
def content_types
62+
CONTENT_TYPES.merge(options[:content_types] || {})
63+
end
64+
65+
def content_type
66+
content_types[options[:format]] || 'text/html'
67+
end
68+
69+
def mime_types
70+
content_types.invert
71+
end
72+
73+
def formatter_for(api_format)
74+
spec = formatters[api_format]
75+
case spec
76+
when nil
77+
lambda { |obj| obj }
78+
when Symbol
79+
method(spec)
80+
else
81+
spec
82+
end
83+
end
84+
85+
end
86+
4187
end
4288
end
43-
end
89+
end

lib/grape/middleware/error.rb

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
module Grape
55
module Middleware
66
class Error < Base
7-
7+
include Formats
8+
89
def default_options
910
{
1011
:default_status => 403, # default status returned on error
@@ -18,36 +19,15 @@ def default_options
1819
}
1920
end
2021

21-
FORMATTERS = {
22-
:json => :format_json,
23-
:txt => :format_txt,
24-
}
25-
26-
def formatters
27-
FORMATTERS.merge(options[:formatters])
28-
end
29-
30-
def formatter_for(api_format)
31-
spec = formatters[api_format]
32-
case spec
33-
when nil
34-
lambda { |obj| obj }
35-
when Symbol
36-
method(spec)
37-
else
38-
spec
39-
end
40-
end
41-
42-
def format_json(message, backtrace)
22+
def encode_json(message, backtrace)
4323
result = message.is_a?(Hash) ? message : { :error => message }
4424
if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
4525
result = result.merge({ :backtrace => backtrace })
4626
end
4727
MultiJson.encode(result)
4828
end
4929

50-
def format_txt(message, backtrace)
30+
def encode_txt(message, backtrace)
5131
result = message.is_a?(Hash) ? MultiJson.encode(message) : message
5232
if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
5333
result += "\r\n "
@@ -73,7 +53,8 @@ def call!(env)
7353
def error_response(error = {})
7454
status = error[:status] || options[:default_status]
7555
message = error[:message] || options[:default_message]
76-
headers = error[:headers] || {}
56+
headers = {'Content-Type' => content_type}
57+
headers.merge!(error[:headers]) if error[:headers].is_a?(Hash)
7758
backtrace = error[:backtrace] || []
7859
Rack::Response.new([format_message(message, backtrace, status)], status, headers).finish
7960
end

lib/grape/middleware/formatter.rb

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,8 @@
44
module Grape
55
module Middleware
66
class Formatter < Base
7-
CONTENT_TYPES = {
8-
:xml => 'application/xml',
9-
:json => 'application/json',
10-
:atom => 'application/atom+xml',
11-
:rss => 'application/rss+xml',
12-
:txt => 'text/plain'
13-
}
14-
FORMATTERS = {
15-
:json => :encode_json,
16-
:txt => :encode_txt,
17-
}
18-
7+
include Formats
8+
199
def default_options
2010
{
2111
:default_format => :txt,
@@ -24,18 +14,6 @@ def default_options
2414
}
2515
end
2616

27-
def content_types
28-
CONTENT_TYPES.merge(options[:content_types])
29-
end
30-
31-
def formatters
32-
FORMATTERS.merge(options[:formatters])
33-
end
34-
35-
def mime_types
36-
content_types.invert
37-
end
38-
3917
def headers
4018
env.dup.inject({}){|h,(k,v)| h[k.downcase] = v; h}
4119
end
@@ -92,18 +70,6 @@ def after
9270
Rack::Response.new(bodymap, status, headers).to_a
9371
end
9472

95-
def formatter_for(api_format)
96-
spec = formatters[api_format]
97-
case spec
98-
when nil
99-
lambda { |obj| obj }
100-
when Symbol
101-
method(spec)
102-
else
103-
spec
104-
end
105-
end
106-
10773
def encode_json(object)
10874
if object.respond_to? :serializable_hash
10975
MultiJson.encode(object.serializable_hash)

spec/grape/api_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,35 @@ def app; subject end
276276
last_response.body.should eql 'Created'
277277
end
278278
end
279+
280+
context 'format' do
281+
before do
282+
subject.get("/foo") { "bar" }
283+
end
284+
285+
it 'should set content type for txt format' do
286+
get '/foo'
287+
last_response.headers['Content-Type'].should eql 'text/plain'
288+
end
289+
290+
it 'should set content type for json' do
291+
get '/foo.json'
292+
last_response.headers['Content-Type'].should eql 'application/json'
293+
end
294+
295+
it 'should set content type for error' do
296+
subject.get('/error') { error!('error in plain text', 500) }
297+
get '/error'
298+
last_response.headers['Content-Type'].should eql 'text/plain'
299+
end
300+
301+
it 'should set content type for error' do
302+
subject.error_format :json
303+
subject.get('/error') { error!('error in json', 500) }
304+
get '/error.json'
305+
last_response.headers['Content-Type'].should eql 'application/json'
306+
end
307+
end
279308

280309
context 'custom middleware' do
281310
class PhonyMiddleware

0 commit comments

Comments
 (0)