Getting started with Faraday gem

Client libraries help in reducing the amount of code for the application developer who is using the API, whether a REST API or any other. By adding a set of code to the application, it provides the basic things an application needs to do in order to interact with the API. This is what a client library does. Also, it may handle user authentication and authorization.

Client libraries are developed by API developer or the community.

There are several HTTP client libraries in Ruby such as:

Among them, the favorite of mine is Faraday gem. Faraday has adapters for popular libraries like Net::HTTP. It is simple, flexible and supports multiple backends and embraces the concept of Rack middleware when processing the request/response cycle. Also, it’s possible to customize its behavior with middleware. We will use a connection object to start with Faraday as it’s more flexible way than a simple getrequest.

conn = Faraday.new
response = conn.get 'http://localhost:3000/tasks'

Using this connection object, we make HTTP requests.

params = {:title => 'Faraday gem', :created_by => 'blog'}
conn.post('http://localhost:3000/tasks',params)

This will POST  title = ‘Faraday gem’  and created by = ‘blog’ to http://localhost:3000/tasks. All HTTP verb methods can take an optional block that will yield aFaraday::Request object.

 conn.post do |req|
   req.url '/tasks'
   req.headers['Content-Type'] = 'application/json'
   req.body = '{"some": "content"}'
 end

Authentication

Basic and Token authentication are handled by Faraday::Request::BasicAuthentication and Faraday::Request::TokenAuthentication respectively. These can be added as middleware manually or through the helper methods.

conn.basic_auth('username', 'password')
conn.token_auth('token')

Proxies

To specify an HTTP proxy:

Faraday.new(:proxy => 'http://proxy.example.com:80')

Using a different HTTP Adapter

Faraday provides an interface between our code and adapter. Sometimes we may want to use features that are not covered in Faraday’s interface. In such cases, we can have access to features specific to any of the adapters supported by Faraday, by passing a block when specifying the adapter to customize it. For example, you can switch to the HTTPClient adapter as below

 conn = Faraday.new do |builder|
   builder.adapter :httpclient do |client| # yields HTTPClient
     client.keep_alive_timeout = 20
   end
 end

Like this, we can switch to any of the supported adapters. The block parameters will change based on the adapters we are using.

Faraday::Connection object middlewares

Faraday::Connection object has a list of middlewares, just like a Rack app. Faraday middlewares are passed as an env hash. It has request and response information.

conn = Faraday.new
conn.builder
=> #<Faraday::RackBuilder:0x0000000155d1f0 @handlers=[Faraday::Request::UrlEncoded,
   #Faraday::Adapter::NetHttp]>

Faraday::Builder is similar to Rack::Builder. A new Faraday::Connectionobject is initialized. It has middlewares Faraday::Request::UrlEncoded in front of an adapter Faraday::Adapter::NetHttp.  Like a Rack application, the adapter at the end of the builder chain is what actually executes the request. Middlewares are grouped into request middlewares, response middlewares, and adapters.

Faraday.new do |builder|
  builder.request :retry
  builder.request :basic_authentication, 'login', 'pass'
  builder.response :logger
  builder.adapter :net_http
end

Advanced Middleware Usage

The order in which middleware is stacked in Faraday is like in Rack. The first middleware on the list wraps all others, while the last middleware is the innermost one, so that’s usually the adapter.

conn = Faraday.new(:url => 'https://redpanthers.co') do |builder|
  # POST/PUT params encoders:
  builder.request :multipart
  builder.request :url_encoded
  builder.adapter :net_http
end

Middlewares stack is manipulated by the Faraday::Builder instance. Each Faraday::Connection instance has a Faraday::Builder instance.

conn = Faraday.new
conn.builder.swap(1, Faraday::Adapter::HTTPClient)
# replace adapter
conn.builder.insert(0, MyCustomMiddleware)
# add middleware to beginning
conn.builder.delete(MyCustomMiddleware)

Writing middleware

Middlewares are classes that respond to call. When middleware is executing, it’s passed as an env hash that has request and response information. Middleware wrap the request/response cycle. The general interface for a middleware is:

class CustomizedMiddleware
  def call(env)
    # do something with the request
    @app.call(env).on_complete do |env|
    # do something with the response
    end
  end
end

All processing of the response should be done in the on-complete block. This enables middleware to work in parallel mode when many requests are occurring at the same time. After the on_complete block, env[:response] is filled in. Faraday::Response instance will be available only after `on_complete`.
faraday-middleware  is a collection of various Faraday middlewares for Faraday-based API wrappers.
For testing middleware, Faraday::Adapter::Test is an HTTP adapter middleware that lets you to fake responses.

References

]]>