Skip to content

Commit 1958fad

Browse files
author
Ted Kulp
committed
Ability to handle incoming JSON in the body
This allows Grape to work with ActiveResource in JSON mode. If the body contains JSON, it's contents will be added to the params hash just like if they came over the GET query string or as regular params.
1 parent 3ffde6a commit 1958fad

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

lib/grape/middleware/formatter.rb

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ class Formatter < Base
1515
:json => :encode_json,
1616
:txt => :encode_txt,
1717
}
18+
PARSERS = {
19+
:json => :decode_json
20+
}
1821

1922
def default_options
2023
{
2124
:default_format => :txt,
2225
:formatters => {},
23-
:content_types => {}
26+
:content_types => {},
27+
:parsers => {}
2428
}
2529
end
2630

@@ -31,6 +35,10 @@ def content_types
3135
def formatters
3236
FORMATTERS.merge(options[:formatters])
3337
end
38+
39+
def parsers
40+
PARSERS.merge(options[:parsers])
41+
end
3442

3543
def mime_types
3644
content_types.invert
@@ -44,7 +52,19 @@ def before
4452
fmt = format_from_extension || format_from_header || options[:default_format]
4553

4654
if content_types.key?(fmt)
47-
env['api.format'] = fmt
55+
if !env['rack.input'].nil? and (body = env['rack.input'].read).length != 0
56+
parser = parser_for fmt
57+
unless parser.nil?
58+
begin
59+
env['rack.request.form_hash'] = !env['rack.request.form_hash'].nil? ? env['rack.request.form_hash'].merge(parser.call(body)) : parser.call(body)
60+
env['rack.request.form_input'] = env['rack.input']
61+
rescue
62+
throw :error, :status => 400, :message => 'Body content could not be parsed.'
63+
end
64+
end
65+
env['rack.input'].rewind
66+
end
67+
env['api.format'] = fmt
4868
else
4969
throw :error, :status => 406, :message => 'The requested format is not supported.'
5070
end
@@ -103,6 +123,22 @@ def formatter_for(api_format)
103123
spec
104124
end
105125
end
126+
127+
def parser_for(api_format)
128+
spec = parsers[api_format]
129+
case spec
130+
when nil
131+
nil
132+
when Symbol
133+
method(spec)
134+
else
135+
spec
136+
end
137+
end
138+
139+
def decode_json(object)
140+
MultiJson.decode(object)
141+
end
106142

107143
def encode_json(object)
108144
if object.respond_to? :serializable_hash

spec/grape/middleware/formatter_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,16 @@ def serializable_hash
123123
body.body.should == ['CUSTOM JSON FORMAT']
124124
end
125125
end
126+
127+
context 'Input' do
128+
it 'should parse the body from a POST/PUT and put the contents into rack.request.form_hash' do
129+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json', 'rack.input' => StringIO.new('{"is_boolean":true,"string":"thing"}')})
130+
subject.env['rack.request.form_hash']['is_boolean'].should be_true
131+
subject.env['rack.request.form_hash']['string'].should == 'thing'
132+
end
133+
it 'should be able to fail gracefully if the body is invalid' do
134+
err = catch(:error){ subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json', 'rack.input' => StringIO.new('{"is_boolean":true,string:"thing"}')}) }
135+
err.should == {:status => 400, :message => "Body content could not be parsed."}
136+
end
137+
end
126138
end

0 commit comments

Comments
 (0)