Skip to content

Commit 9b68e2b

Browse files
committed
Added file, explicitly set file-like response object.
1 parent 7a2761d commit 9b68e2b

File tree

7 files changed

+71
-5
lines changed

7 files changed

+71
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* [#952](https://github.com/intridea/grape/pull/952): Status method now raises error when called with invalid status code - [@dabrorius](https://github.com/dabrorius).
1212
* [#957](https://github.com/intridea/grape/pull/957): Regexp validator now supports `allow_blank`, `nil` value behavior changed - [@calfzhou](https://giihub.com/calfzhou).
1313
* [#962](https://github.com/intridea/grape/pull/962): The `default` attribute with `false` value is documented now - [@ajvondrak](https://github.com/ajvondrak).
14+
* [#](https://github.com/intridea/grape/pull/): Added `file` method, explicitly setting a file-like response object - [@dblock](https://github.com/dblock).
1415

1516
#### Fixes
1617

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2009,7 +2009,7 @@ class API < Grape::API
20092009
end
20102010
```
20112011
2012-
You can also set the response body explicitly with `body`.
2012+
You can set the response body explicitly with `body`.
20132013
20142014
```ruby
20152015
class API < Grape::API
@@ -2023,6 +2023,28 @@ end
20232023
20242024
Use `body false` to return `204 No Content` without any data or content-type.
20252025
2026+
You can also set the response to a file-like object with `file`.
2027+
2028+
```ruby
2029+
class FileStreamer
2030+
def initialize(file_path)
2031+
@file_path = file_path
2032+
end
2033+
2034+
def each(&blk)
2035+
File.open(@file_path, 'rb') do |file|
2036+
file.each(10, &blk)
2037+
end
2038+
end
2039+
end
2040+
2041+
class API < Grape::API
2042+
get '/' do
2043+
file FileStreamer.new('file.bin')
2044+
end
2045+
end
2046+
```
2047+
20262048
## Authentication
20272049
20282050
### Basic and Digest Auth

lib/grape/dsl/inside_route.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@ def body(value = nil)
169169
end
170170
end
171171

172+
# Allows you to define the response as a file-like object.
173+
#
174+
# @example
175+
# get '/file' do
176+
# file FileStreamer.new(...)
177+
# end
178+
#
179+
# GET /file # => "contents of file"
180+
def file(value = nil)
181+
if value
182+
@file = value
183+
else
184+
@file
185+
end
186+
end
187+
172188
# Allows you to make use of Grape Entities by setting
173189
# the response body to the serializable hash of the
174190
# entity provided in the `:with` option. This has the

lib/grape/endpoint.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,13 @@ def run(env)
248248

249249
run_filters after_validations
250250

251-
response_text = @block ? @block.call(self) : nil
251+
response_object = @block ? @block.call(self) : nil
252252
run_filters afters
253253
cookies.write(header)
254254

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

258260
def build_middleware

lib/grape/middleware/formatter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ def after
2929
api_format = mime_types[headers[Grape::Http::Headers::CONTENT_TYPE]] || env['api.format']
3030
formatter = Grape::Formatter::Base.formatter_for api_format, options
3131
begin
32-
bodymap = bodies.collect do |body|
32+
bodymap = bodies.respond_to?(:collect) ? bodies.collect do |body|
3333
formatter.call body, env
34-
end
34+
end : bodies
3535
rescue Grape::Exceptions::InvalidFormatter => e
3636
throw :error, status: 500, message: e.message
3737
end

spec/grape/endpoint_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,4 +927,18 @@ def memoized
927927
expect(last_response.status).to eq(406)
928928
end
929929
end
930+
931+
context 'binary' do
932+
before do
933+
subject.get do
934+
file FileStreamer.new(__FILE__)
935+
end
936+
end
937+
938+
it 'suports stream objects in response' do
939+
get '/'
940+
expect(last_response.status).to eq 200
941+
expect(last_response.body).to eq File.read(__FILE__)
942+
end
943+
end
930944
end

spec/support/file_streamer.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class FileStreamer
2+
def initialize(file_path)
3+
@file_path = file_path
4+
end
5+
6+
def each(&blk)
7+
File.open(@file_path, 'rb') do |file|
8+
file.each(10, &blk)
9+
end
10+
end
11+
end

0 commit comments

Comments
 (0)