## File: README.md

# [][website]

[](https://rubygems.org/gems/faraday)
[](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
[](https://github.com/lostisland/faraday/discussions)

Faraday is an HTTP client library abstraction layer that provides a common interface over many
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
Take a look at [Awesome Faraday][awesome] for a list of available adapters and middleware.

## Why use Faraday?

Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses,
making it easier to build sophisticated API clients or web service libraries that abstract away
the details of how HTTP requests are made.

Faraday comes with a lot of features out of the box, such as:
* Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
* Persistent connections (keep-alive)
* Parallel requests
* Automatic response parsing (JSON, XML, YAML)
* Customization of the request/response cycle with middleware
* Support for streaming responses
* Support for uploading files
* And much more!

## Getting Started

The best starting point is the [Faraday Website][website], with its introduction and explanation.

Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally, or take a look at [Advanced techniques for calling HTTP APIs in Ruby](https://mattbrictson.com/blog/advanced-http-techniques-in-ruby) blog post from [@mattbrictson](https://github.com/mattbrictson) 🚀

## Supported Ruby versions

This library aims to support and is [tested against][actions] the currently officially supported Ruby
implementations. This means that, even without a major release, we could add or drop support for Ruby versions,
following their [EOL](https://endoflife.date/ruby).
Currently that means we support Ruby 3.0+

If something doesn't work on one of these Ruby versions, it's a bug.

This library may inadvertently work (or seem to work) on other Ruby
implementations and versions, however support will only be provided for the versions listed
above.

If you would like this library to support another Ruby version, you may
volunteer to be a maintainer. Being a maintainer entails making sure all tests
run and pass on that implementation. When something breaks on your
implementation, you will be responsible for providing patches in a timely
fashion. If critical issues for a particular implementation exist at the time
of a major release, support for that Ruby version may be dropped.

## Contribute

Do you want to contribute to Faraday?
Open the issues page and check for the `help wanted` label!
But before you start coding, please read our [Contributing Guide][contributing]

## Copyright

&copy; 2009 - 2026, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).

[awesome]: https://github.com/lostisland/awesome-faraday/#adapters
[website]: https://lostisland.github.io/faraday
[contributing]: https://github.com/lostisland/faraday/blob/main/.github/CONTRIBUTING.md
[apidoc]: https://www.rubydoc.info/github/lostisland/faraday
[actions]: https://github.com/lostisland/faraday/actions

---

## File: docs/adapters/custom/index.md

# Writing custom adapters

!> A template for writing your own custom adapter is available in the [faraday-adapter-template](https://github.com/lostisland/faraday-adapter-template) repository.

Adapters have methods that can help you implement support for a new backend.

This example will use a fictional HTTP backend gem called `FlorpHttp`. It doesn't
exist. Its only function is to make this example more concrete.

## An Adapter _is_ a Middleware

When you subclass `Faraday::Adapter`, you get helpful methods defined and all you need to do is to
extend the `call` method (remember to call `super` inside it!):

```ruby
module Faraday
  class Adapter
    class FlorpHttp < Faraday::Adapter
      def call(env)
        super
        # Perform the request and call `save_response`
      end
    end
  end
end
```

Now, there are only two things which are actually mandatory for an adapter middleware to function:

- a `#call` implementation
- a call to `#save_response` inside `#call`, which will keep the Response around.

These are the only two things, the rest of this text is about methods which make the authoring easier.

Like any other middleware, the `env` parameter passed to `#call` is an instance of [Faraday::Env][env-object].
This object will contain all the information about the request, as well as the configuration of the connection.
Your adapter is expected to deal with SSL and Proxy settings, as well as any other configuration options.

## Connection options and configuration block

Users of your adapter have two main ways of configuring it:
* connection options: these can be passed to your adapter initializer and are automatically stored into an instance variable `@connection_options`.
* configuration block: this can also be provided to your adapter initializer and it's stored into an instance variable `@config_block`.

Both of these are automatically managed by `Faraday::Adapter#initialize`, so remember to call it with `super` if you create an `initialize` method in your adapter.
You can then use them in your adapter code as you wish, since they're pretty flexible.

Below is an example of how they can be used:

```ruby
# You can use @connection_options and @config_block in your adapter code
class FlorpHttp < Faraday::Adapter
  def call(env)
    # `connection` internally calls `build_connection` and yields the result
    connection do |conn|
      # perform the request using configured `conn`
    end
  end

  def build_connection(env)
    conn = FlorpHttp::Client.new(pool_size: @connection_options[:pool_size] || 10)
    @config_block&.call(conn)
    conn
  end
end

# Then your users can provide them when initializing the connection
Faraday.new(...) do |f|
  # ...
  # in this example, { pool_size: 5 } will be provided as `connection_options`
  f.adapter :florp_http, pool_size: 5 do |client|
    # this block is useful to set properties unique to HTTP clients that are not
    # manageable through the Faraday API
    client.some_fancy_florp_http_property = 10
  end
end
```

## Implementing `#close`

Just like middleware, adapters can implement a `#close` method. It will be called when the connection is closed.
In this method, you should close any resources that you opened in `#initialize` or `#call`, like sockets or files.

```ruby
class FlorpHttp < Faraday::Adapter
  def close
    @socket.close if @socket
  end
end
```

## Helper methods

`Faraday::Adapter` provides some helper methods to make it easier to implement adapters.

### `#save_response`

The most important helper method and the only one you're expected to call from your `#call` method.
This method is responsible for, among other things, the following:
* Take the `env` object and save the response into it.
* Set the `:response` key in the `env` object.
* Parse headers using `Utils::Headers` and set the `:response_headers` key in the `env` object.
* Call `#finish` on the `Response` object, triggering the `#on_complete` callbacks in the middleware stack.

```ruby
class FlorpHttp < Faraday::Adapter
  def call(env)
    super
    # Perform the request using FlorpHttp.
    # Returns a FlorpHttp::Response object.
    response = FlorpHttp.perform_request(...)

    save_response(env, response.status, response.body, response.headers, response.reason_phrase)
  end
end
```

`#save_response` also accepts a `finished` keyword argument, which defaults to `true`, but that you can set to false
if you don't want it to call `#finish` on the `Response` object.

### `#request_timeout`

Most HTTP libraries support different types of timeouts, like `:open_timeout`, `:read_timeout` and `:write_timeout`.
Faraday let you set individual values for each of these, as well as a more generic `:timeout` value on the request options.

This helper method knows about supported timeout types, and falls back to `:timeout` if they are not set.
You can use those when building the options you need for your backend's instantiation.

```ruby
class FlorpHttp < Faraday::Adapter
  def call(env)
    super
    # Perform the request using FlorpHttp.
    # Returns a FlorpHttp::Response object.
    response = FlorpHttp.perform_request(
      # ... other options ...,
      open_timeout: request_timeout(:open, env[:request]),
      read_timeout: request_timeout(:read, env[:request]),
      write_timeout: request_timeout(:write, env[:request])
    )

    # Call save_response
  end
end
```

## Register your adapter

Like middleware, you may register a nickname for your adapter.
People can then refer to your adapter with that name when initializing their connection.
You do that using `Faraday::Adapter.register_middleware`, like this:

```ruby
class FlorpHttp < Faraday::Adapter
  # ...
end

Faraday::Adapter.register_middleware(florp_http: FlorpHttp)
```

[env-object]: /getting-started/env-object.md

---

## File: docs/adapters/custom/parallel-requests.md

# Adding support for parallel requests

!> This is slightly more involved, and this section is not fully formed.

Vague example, excerpted from [the test suite about parallel requests](https://github.com/lostisland/faraday/blob/main/spec/support/shared_examples/request_method.rb#L179)

```ruby
response_1 = nil
response_2 = nil

conn.in_parallel do
  response_1 = conn.get('/about')
  response_2 = conn.get('/products')
end

puts response_1.status
puts response_2.status
```

First, in your class definition, you can tell Faraday that your backend supports parallel operation:

```ruby
class FlorpHttp < ::Faraday::Adapter
  dependency do
    require 'florp_http'
  end

  self.supports_parallel = true
end
```

Then, implement a method which returns a ParallelManager:

```ruby
class FlorpHttp < ::Faraday::Adapter
  dependency do
    require 'florp_http'
  end

  self.supports_parallel = true

  def self.setup_parallel_manager(_options = nil)
    FlorpParallelManager.new # NB: we will need to define this
  end

  def call(env)
    # NB: you can call `in_parallel?` here to check if the current request
    # is part of a parallel batch. Useful if you need to collect all requests
    # into the ParallelManager before running them.
  end
end

class FlorpParallelManager
  # The execute method will be passed the same block as `in_parallel`,
  # so you can either collect the requests or just wrap them into a wrapper,
  # depending on how your adapter works.
  def execute(&block)
    run_async(&block)
  end
end
```

### A note on the old, deprecated interface

Prior to the introduction of the `execute` method, the `ParallelManager` was expected to implement a `run` method
and the execution of the block was done by the Faraday connection BEFORE calling that method.

This approach made the `ParallelManager` implementation harder and forced you to keep state around.
The new `execute` implementation allows to avoid this shortfall and support different flows.

As of Faraday 2.0, `run` is still supported in case `execute` is not implemented by the `ParallelManager`,
but this method should be considered deprecated.

For reference, please see an example using `run` from [em-synchrony](https://github.com/lostisland/faraday-em_synchrony/blob/main/lib/faraday/adapter/em_synchrony.rb)
and its [ParallelManager implementation](https://github.com/lostisland/faraday-em_synchrony/blob/main/lib/faraday/adapter/em_synchrony/parallel_manager.rb).

---

## File: docs/adapters/custom/streaming.md

# Adding support for streaming

Faraday supports streaming responses, which means that the response body is not loaded into memory all at once,
but instead it is read in chunks. This can be particularly useful when dealing with large responses.
Not all HTTP clients support this, so it is not required for adapters to support it.

However, if you do want to support it in your adapter, you can do so by leveraging helpers provided by the env object.
Let's see an example implementation first with some comments, and then we'll explain it in more detail:

```ruby
module Faraday
  class Adapter
    class FlorpHttp < Faraday::Adapter
      def call(env)
        super
        if env.stream_response? # check if the user wants to stream the response
          # start a streaming response.
          # on_data is a block that will let users consume the response body
          http_response = env.stream_response do |&on_data|
            # perform the request using FlorpHttp
            # the block will be called for each chunk of data
            FlorpHttp.perform_request(...) do |chunk|
              on_data.call(chunk)
            end
          end
          # the body is already consumed by the block
          # so it's good practice to set it to nil
          http_response.body = nil
        else
          # perform the request normally, no streaming.
          http_response = FlorpHttp.perform_request(...)
        end
        save_response(env, http_response.status, http_response.body, http_response.headers, http_response.reason_phrase)
      end
    end
  end
end
```

## How it works

### `#stream_response?`

The first helper method we use is `#stream_response?`. This method is provided by the env object and it returns true
if the user wants to stream the response. This is controlled by the presence of an `on_data` callback in the request options.

### `#stream_response`

The second helper is `#stream_response`. This method is also provided by the env object and it takes a block.
The block will be called with a single argument, which is a callback that the user can use to consume the response body.
All your adapter needs to do, is to call this callback with each chunk of data that you receive from the server.

The `on_data` callback will internally call the callback provided by the user, so you don't need to worry about that.
It will also keep track of the number of bytes that have been read, and pass that information to the user's callback.

To see how this all works together, let's see an example of how a user would use this feature:

```ruby
# A buffer to store the streamed data
streamed = []

conn = Faraday.new('http://httpbingo.org')
conn.get('/stream/100') do |req|
  # Set a callback which will receive tuples of chunk Strings,
  # the sum of characters received so far, and the response environment.
  # The latter will allow access to the response status, headers and reason, as well as the request info.
  req.options.on_data = proc do |chunk, overall_received_bytes, env|
    puts "Received #{overall_received_bytes} characters"
    streamed << chunk
  end
end

# Joins all response chunks together
streamed.join
```

For more details on the user experience, check the [Streaming Responses] page.

[Streaming Responses]: /advanced/streaming-responses.md

---

## File: docs/adapters/custom/testing.md

# Test your custom adapter

Faraday puts a lot of expectations on adapters, but it also provides you with useful tools to test your adapter
against those expectations. This guide will walk you through the process of testing your adapter.

## The adapter test suite

Faraday provides a test suite that you can use to test your adapter.
The test suite is located in the `spec/external_adapters/faraday_specs_setup.rb`.

All you need to do is to `require 'faraday_specs_setup'` in your adapter's `spec_helper.rb` file.
This will load the `an adapter` shared example group that you can use to test your adapter.

```ruby
require 'faraday_specs_setup'

RSpec.describe Faraday::Adapter::FlorpHttp do
  it_behaves_like 'an adapter'

  # You can then add any other test specific to this adapter here...
end
```

## Testing optional features

By default, `an adapter` will test your adapter against the required behaviour for an adapter.
However, there are some optional "features" that your adapter can implement, like parallel requests or streaming.

If your adapter implements any of those optional features, you can test it against those extra expectations
by calling the `features` method:

```ruby
RSpec.describe Faraday::Adapter::MyAdapter do
  # Since not all adapters support all the features Faraday has to offer, you can use
  # the `features` method to turn on only the ones you know you can support.
  features :request_body_on_query_methods,
           :compression,
           :streaming

  # Runs the tests provide by Faraday, according to the features specified above.
  it_behaves_like 'an adapter'

  # You can then add any other test specific to this adapter here...
end
```

### Available features

| Feature                          | Description                                                                                              |
|----------------------------------|----------------------------------------------------------------------------------------------------------|
| `:compression`                   | Tests that your adapter can handle `gzip` and `deflate` compressions.                                    |
| `:local_socket_binding`          | Tests that your adapter supports binding to a local socket via the `:bind` request option.               |
| `:parallel`                      | Tests that your adapter supports parallel requests. See [Parallel requests][parallel] for more details.  |
| `:reason_phrase_parse`           | Tests that your adapter supports parsing the `reason_phrase` from the response.                          |
| `:request_body_on_query_methods` | Tests that your adapter supports sending a request body on `GET`, `HEAD`, `DELETE` and `TRACE` requests. |
| `:streaming`                     | Tests that your adapter supports streaming responses. See [Streaming][streaming] for more details.       |
| `:trace_method`                  | Tests your adapter against the `TRACE` HTTP method.                                                      |

[streaming]: /adapters/custom/streaming.md
[parallel]: /adapters/custom/parallel-requests.md

---

## File: docs/adapters/index.md

# Adapters

The Faraday Adapter interface determines how a Faraday request is turned into
a Faraday response object. Adapters are typically implemented with common Ruby
HTTP clients, but can have custom implementations. Adapters can be configured
either globally or per Faraday Connection through the configuration block.

For example, consider using `httpclient` as an adapter. Note that [faraday-httpclient](https://github.com/lostisland/faraday-httpclient) must be installed beforehand.

If you want to configure it globally, do the following:

```ruby
require 'faraday'
require 'faraday/httpclient'

Faraday.default_adapter = :httpclient
```

If you want to configure it per Faraday Connection, do the following:

```ruby
require 'faraday'
require 'faraday/httpclient'

conn = Faraday.new do |f|
  f.adapter :httpclient
end
```

## Fantastic adapters and where to find them

Except for the default [Net::HTTP][net_http] adapter and the [Test Adapter][testing] adapter, which is for _test purposes only_,
adapters are distributed separately from Faraday and need to be manually installed.
They are usually available as gems, or bundled with HTTP clients.

While most adapters use a common Ruby HTTP client library, adapters can also
have completely custom implementations.

If you're just getting started you can find a list of featured adapters in [Awesome Faraday][awesome].
Anyone can create a Faraday adapter and distribute it. If you're interested learning more, check how to [build your own][build_adapters]!


[testing]:        /adapters/test-adapter.md
[net_http]:       /adapters/net-http.md
[awesome]:        https://github.com/lostisland/awesome-faraday/#adapters
[build_adapters]: /adapters/custom/index.md

---

## File: docs/adapters/net-http.md

# Net::HTTP Adapter

Faraday's Net::HTTP adapter is the default adapter. It uses the `Net::HTTP`
library that ships with Ruby's standard library.
Unless you have a specific reason to use a different adapter, this is probably
the adapter you want to use.

With the release of Faraday 2.0, the Net::HTTP adapter has been moved into a [separate gem][faraday-net_http],
but it has also been added as a dependency of Faraday.
That means you can use it without having to install it or require it explicitly.

[faraday-net_http]: https://github.com/lostisland/faraday-net_http

---

## File: docs/adapters/test-adapter.md

# Test Adapter

The built-in Faraday Test adapter lets you define stubbed HTTP requests. This can
be used to mock out network services in an application's unit tests.

The easiest way to do this is to create the stubbed requests when initializing
a `Faraday::Connection`. Stubbing a request by path yields a block with a
`Faraday::Env` object. The stub block expects an Array return value with three
values: an Integer HTTP status code, a Hash of key/value headers, and a
response body.

```ruby
conn = Faraday.new do |builder|
  builder.adapter :test do |stub|
    # block returns an array with 3 items:
    # - Integer response status
    # - Hash HTTP headers
    # - String response body
    stub.get('/ebi') do |env|
      [
        200,
        { 'Content-Type': 'text/plain', },
        'shrimp'
      ]
    end

    # test exceptions too
    stub.get('/boom') do
      raise Faraday::ConnectionFailed
    end
  end
end
```

You can define the stubbed requests outside of the test adapter block:

```ruby
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
  stub.get('/tamago') { |env| [200, {}, 'egg'] }
end
```

This Stubs instance can be passed to a new Connection:

```ruby
conn = Faraday.new do |builder|
  builder.adapter :test, stubs do |stub|
    stub.get('/ebi') { |env| [ 200, {}, 'shrimp' ]}
  end
end
```

It's also possible to stub additional requests after the connection has been
initialized. This is useful for testing.

```ruby
stubs.get('/uni') { |env| [ 200, {}, 'urchin' ]}
```

You can also stub the request body with a string or a proc.
It would be useful to pass a proc if it's OK only to check the parts of the request body are passed.

```ruby
stubs.post('/kohada', 'where=sea&temperature=24') { |env| [ 200, {}, 'spotted gizzard shad' ]}
stubs.post('/anago', -> (request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'Wakamoto' } }) { |env| [200, {}, 'conger eel'] }
```

If you want to stub requests that exactly match a path, parameters, and headers,
`strict_mode` would be useful.

```ruby
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true) do |stub|
  stub.get('/ikura?nori=true', 'X-Soy-Sauce' => '5ml' ) { |env| [200, {}, 'ikura gunkan maki'] }
end
```

This stub expects the connection will be called like this:

```ruby
conn.get('/ikura', { nori: 'true' }, { 'X-Soy-Sauce' => '5ml' } )
```

If there are other parameters or headers included, the Faraday Test adapter
will raise `Faraday::Test::Stubs::NotFound`. It also raises the error
if the specified parameters (`nori`) or headers (`X-Soy-Sauce`) are omitted.

You can also enable `strict_mode` after initializing the connection.
In this case, all requests, including ones that have been already stubbed,
will be handled in a strict way.

```ruby
stubs.strict_mode = true
```

Finally, you can treat your stubs as mocks by verifying that all of the stubbed
calls were made. NOTE: this feature is still fairly experimental. It will not
verify the order or count of any stub.

```ruby
stubs.verify_stubbed_calls
```

After the test case is completed (possibly in an `after` hook), you should reset
the stubs so each test starts with its own set. When you hold a reference to the
`Stubs` instance, call `clear` to remove every stub, including consumed ones.

```ruby
stubs.clear
```

Alternatively, if you rely on the default connection, you can clear it to prevent
it from being cached between different tests.

```ruby
Faraday.default_connection = nil
```

## Examples

Working [RSpec] and [test/unit] examples for a fictional JSON API client are
available.

[RSpec]: https://github.com/lostisland/faraday/blob/main/examples/client_spec.rb
[test/unit]: https://github.com/lostisland/faraday/blob/main/examples/client_test.rb

---

## File: docs/advanced/parallel-requests.md

# Parallel Requests

Some adapters support running requests in parallel.
This can be achieved using the `#in_parallel` method on the connection object.

```ruby
# Install the Typhoeus adapter with `gem install faraday-typhoeus` first.
require 'faraday/typhoeus'

conn = Faraday.new('http://httpbingo.org') do |faraday|
  faraday.adapter :typhoeus
end

now = Time.now

conn.in_parallel do
  conn.get('/delay/3')
  conn.get('/delay/3')
end

# This should take about 3 seconds, not 6.
puts "Time taken: #{Time.now - now}"
```

## A note on Async

You might have heard about [Async] and its native integration with Ruby 3.0.
The good news is that you can already use Async with Faraday (thanks to the [async-http-faraday] gem)
and this does not require the use of `#in_parallel` to run parallel requests.
Instead, you only need to wrap your Faraday code into an Async block:

```ruby
# Install the Async adapter with `gem install async-http-faraday` first.
require 'async/http/faraday'

conn = Faraday.new('http://httpbingo.org') do |faraday|
  faraday.adapter :async_http
end

now = Time.now

# NOTE: This is not limited to a single connection anymore!
# You can run parallel requests spanning multiple connections.
Async do
  Async { conn.get('/delay/3') }
  Async { conn.get('/delay/3') }
end

# This should take about 3 seconds, not 6.
puts "Time taken: #{Time.now - now}"

```

The big advantage of using Async is that you can now run parallel requests *spanning multiple connections*,
whereas the `#in_parallel` method only works for requests that are made through the same connection.

[Async]: https://github.com/socketry/async
[async-http-faraday]: https://github.com/socketry/async-http-faraday

---

## File: docs/advanced/streaming-responses.md

# Streaming Responses

Sometimes you might need to receive a streaming response.
You can do this with the `on_data` request option.

The `on_data` callback is a receives tuples of chunk Strings, and the total
of received bytes so far.

This example implements such a callback:

```ruby
# A buffer to store the streamed data
streamed = []

conn = Faraday.new('http://httpbingo.org')
conn.get('/stream/100') do |req|
  # Set a callback which will receive tuples of chunk Strings,
  # the sum of characters received so far, and the response environment.
  # The latter will allow access to the response status, headers and reason, as well as the request info.
  req.options.on_data = Proc.new do |chunk, overall_received_bytes, env|
    puts "Received #{overall_received_bytes} characters"
    streamed << chunk
  end
end

# Joins all response chunks together
streamed.join
```

The `on_data` streaming is currently only supported by some adapters.
To see which ones, please refer to [Awesome Faraday][awesome] comparative table or check the adapter documentation.
Moreover, the `env` parameter was only recently added, which means some adapters may only have partial support
(i.e. only `chunk` and `overall_received_bytes` will be passed to your block).

[awesome]:      https://github.com/lostisland/awesome-faraday/#adapters