mirror of
https://github.com/rest-client/rest-client.git
synced 2022-11-09 13:49:40 -05:00
Add much more documentation around streaming.
Write docs on both methods of streaming responses, and add docs around streaming request payloads.
This commit is contained in:
parent
e0e48fc4db
commit
8c3375b299
2 changed files with 87 additions and 14 deletions
98
README.md
98
README.md
|
@ -444,35 +444,105 @@ You can:
|
||||||
- override cookies
|
- override cookies
|
||||||
- manually handle the response (e.g. to operate on it as a stream rather than reading it all into memory)
|
- manually handle the response (e.g. to operate on it as a stream rather than reading it all into memory)
|
||||||
|
|
||||||
See `RestClient::Request`'s documentation for more information.
|
See `RestClient::Request`'s documentation for more information.
|
||||||
|
|
||||||
### Streaming
|
### Streaming request payload
|
||||||
|
|
||||||
|
RestClient will try to stream any file-like payload rather than reading it into
|
||||||
|
memory. This happens through `RestClient::Payload::Streamed`, which is
|
||||||
|
automatically called internally by `RestClient::Payload.generate` on anything
|
||||||
|
with a `read` method.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
>> r = RestClient.put('http://httpbin.org/put', File.open('/tmp/foo.txt', 'r'),
|
||||||
|
content_type: 'text/plain')
|
||||||
|
=> <RestClient::Response 200 "{\n \"args\":...">
|
||||||
|
```
|
||||||
|
|
||||||
|
In Multipart requests, RestClient will also stream file handles passed as Hash
|
||||||
|
(or __new in 2.1__ ParamsArray).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
>> r = RestClient.put('http://httpbin.org/put',
|
||||||
|
{file_a: File.open('a.txt', 'r'),
|
||||||
|
file_b: File.open('b.txt', 'r')})
|
||||||
|
=> <RestClient::Response 200 "{\n \"args\":...">
|
||||||
|
|
||||||
|
# received by server as two file uploads with multipart/form-data
|
||||||
|
>> JSON.parse(r)['files'].keys
|
||||||
|
=> ['file_a', 'file_b']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Streaming responses
|
||||||
|
|
||||||
Normally, when you use `RestClient.get` or the lower level
|
Normally, when you use `RestClient.get` or the lower level
|
||||||
`RestClient::Request.execute method: :get` to retrieve data, the entire
|
`RestClient::Request.execute method: :get` to retrieve data, the entire
|
||||||
response is buffered in memory and returned as the response to the call.
|
response is buffered in memory and returned as the response to the call.
|
||||||
|
|
||||||
However, if you are retrieving a large amount of data, for example a Docker
|
However, if you are retrieving a large amount of data, for example a Docker
|
||||||
image, an iso or any other large file, you may want to stream the response
|
image, an iso, or any other large file, you may want to stream the response
|
||||||
directly to disk rather than loading it in memory. If you have a very large
|
directly to disk rather than loading it in memory. If you have a very large
|
||||||
file, it may become *impossible* to load it into memory.
|
file, it may become *impossible* to load it into memory.
|
||||||
|
|
||||||
If you want to stream the data from the `GET` to a file as it comes, rather
|
There are two main ways to do this:
|
||||||
than entirely in memory, you must pass `RestClient::Request.execute` a
|
|
||||||
parameter `block_response` to which you pass a `block` that streams the
|
#### `raw_response`, saves into Tempfile
|
||||||
request. That block, in turn, will receive the response and the ability to
|
|
||||||
stream directly to file as each chunk comes across.
|
If you pass `raw_response: true` to `RestClient::Request.execute`, it will save
|
||||||
|
the response body to a temporary file (using `Tempfile`) and return a
|
||||||
|
`RestClient::RawResponse` object rather than a `RestClient::Response`.
|
||||||
|
|
||||||
|
Note that the tempfile created by `Tempfile.new` will be in `Dir.tmpdir`
|
||||||
|
(usually `/tmp/`), which you can override to store temporary files in a
|
||||||
|
different location. This file will be unlinked when it is dereferenced.
|
||||||
|
|
||||||
|
If logging is enabled, this will also print download progress.
|
||||||
|
__New in 2.1:__ Customize the interval with `:stream_log_percent` (defaults to
|
||||||
|
10 for printing a message every 10% complete).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
>> raw = RestClient::Request.execute(
|
||||||
|
method: :get,
|
||||||
|
url: 'http://releases.ubuntu.com/16.04.2/ubuntu-16.04.2-desktop-amd64.iso',
|
||||||
|
raw_response: true)
|
||||||
|
=> <RestClient::RawResponse @code=200, @file=#<Tempfile:/tmp/rest-client.20170522-5346-1pptjm1>, @request=<RestClient::Request @method="get", @url="http://releases.ubuntu.com/16.04.2/ubuntu-16.04.2-desktop-amd64.iso">>
|
||||||
|
>> raw.file.size
|
||||||
|
=> 1554186240
|
||||||
|
>> raw.file.path
|
||||||
|
=> "/tmp/rest-client.20170522-5346-1pptjm1"
|
||||||
|
raw.file.path
|
||||||
|
=> "/tmp/rest-client.20170522-5346-1pptjm1"
|
||||||
|
|
||||||
|
>> require 'digest/sha1'
|
||||||
|
>> Digest::SHA1.file(raw.file.path).hexdigest
|
||||||
|
=> "4375b73e3a1aa305a36320ffd7484682922262b3"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `block_response`, receives raw Net::HTTPResponse
|
||||||
|
|
||||||
|
If you want to stream the data from the response to a file as it comes, rather
|
||||||
|
than entirely in memory, you can also pass `RestClient::Request.execute` a
|
||||||
|
parameter `:block_response` to which you pass a block/proc. This block receives
|
||||||
|
the raw unmodified Net::HTTPResponse object from Net::HTTP, which you can use
|
||||||
|
to stream directly to a file as each chunk is received.
|
||||||
|
|
||||||
|
Note that this bypasses all the usual HTTP status code handling, so you will
|
||||||
|
want to do you own checking for HTTP 20x response codes, redirects, etc.
|
||||||
|
|
||||||
The following is an example:
|
The following is an example:
|
||||||
|
|
||||||
````ruby
|
````ruby
|
||||||
File.open('/some/output/file', 'w') {|f|
|
File.open('/some/output/file', 'w') {|f|
|
||||||
block = proc { |response|
|
block = proc { |response|
|
||||||
response.read_body do |chunk|
|
response.read_body do |chunk|
|
||||||
f.write chunk
|
f.write chunk
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
RestClient::Request.new(method: :get, url: 'http://somedomain.com/some/really/big/file.img', block_response: block).execute
|
RestClient::Request.execute(method: :get,
|
||||||
|
url: 'http://example.com/some/really/big/file.img',
|
||||||
|
block_response: block)
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,9 @@ module RestClient
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO (breaks compatibility): ought to use mime_for() to autodetect the
|
||||||
|
# Content-Type for stream objects that have a filename.
|
||||||
|
|
||||||
alias :length :size
|
alias :length :size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue