diff --git a/CHANGELOG.md b/CHANGELOG.md index bf032218ee..231b544aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ Next Release ============ * [#352](https://github.com/intridea/grape/pull/352): Modified registration/execution order of Rack Middleware, fixes issues with `Rack::JSONP` responses that contain a `Grape::Entity` - [@deckchair](https://github.com/deckchair). +* [#347](https://github.com/intridea/grape/issues/347): Grape will accept any valid JSON as PUT or POST, including strings, symbols and arrays - [@qqshfox](https://github.com/qqshfox), [@dblock](https://github.com/dblock). +* [#347](https://github.com/intridea/grape/issues/347): JSON format APIs will always return valid JSON, eg. strings are now returned as `"string"` and no longer `string` - [@dblock](https://github.com/dblock). * Your contribution here. 0.3.2 (2/28/2013) diff --git a/lib/grape/formatter/json.rb b/lib/grape/formatter/json.rb index 37c060c1a9..5bea9b20c1 100644 --- a/lib/grape/formatter/json.rb +++ b/lib/grape/formatter/json.rb @@ -4,7 +4,6 @@ module Json class << self def call(object, env) - return object if object.is_a?(String) return object.to_json if object.respond_to?(:to_json) MultiJson.dump(object) end diff --git a/lib/grape/middleware/formatter.rb b/lib/grape/middleware/formatter.rb index 8c2e81a45d..1969d33fa4 100644 --- a/lib/grape/middleware/formatter.rb +++ b/lib/grape/middleware/formatter.rb @@ -44,10 +44,14 @@ def read_body_input fmt = mime_types[request.media_type] if request.media_type if content_type_for(fmt) parser = Grape::Parser::Base.parser_for fmt, options - unless parser.nil? + if parser begin - body = parser.call body, env - env['rack.request.form_hash'] = env['rack.request.form_hash'] ? env['rack.request.form_hash'].merge(body) : body + body = (env['api.request.body'] = parser.call(body, env)) + if body.is_a?(Hash) + env['rack.request.form_hash'] = env['rack.request.form_hash'] ? env['rack.request.form_hash'].merge(body) : body + else + env['api.request.body'] = body + end env['rack.request.form_input'] = env['rack.input'] rescue Exception => e throw :error, :status => 400, :message => e.message diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 87271e42b6..9ce1a59196 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -203,13 +203,14 @@ def app; subject end describe 'root routes should work with' do before do + subject.format :txt def subject.enable_root_route! - self.get("/") {"root"} + self.get("/") { "root" } end end after do - last_response.body.should eql 'root' + last_response.body.should eql "root" end describe 'path versioned APIs' do @@ -314,16 +315,18 @@ def subject.enable_root_route! last_response.body.should eql 'hiya' end - %w(put post).each do |verb| - ['string', :symbol, 1, -1.1, {}, [], true, false, nil].each do |object| - it "allows a(n) #{object.class} json object for #{verb.upcase} when accessing the params" do - subject.send(verb) do - params # TODO: get the object passed in - {} + [ :put, :post ].each do |verb| + context verb do + [ 'string', :symbol, 1, -1.1, {}, [], true, false, nil ].each do |object| + it "allows a(n) #{object.class} json object in params" do + subject.format :json + subject.send(verb) do + env['api.request.body'] + end + send verb, '/', MultiJson.dump(object), { 'CONTENT_TYPE' => 'application/json' } + last_response.status.should == (verb == :post ? 201 : 200) + last_response.body.should eql MultiJson.dump(object) end - send verb, '/', MultiJson.dump(object), {'CONTENT_TYPE' => 'application/json'} - last_response.status.should == (verb == 'post' ? 201 : 200) - last_response.body.should eql '{}' end end end diff --git a/spec/grape/validations/presence_spec.rb b/spec/grape/validations/presence_spec.rb index 37b969dd7a..9231a6d5ab 100644 --- a/spec/grape/validations/presence_spec.rb +++ b/spec/grape/validations/presence_spec.rb @@ -17,7 +17,7 @@ class API < Grape::API requires :id, :regexp => /^[0-9]+$/ end post do - {:ret => params[:id]} + { :ret => params[:id] } end params do @@ -60,7 +60,7 @@ def app it 'does not validate for any params' do get("/bacons") last_response.status.should == 200 - last_response.body.should == "All the bacon" + last_response.body.should == "All the bacon".to_json end it 'validates id' do @@ -94,7 +94,7 @@ def app get('/', :name => "Bob", :company => "TestCorp") last_response.status.should == 200 - last_response.body.should == "Hello" + last_response.body.should == "Hello".to_json end it 'validates nested parameters' do @@ -108,7 +108,7 @@ def app get('/nested', :user => {:first_name => "Billy", :last_name => "Bob"}) last_response.status.should == 200 - last_response.body.should == "Nested" + last_response.body.should == "Nested".to_json end it 'validates triple nested parameters' do @@ -138,7 +138,7 @@ def app get('/nested_triple', :admin => { :admin_name => 'admin', :super => {:user => {:first_name => "Billy", :last_name => "Bob"}}}) last_response.status.should == 200 - last_response.body.should == "Nested triple" + last_response.body.should == "Nested triple".to_json end end diff --git a/spec/shared/versioning_examples.rb b/spec/shared/versioning_examples.rb index 3ca6bb317e..b7898fe4d5 100644 --- a/spec/shared/versioning_examples.rb +++ b/spec/shared/versioning_examples.rb @@ -1,5 +1,6 @@ shared_examples_for 'versioning' do it 'sets the API version' do + subject.format :txt subject.version 'v1', macro_options subject.get :hello do "Version: #{request.env['api.version']}" @@ -9,7 +10,8 @@ end it 'adds the prefix before the API version' do - subject.prefix 'api' + subject.format :txt + subject.prefix 'api' subject.version 'v1', macro_options subject.get :hello do "Version: #{request.env['api.version']}" @@ -58,6 +60,7 @@ context 'with different versions for the same endpoint' do context 'without a prefix' do it 'allows the same endpoint to be implemented' do + subject.format :txt subject.version 'v2', macro_options subject.get 'version' do request.env['api.version'] @@ -79,7 +82,8 @@ end context 'with a prefix' do - it 'allows the same endpoint to be implemented' do + it 'allows the same endpoint to be implemented' do + subject.format :txt subject.prefix 'api' subject.version 'v2', macro_options subject.get 'version' do