Skip to content

Commit

Permalink
Added file, explicitly set file-like response object.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Jun 3, 2015
1 parent 7a2761d commit 9b68e2b
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 5 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 @@
* [#952](/~https://github.com/intridea/grape/pull/952): Status method now raises error when called with invalid status code - [@dabrorius](/~https://github.com/dabrorius).
* [#957](/~https://github.com/intridea/grape/pull/957): Regexp validator now supports `allow_blank`, `nil` value behavior changed - [@calfzhou](https://giihub.com/calfzhou).
* [#962](/~https://github.com/intridea/grape/pull/962): The `default` attribute with `false` value is documented now - [@ajvondrak](/~https://github.com/ajvondrak).
* [#](/~https://github.com/intridea/grape/pull/): Added `file` method, explicitly setting a file-like response object - [@dblock](/~https://github.com/dblock).

#### Fixes

Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2009,7 +2009,7 @@ class API < Grape::API
end
```
You can also set the response body explicitly with `body`.
You can set the response body explicitly with `body`.
```ruby
class API < Grape::API
Expand All @@ -2023,6 +2023,28 @@ end
Use `body false` to return `204 No Content` without any data or content-type.
You can also set the response to a file-like object with `file`.
```ruby
class FileStreamer
def initialize(file_path)
@file_path = file_path
end
def each(&blk)
File.open(@file_path, 'rb') do |file|
file.each(10, &blk)
end
end
end
class API < Grape::API
get '/' do
file FileStreamer.new('file.bin')
end
end
```
## Authentication
### Basic and Digest Auth
Expand Down
16 changes: 16 additions & 0 deletions lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,22 @@ def body(value = nil)
end
end

# Allows you to define the response as a file-like object.
#
# @example
# get '/file' do
# file FileStreamer.new(...)
# end
#
# GET /file # => "contents of file"
def file(value = nil)
if value
@file = value
else
@file
end
end

# Allows you to make use of Grape Entities by setting
# the response body to the serializable hash of the
# entity provided in the `:with` option. This has the
Expand Down
6 changes: 4 additions & 2 deletions lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,13 @@ def run(env)

run_filters after_validations

response_text = @block ? @block.call(self) : nil
response_object = @block ? @block.call(self) : nil
run_filters afters
cookies.write(header)

[status, header, [body || response_text]]
# The Body commonly is an Array of Strings, the application instance itself, or a File-like object.
response_object = file || [body || response_object]
[status, header, response_object]
end

def build_middleware
Expand Down
4 changes: 2 additions & 2 deletions lib/grape/middleware/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ def after
api_format = mime_types[headers[Grape::Http::Headers::CONTENT_TYPE]] || env['api.format']
formatter = Grape::Formatter::Base.formatter_for api_format, options
begin
bodymap = bodies.collect do |body|
bodymap = bodies.respond_to?(:collect) ? bodies.collect do |body|
formatter.call body, env
end
end : bodies
rescue Grape::Exceptions::InvalidFormatter => e
throw :error, status: 500, message: e.message
end
Expand Down
14 changes: 14 additions & 0 deletions spec/grape/endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -927,4 +927,18 @@ def memoized
expect(last_response.status).to eq(406)
end
end

context 'binary' do
before do
subject.get do
file FileStreamer.new(__FILE__)
end
end

it 'suports stream objects in response' do
get '/'
expect(last_response.status).to eq 200
expect(last_response.body).to eq File.read(__FILE__)
end
end
end
11 changes: 11 additions & 0 deletions spec/support/file_streamer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class FileStreamer
def initialize(file_path)
@file_path = file_path
end

def each(&blk)
File.open(@file_path, 'rb') do |file|
file.each(10, &blk)
end
end
end

0 comments on commit 9b68e2b

Please sign in to comment.