Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions lib/grape/middleware/base.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'multi_json'

module Grape
module Middleware
class Base
Expand Down Expand Up @@ -53,11 +55,18 @@ module Formats
:json => :encode_json,
:txt => :encode_txt,
}
PARSERS = {
:json => :decode_json
}

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

def parsers
PARSERS.merge(options[:parsers] || {})
end

def content_types
CONTENT_TYPES.merge(options[:content_types] || {})
end
Expand All @@ -82,6 +91,35 @@ def formatter_for(api_format)
end
end

def parser_for(api_format)
spec = parsers[api_format]
case spec
when nil
nil
when Symbol
method(spec)
else
spec
end
end

def decode_json(object)
MultiJson.decode(object)
end

def encode_json(object)
if object.respond_to? :serializable_hash
MultiJson.encode(object.serializable_hash)
elsif object.respond_to? :to_json
object.to_json
else
MultiJson.encode(object)
end
end

def encode_txt(object)
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
end
end

end
Expand Down
33 changes: 16 additions & 17 deletions lib/grape/middleware/formatter.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require 'grape/middleware/base'
require 'multi_json'

module Grape
module Middleware
Expand All @@ -10,7 +9,8 @@ def default_options
{
:default_format => :txt,
:formatters => {},
:content_types => {}
:content_types => {},
:parsers => {}
}
end

Expand All @@ -22,7 +22,20 @@ def before
fmt = format_from_extension || format_from_header || options[:default_format]

if content_types.key?(fmt)
env['api.format'] = fmt
if !env['rack.input'].nil? and (body = env['rack.input'].read).strip.length != 0
parser = parser_for fmt
unless parser.nil?
begin
body = parser.call(body)
env['rack.request.form_hash'] = !env['rack.request.form_hash'].nil? ? env['rack.request.form_hash'].merge(body) : body
env['rack.request.form_input'] = env['rack.input']
rescue
# It's possible that it's just regular POST content -- just back off
end
end
env['rack.input'].rewind
end
env['api.format'] = fmt
else
throw :error, :status => 406, :message => 'The requested format is not supported.'
end
Expand Down Expand Up @@ -69,20 +82,6 @@ def after
headers['Content-Type'] = content_types[env['api.format']]
Rack::Response.new(bodymap, status, headers).to_a
end

def encode_json(object)
if object.respond_to? :serializable_hash
MultiJson.encode(object.serializable_hash)
elsif object.respond_to? :to_json
object.to_json
else
MultiJson.encode(object)
end
end

def encode_txt(object)
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
end
end
end
end
12 changes: 12 additions & 0 deletions spec/grape/middleware/formatter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,16 @@ def serializable_hash
body.body.should == ['CUSTOM JSON FORMAT']
end
end

context 'Input' do
it 'should parse the body from a POST/PUT and put the contents into rack.request.form_hash' do
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json', 'rack.input' => StringIO.new('{"is_boolean":true,"string":"thing"}')})
subject.env['rack.request.form_hash']['is_boolean'].should be_true
subject.env['rack.request.form_hash']['string'].should == 'thing'
end
it 'should be able to fail gracefully if the body is regular POST content' do
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json', 'rack.input' => StringIO.new('name=Other+Test+Thing')})
subject.env['rack.request.form_hash'].should be_nil
end
end
end