From e6db7e7cbc48f611cf8230ae13628960f497fd2f Mon Sep 17 00:00:00 2001 From: Robert Ross Date: Thu, 31 May 2012 17:47:58 -0700 Subject: [PATCH 1/4] - Add ability to get request bodies as parameters. - Add spec to make sure body_params does not include parameters defined by the route. --- lib/grape/endpoint.rb | 21 ++++++++++++++++++++- spec/grape/endpoint_spec.rb | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) 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..4695da37e3 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -167,7 +167,31 @@ 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 + 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 XML bodies to params' do + post '/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 From 3be0f54d745bb740b9eee4400eda5a28e3a1b2fe Mon Sep 17 00:00:00 2001 From: Robert Ross Date: Fri, 1 Jun 2012 09:10:50 -0700 Subject: [PATCH 2/4] Add parameters documentation for request bodies. --- README.markdown | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.markdown b/README.markdown index c13412648e..208c28f4ec 100644 --- a/README.markdown +++ b/README.markdown @@ -143,6 +143,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://readercity.com/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. From ba2f522232ad282618d32512ed2894c9d1490c8f Mon Sep 17 00:00:00 2001 From: Robert Ross Date: Fri, 1 Jun 2012 09:28:21 -0700 Subject: [PATCH 3/4] Make sure PUT's work as well. --- spec/grape/endpoint_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 4695da37e3..8f11ed8644 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -175,6 +175,10 @@ def app; subject end 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 @@ -182,11 +186,21 @@ def app; subject end 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 From 6f22b1761165607f9f6168192c34c50a4d017f93 Mon Sep 17 00:00:00 2001 From: Robert Ross Date: Mon, 4 Jun 2012 08:51:11 -0700 Subject: [PATCH 4/4] Change example to use localhost:9292 --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 208c28f4ec..ef1c008ff0 100644 --- a/README.markdown +++ b/README.markdown @@ -146,7 +146,7 @@ along with any named parameters you specify in your route strings. 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://readercity.com/json_endpoint' -H Content-Type:application/json -v``` +```curl -d '{"some_key": "some_value"}' 'http://localhost:9292/json_endpoint' -H Content-Type:application/json -v``` The Grape Endpoint: