From 4aa9ab6a4b6f45f7485b26754642a901a6fce5f9 Mon Sep 17 00:00:00 2001 From: dblock Date: Sun, 19 May 2013 21:39:27 -0400 Subject: [PATCH] Fix #407: specifying 'default_format' will also set the default POST/PUT data parser to the given format. --- CHANGELOG.md | 3 ++- README.md | 10 ++++++++++ lib/grape/middleware/formatter.rb | 4 +++- spec/grape/api_spec.rb | 32 +++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b677c3e20..64e5c40476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ Next Release * [#392](https://github.com/intridea/grape/pull/392): Extracted headers and params from `Endpoint` to `Grape::Request` - [@niedhui](https://github.com/niedhui). * [#394](https://github.com/intridea/grape/pull/394): Path version no longer overwrites a `version` parameter - [@tmornini](https://github.com/tmornini). * [#390](https://github.com/intridea/grape/pull/390): Added default value for an `optional` parameter - [@oivoodoo](https://github.com/oivoodoo). -* [#403](https://github.com/intridea/grape/pull/403): Added support for versioning using the `Accept-Version` header - [@politician](https://github.com/politician). +* [#403](https://github.com/intridea/grape/pull/403): Added support for versioning using the `Accept-Version` header - [@politician](https://github.com/politician). +* [#407](https://github.com/intridea/grape/issues/407): Specifying `default_format` will also set the default POST/PUT data parser to the given format - [@dblock](https://github.com/dblock). * Your contribution here. 0.4.1 (4/1/2013) diff --git a/README.md b/README.md index 36d6014e76..29f5b03680 100644 --- a/README.md +++ b/README.md @@ -799,6 +799,16 @@ class Twitter::API < Grape::API end ``` +When the content-type is omitted, Grape will return a 406 error code unless `default_format` is specified. +The following API will try to parse any data without a content-type using a JSON parser. + +```ruby +class Twitter::API < Grape::API + format :json + default_format :json +end +``` + If you combine `format` with `rescue_from :all`, errors will be rendered using the same format. If you do not want this behavior, set the default error formatter with `default_error_formatter`. diff --git a/lib/grape/middleware/formatter.rb b/lib/grape/middleware/formatter.rb index 996cb398a3..046ef88a21 100644 --- a/lib/grape/middleware/formatter.rb +++ b/lib/grape/middleware/formatter.rb @@ -40,7 +40,8 @@ def after # store read input in env['api.request.input'] def read_body_input if (request.post? || request.put? || request.patch?) && - (! request.form_data?) && (! request.parseable_data?) && + (! request.form_data? || ! request.media_type) && + (! request.parseable_data?) && (request.content_length.to_i > 0 || request.env['HTTP_TRANSFER_ENCODING'] == 'chunked') if env['rack.input'] && (body = (env['api.request.input'] = env['rack.input'].read)).length > 0 @@ -53,6 +54,7 @@ def read_body_input def read_rack_input(body) begin fmt = mime_types[request.media_type] if request.media_type + fmt ||= options[:default_format] if content_type_for(fmt) parser = Grape::Parser::Base.parser_for fmt, options if parser diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 0dd03084cc..f6e3408aee 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -1267,6 +1267,15 @@ def self.call(object, env) end describe '.parser' do + it 'parses data in format requested by content-type' do + subject.format :json + subject.post '/data' do + { :x => params[:x] } + end + post "/data", '{"x":42}', { 'CONTENT_TYPE' => 'application/json' } + last_response.status.should == 201 + last_response.body.should == '{"x":42}' + end context 'lambda parser' do before :each do subject.content_type :txt, "text/plain" @@ -1329,6 +1338,29 @@ def self.call(object, env) end end + describe '.default_format' do + before :each do + subject.format :json + subject.default_format :json + end + it 'returns data in default format' do + subject.get '/data' do + { :x => 42 } + end + get "/data" + last_response.status.should == 200 + last_response.body.should == '{"x":42}' + end + it 'parses data in default format' do + subject.post '/data' do + { :x => params[:x] } + end + post "/data", '{"x":42}', "CONTENT_TYPE" => "" + last_response.status.should == 201 + last_response.body.should == '{"x":42}' + end + end + describe '.default_error_status' do it 'allows setting default_error_status' do subject.rescue_from :all