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