diff --git a/README.markdown b/README.markdown index 5553dee555..533b58f4f9 100644 --- a/README.markdown +++ b/README.markdown @@ -161,6 +161,19 @@ along with any named parameters you specify in your route strings. end ``` +Parameters are also populated from the request body on POST and PUT for JSON and XML content-types. + +The Request: +```curl -d '{"some_key": "some_value"}' 'http://localhost:9292/json_endpoint' -H Content-Type:application/json -v``` + + +The Grape Endpoint: +```ruby + post '/json_endpoint' do + params[:some_key] + end +``` + ## Headers Headers are available through the `env` hash object. diff --git a/lib/grape/endpoint.rb b/lib/grape/endpoint.rb index 38f63fd028..cbd318f458 100644 --- a/lib/grape/endpoint.rb +++ b/lib/grape/endpoint.rb @@ -118,7 +118,26 @@ def call!(env) # The parameters passed into the request as # well as parsed from URL segments. def params - @params ||= Hashie::Mash.new.deep_merge(request.params).deep_merge(env['rack.routing_args'] || {}) + @params ||= Hashie::Mash.new. + deep_merge(request.params). + deep_merge(env['rack.routing_args'] || {}). + deep_merge(self.body_params) + end + + # Pull out request body params if the content type matches and we're on a POST or PUT + def body_params + if ['POST', 'PUT'].include?(request.request_method.to_s.upcase) + return case env['CONTENT_TYPE'] + when 'application/json' + MultiJson.decode(request.body.read) + when 'application/xml' + MultiXml.parse(request.body.read) + else + {} + end + end + + {} end # The API version as specified in the URL. diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 79ff11671a..8f11ed8644 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -167,7 +167,45 @@ def app; subject end get 'rodzyn@test.com/wrong_middle/1' last_response.status.should == 404 + end + end + + context 'from body parameters' do + before(:each) do + subject.post '/request_body' do + params[:user] + end + + subject.put '/request_body' do + params[:user] + end + end + + it 'should convert JSON bodies to params' do + post '/request_body', MultiJson.encode(user: 'Bobby T.'), {'CONTENT_TYPE' => 'application/json'} + last_response.body.should == 'Bobby T.' + end + + it 'should convert JSON bodies to params' do + put '/request_body', MultiJson.encode(user: 'Bobby T.'), {'CONTENT_TYPE' => 'application/json'} + last_response.body.should == 'Bobby T.' + end + + it 'should convert XML bodies to params' do + post '/request_body', 'Bobby T.', {'CONTENT_TYPE' => 'application/xml'} + last_response.body.should == 'Bobby T.' + end + + it 'should convert XML bodies to params' do + put '/request_body', 'Bobby T.', {'CONTENT_TYPE' => 'application/xml'} + last_response.body.should == 'Bobby T.' + end + it 'does not include parameters not defined by the body' do + subject.post '/omitted_params' do + body_params[:version].should == nil + end + post '/omitted_params', MultiJson.encode(user: 'Blah'), {'CONTENT_TYPE' => 'application/json'} end end end