Response Handling

The response object (if you’re in the documentation, look for HTTPX::Response) is the result after you perform the request.

The core implementation supports a minimal number of methods. The most importants are:

(You can find the rest in HTTPX::Response documentation.

#status (Integer)

returns an HTTP status code, which is an integer ranging from 100 to 599.

#headers (HTTPX::Headers)

returns a headers object. It has a minimal API to allow Hash-like lookups, and it can also be turned into an Hash or an array (via #to_h or #to_a).

It supports case-insensitive header lookup:

response.headers["content-type"]
# same as
response.headers["Content-Type"]

#body (HTTPX::Response::Body)

The response body is where the HTTP response payload is.

It can be fully buffered into a string:

response.body.to_s #=> "<!DOCTYPE html> ...."

However, it’s advisable that you treat it like a file, or a buffer, or even an enumerable, given that reading an HTTP response into memory might end up draining your resources.

# as a reader
while chunk = response.body.read(16_384)

end

# using IO.copy_stream
IO.copy_stream(response.body, destination_file_or_path)

# or, using the more efficient operation:

response.body.copy_to(destination_file_or_path)

# as an enumerable
response.body.each do |chunk|
  # do something with the chunk
end

Notes

  • although this is done automatically when you “drain” a response, it’s always advised that you call #close when you’re done with it.
  • The response will handle decode content transparently, i.e. HTTP/1.1 chunked encoding is handled automatically, as well as other known content encodings such as gzip or deflate (more about it in here).

response decoding

HTTPX::Response will also allow decoding of the body into ruby objects, as long as it understands the given mime type. The following methods are provided:

  • HTTPX::Response#json: returns the decoded JSON payload in a ruby Hash or Array.
  • HTTPX::Response#form: returns the decoded x-www-urlencoded or multipart/form-data payload in a ruby Hash or Array.

Here’s the gist of it:

require "httpx"
response = HTTPX.get("https://nghttp2.org/httpbin/get")
#=> #<Response:3280 HTTP/2.0 @status=200 @headers={"date"=>["Tue, 10 Aug 2021 10:41:27 GMT"], "content-type"=>["application/json"], "content-length"=>["199"], "access-control-allow-origin"=>["*"], "access-control-allow-credentials"=>["true"], "x-backend-header-rtt"=>["0.003102"], "strict-transport-security"=>["max-age=31536000"], "server"=>["nghttpx"], "via"=>["1.1 nghttpx"], "alt-svc"=>["h3-29=\":443\"; ma=3600"], "x-frame-options"=>["SAMEORIGIN"], "x-xss-protection"=>["1; mode=block"], "x-content-type-options"=>["nosniff"]} @body=199>
response.json
#=> {"args"=>{}, "headers"=>{"Accept"=>"*/*", "Host"=>"nghttp2.org", "User-Agent"=>"httpx.rb/0.16.1"}, "origin"=>"144.64.139.19", "url"=>"https://nghttp2.org/httpbin/get"}

pattern matching

Pattern matching can be used to match information about responses.

This is how you’d pattern match on error status codes:

case response
in {status: 400.., body: body}
  puts body.to_s
# ...
end

This is how you could parse json responses only:

body = case response
in {headers: [*, %w[content-type application/json], *], body: body}
  JSON.parse(body.to_s)
# ...
end

You could also use array patterns for pattern match:

body = case response
in [200, [*, %w[content-type application/json], *], body]
  JSON.parse(body.to_s)
  # ...
end

You can also pattern match against error reponses

Next: Plugins