Skip to content

Commit

Permalink
Fix fetch_formatter api_format (#2506)
Browse files Browse the repository at this point in the history
* Add `api_format` function accessible from inside_route
fetch_formatter will look api.format first
Use fetch {} instead of [] ||
Update spec
Add HTTP_VERSION in Grape::Http::Headers
Update README

* Add CHANGELOG and UPGRADING.md

* Change `api_format` to ':txt'

* Fix upgrading
  • Loading branch information
ericproulx authored Oct 20, 2024
1 parent 277fe3e commit f4e2af5
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#### Fixes

* [#2504](https://github.com/ruby-grape/grape/pull/2504): Fix leaky modules in specs - [@ericproulx](https://github.com/ericproulx).
* [#2506](https://github.com/ruby-grape/grape/pull/2506): Fix fetch_formatter api_format - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

### 2.2.0 (2024-09-14)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3066,15 +3066,15 @@ end
* `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header corresponds to a recognized format, so it will respond with XML.
* `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header, so it will respond with JSON (the default format).

You can override this process explicitly by specifying `env['api.format']` in the API itself.
You can override this process explicitly by calling `api_format` in the API itself.
For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.

```ruby
class Twitter::API < Grape::API
post 'attachment' do
filename = params[:file][:filename]
content_type MIME::Types.type_for(filename)[0].to_s
env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
api_format :binary # there's no formatter for :binary, data will be returned "as is"
header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(filename)}"
params[:file][:tempfile].read
end
Expand Down
6 changes: 6 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ Upgrading Grape

### Upgrading to >= 2.3.0

### `content_type` vs `api.format` inside API

Before 2.3.0, `content_type` had priority over `env['api.format']` when set in an API, which was incorrect. The priority has been flipped and `env['api.format']` will be checked first.
In addition, the function `api_format` has been added. Instead of setting `env['api.format']` directly, you can call `api_format`.
See [#2506](https://github.com/ruby-grape/grape/pull/2506) for more information.

#### Remove Deprecated Methods and Options

- Deprecated `file` method has been removed. Use `send_file` or `stream`.
Expand Down
6 changes: 5 additions & 1 deletion lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,11 @@ def entity_representation_for(entity_class, object, options)
end

def http_version
env['HTTP_VERSION'] || env[Rack::SERVER_PROTOCOL]
env.fetch(Grape::Http::Headers::HTTP_VERSION) { env[Rack::SERVER_PROTOCOL] }
end

def api_format(format)
env[Grape::Env::API_FORMAT] = format
end

def context
Expand Down
1 change: 1 addition & 0 deletions lib/grape/http/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Headers
HTTP_ACCEPT_VERSION = 'HTTP_ACCEPT_VERSION'
HTTP_ACCEPT = 'HTTP_ACCEPT'
HTTP_TRANSFER_ENCODING = 'HTTP_TRANSFER_ENCODING'
HTTP_VERSION = 'HTTP_VERSION'

ALLOW = 'Allow'
LOCATION = 'Location'
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/middleware/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def build_formatted_response(status, headers, bodies)
end

def fetch_formatter(headers, options)
api_format = mime_types[headers[Rack::CONTENT_TYPE]] || env[Grape::Env::API_FORMAT]
api_format = env.fetch(Grape::Env::API_FORMAT) { mime_types[headers[Rack::CONTENT_TYPE]] }
Grape::Formatter.formatter_for(api_format, options[:formatters])
end

Expand Down
4 changes: 2 additions & 2 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4092,9 +4092,9 @@ def my_method
expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
end

it 'can be overwritten with an explicit content type' do
it 'can be overwritten with an explicit api_format' do
subject.get '/meaning_of_life_with_content_type' do
content_type 'text/plain'
api_format :txt
{ meaning_of_life: 42 }.to_s
end
get '/meaning_of_life_with_content_type'
Expand Down

0 comments on commit f4e2af5

Please sign in to comment.