Last Update: 2023-12-05 13:42:13 +0000



GRPC plugin

A new plugin, :grpc, is now available. This plugin provides a simple DSL to build GRPC services and performing calls using httpx under the hood.


require "httpx"

grpc = HTTPX.plugin(:grpc)
helloworld_stub = grpc.build_stub("localhost:4545")
helloworld_svc = helloworld_stub.rpc(:SayHello, HelloRequest, HelloReply)
result = helloworld_svc.say_hello(HelloRequest.new(name: "Jack")) #=> HelloReply: "Hello Jack"

You can read more about the :grpc plugin in the wiki.


A new :origin option is available. You can use it for setting a base URL for subsequent relative paths on that session:

HTTPX.get("/httpbin/get") #=> HTTPX::Error: invalid URI: /httpbin/get

httpbin = HTTPX.with(origin: "https://nghttp2.org")
httpbin.get("/httpbin/get") #=> #<Response:5420 HTTP/2.0 @status=200 ....

Note! The origin is not for setting base paths, i.e. if you pass it a relative path, it’ll be filtered out in subsequent requests (HTTPX.with(origin: "https://nghttp2.org/httpbin") will still use only "https://nghttp2.org").


  • setting an unexpected option will now raise an HTTPX::Error with an helpful message, instead of a confusing NoMethodError:

HTTPX.with(foo: "bar")
# before
#=> NoMethodError
# after
#=> HTTPX::Error: unknown option: foo
  • HTTPX::Options#def_option (which can be used for setting custom plugin options) can now be passed a full body string (where the argument is value), although it still support the block form. This is the recommended approach, as the block form is based on define_method, which would make clients unusable inside ractors.

  • Added support for :wait_for_handshake under the http2_settings option (false by default). HTTP/2 connections complete the protocol handshake before requests are sent. When this option is true, requests get send in the initial payload, before the HTTP/2 connection is fully acknowledged.

  • 441716a5ac0f7707211ebe0048f568cf0b759c3f: The :stream plugin has been improved to start streaming the real response as methods are called (instead of a completely separate synchronous one, which is definitely not good):

session = HTTPX.plugin(:stream)
response = session.get(build_uri("/stream/3"), stream: true)

# before
response.status # this could block indefinitely, if the request truly streams infinitely.

# after
response.status # sends the request, and starts streaming the response until status is available.
response.each {|chunk|...} # and now you can start yielding the chunks...


  • fixed usage of the :multipart if pathname isn’t loaded.

  • fixed HTTP/2 trailers.

  • fixed connection merges with the same origin, which was causing them to be duplicated and breaking further usage. (#125)

  • fixed repeated session callbacks on a connection, by ensure they’re set only once.

  • fixed calculation of content-length for streaming or chunked compressed requests.


  • using ruby base container images in CI instead.

  • using truffleruby official container image.