faraday Documentation

Simple, but flexible HTTP client library, with support for multiple backends.

5,930 stars Ruby Ruby 1 file ยท ~6,849 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy faraday on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name faraday -p 5432:5432 --restart always index.docker.io/faradaysec/faraday:latest
Configured Services & Ports
โš™๏ธ db
image: postgres:12.7-alpine
๐Ÿ”Œ Ports: 5432
โš™๏ธ redis
image: redis:8.4-alpine
๐Ÿ”Œ Ports: 6379
โš™๏ธ change-password
image: index.docker.io/faradaysec/faraday:latest
โš™๏ธ faraday-manage
image: index.docker.io/faradaysec/faraday:latest
โš™๏ธ faraday-default-worker
image: index.docker.io/faradaysec/faraday:latest
โš™๏ธ faraday-beat
image: index.docker.io/faradaysec/faraday:latest
โš™๏ธ faraday-server
image: index.docker.io/faradaysec/faraday:latest
๐Ÿ”Œ Ports: 5985:5985
docker-compose.yml
yaml (docker-compose.yml)
x-faraday-image: &faraday-image index.docker.io/faradaysec/faraday:latest  # Use official image from Docker Hub registry or, see below for local development
# x-faraday-image: &faraday-image faraday-local  # For local development, use local image built with `docker-compose build faraday-server`

x-faraday-volumes: &faraday-volumes
  - "faraday:/home/faraday/.faraday:rw"  # by default, store data in a Docker volume.
  # - "$HOME/.faraday:/home/faraday/.faraday:rw"  # Uncomment to use your whole existing `.faraday` folder. Remember to comment the volume above.
  # - "path_to/faraday/cloned/repo:/src"  # Uncomment and adjust path to your local faraday source code directory if you want to use a local development version.

services:
  db:
    image: postgres:12.7-alpine
    restart: always
    container_name: faraday_db
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=faraday
    ports:
      - '5432'
    volumes:
      - "db:/var/lib/postgresql/data:rw"
  redis:
    image: 'redis:8.4-alpine'
    container_name: faraday_redis
    ports:
      - '6379'
  change-password:
    image: *faraday-image
    profiles: ["manual"]
    command: ["faraday-manage", "change-password"]
    volumes: *faraday-volumes
    depends_on:
      - db
  faraday-manage:
    image: *faraday-image
    profiles: [ "manual" ]
    command: [ "faraday-manage" ]
    volumes: *faraday-volumes
    depends_on:
      - db
  faraday-default-worker:
    image: *faraday-image
    restart: always
    container_name: faraday_worker
    command: [ "faraday-worker" ]
    volumes: *faraday-volumes
    environment:
      - PGSQL_USER=postgres
      - PGSQL_PASSWD=postgres
      - PGSQL_HOST=db
      - PGSQL_DBNAME=faraday
      - REDIS_SERVER=redis
    depends_on:
      faraday-server:
        condition: service_healthy
  # Celery Beat scheduler. Run exactly one; do not scale this service.
  faraday-beat:
    image: *faraday-image
    restart: always
    container_name: faraday_beat
    command: [ "faraday-beat" ]
    volumes: *faraday-volumes
    environment:
      - PGSQL_USER=postgres
      - PGSQL_PASSWD=postgres
      - PGSQL_HOST=db
      - PGSQL_DBNAME=faraday
      - REDIS_SERVER=redis
    depends_on:
      faraday-server:
        condition: service_healthy
  faraday-server:
    build:
      context: .
      # args:
      #  - DEV_ENV= 1  # uncomment to use local code source
    image: *faraday-image
    restart: always
    container_name: faraday_server
    entrypoint: "/entrypoint.sh"
    volumes: *faraday-volumes
    environment:
      - PGSQL_USER=postgres
      - PGSQL_PASSWD=postgres
      - PGSQL_HOST=db
      - PGSQL_DBNAME=faraday
      - REDIS_SERVER=redis
    depends_on:
     - db
     - redis
    ports:
     - "5985:5985"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5985/_api/config"]
      interval: 20s
      timeout: 5s
      retries: 10
volumes:
  db:
    driver: local
  faraday:
    driver: local

File: README.md

[][website]



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 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, with its introduction and explanation.

Need more details? See the Faraday API Documentation to see how it works internally, or take a look at Advanced techniques for calling HTTP APIs in Ruby blog post from @mattbrictson ๐Ÿš€

Supported Ruby versions

This library aims to support and is tested against 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.
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

© 2009 - 2026, the Faraday Team. Website and branding design by Elena Lo Piccolo.


File: docs/adapters/custom/index.md

Writing custom adapters

!> A template for writing your own custom adapter is available in the 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.
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)

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

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
and its ParallelManager implementation.


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.


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 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 for more details.
:trace_method Tests your adapter against the TRACE HTTP method.

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 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 adapter and the Test Adapter 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.
Anyone can create a Faraday adapter and distribute it. If you're interested learning more, check how to build your own!


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,
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.


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.


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.


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 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).