diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a8d88541..9cfa5408d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * [#988](https://github.com/intridea/grape/pull/988): Fixed duplicate identical endpoints - [@u2](https://github.com/u2). * [#936](https://github.com/intridea/grape/pull/936): Fixed default params processing for optional groups - [@dm1try](https://github.com/dm1try). * [#942](https://github.com/intridea/grape/pull/942): Fixed forced presence for optional params when based on a reused entity that was also required in another context - [@croeck](https://github.com/croeck). +* [#1001](https://github.com/intridea/grape/pull/1001): Fixed calling endpoint with specified format with format in its path - [@hodak](https://github.com/hodak). * Your contribution here. diff --git a/README.md b/README.md index cd6b4a1400..375ed63abc 100644 --- a/README.md +++ b/README.md @@ -1680,7 +1680,7 @@ end ``` You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file -extensions. For example, consider the following API. +extensions other than specified in `format`. For example, consider the following API. ```ruby class SingleFormatAPI < Grape::API @@ -1693,7 +1693,8 @@ end ``` * `GET /hello` will respond with JSON. -* `GET /hello.xml`, `GET /hello.json`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code. +* `GET /hello.json` will respond with JSON. +* `GET /hello.xml`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code. * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter is not supported. * `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a diff --git a/UPGRADING.md b/UPGRADING.md index 734aa950dc..18dc895940 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -56,6 +56,26 @@ error!(e) See [#889](https://github.com/intridea/grape/issues/889) for more information. +#### Changes to routes when using `format` + +Now it's possible to call API with proper suffix when single `format` is defined. I. e. + +```ruby +class API < Grape::API + format :json + + get :hello do + { hello: 'world' } + end +end +``` + +Will respond with JSON to `/hello` **and** `/hello.json`. + +Will respond with 404 to `/hello.xml`, `/hello.txt` etc. + +See the [#1001](https://github.com/intridea/grape/pull/1001) for more info. + ### Upgrading to >= 0.11.0 #### Added Rack 1.6.0 support diff --git a/lib/grape/path.rb b/lib/grape/path.rb index 15542def7c..ef5ff69b99 100644 --- a/lib/grape/path.rb +++ b/lib/grape/path.rb @@ -38,7 +38,7 @@ def has_path? def suffix if uses_specific_format? - '' + "(.#{settings[:format]})" elsif !uses_path_versioning? || (has_namespace? || has_path?) '(.:format)' else diff --git a/spec/grape/api/deeply_included_options_spec.rb b/spec/grape/api/deeply_included_options_spec.rb new file mode 100644 index 0000000000..4ab111c864 --- /dev/null +++ b/spec/grape/api/deeply_included_options_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +module API + module Defaults + extend ActiveSupport::Concern + included do + format :json + end + end + + module Admin + module Defaults + extend ActiveSupport::Concern + include API::Defaults + end + + class Users < Grape::API + include API::Admin::Defaults + + resource :users do + get do + status 200 + end + end + end + end +end + +class Main < Grape::API + mount API::Admin::Users +end + +describe Grape::API do + subject { Main } + + def app + subject + end + + it 'works for unspecified format' do + get '/users' + expect(last_response.status).to eql 200 + expect(last_response.content_type).to eql 'application/json' + end + + it 'works for specified format' do + get '/users.json' + expect(last_response.status).to eql 200 + expect(last_response.content_type).to eql 'application/json' + end + + it "doesn't work for format different than specified" do + get '/users.txt' + expect(last_response.status).to eql 404 + end +end diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 9973ae7a5f..b678eedf93 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -804,7 +804,8 @@ def subject.enable_root_route! it 'sets content type for json error' do subject.format :json subject.get('/error') { error!('error in json', 500) } - get '/error' + get '/error.json' + expect(last_response.status).to eql 500 expect(last_response.headers['Content-Type']).to eql 'application/json' end @@ -812,6 +813,7 @@ def subject.enable_root_route! subject.format :xml subject.get('/error') { error!('error in xml', 500) } get '/error' + expect(last_response.status).to eql 500 expect(last_response.headers['Content-Type']).to eql 'application/xml' end @@ -2642,7 +2644,11 @@ def static get '/meaning_of_life' expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s) end - it 'does not accept any extensions' do + it 'accepts specified extension' do + get '/meaning_of_life.txt' + expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s) + end + it 'does not accept extensions other than specified' do get '/meaning_of_life.json' expect(last_response.status).to eq(404) end diff --git a/spec/grape/path_spec.rb b/spec/grape/path_spec.rb index 799fcc2744..f2f93a067d 100644 --- a/spec/grape/path_spec.rb +++ b/spec/grape/path_spec.rb @@ -182,11 +182,12 @@ module Grape describe '#suffix' do context 'when using a specific format' do - it 'is empty' do + it 'accepts specified format' do path = Path.new(nil, nil, {}) allow(path).to receive(:uses_specific_format?) { true } + allow(path).to receive(:settings) { { format: :json } } - expect(path.suffix).to eql('') + expect(path.suffix).to eql('(.json)') end end @@ -237,12 +238,13 @@ module Grape end context 'when using a specific format' do - it 'does not have a suffix' do + it 'might have a suffix with specified format' do path = Path.new(nil, nil, {}) allow(path).to receive(:path) { '/the/path' } allow(path).to receive(:uses_specific_format?) { true } + allow(path).to receive(:settings) { { format: :json } } - expect(path.path_with_suffix).to eql('/the/path') + expect(path.path_with_suffix).to eql('/the/path(.json)') end end end