Faraday

Chapter 1
http_services
The Good
- Easily understood purpose from name
- Set the groundwork for common service consumption
- Strictly controls the form that requests may take
The Bad
- Inflexible
- Strictly controls the form that requests may take
- Significant code bloat
- Redundant methods (read, write, create, delete)
base_client.rb
Chapter 2
Faraday (gem)
The Good
- Very flexible
- Easy to understand interface
- Good community support
- Regular release cycle
- Highly extensible through middleware
The Bad
- Sparsely documented
- Relies heavily on env Hash-like object that can become very cluttered.
Chapter 3
Faraday Middleware
The Concept
Faraday implements a Rack-like structure to allow individuals to define middleware to address specific concerns for their applications. This is where the true power of Faraday lies. By only implementing what you need, you avoid having to pull in code that will never be used or is inappropriate for your use-case.

The Good
- Maintained by the same people as Faraday
- Strong set of general-use middleware
- Reasonable model for new middleware development
The Bad
- Very poor documentation
- Pulling in the FM project is counter to the idea that you only pull in what is absolutely needed.
- A bit of a learning curve, partially due to poor documentation.
- Did I mention the documentation?
FaradayMiddleware (gem)

The Good
This is just one more example of pre-existing middleware that is available. It is also very well documented and tested. Even if we didn't want to use this project directly, it would likely be a strong model for developing our own middleware.
The Bad
One more external dependency.
FaradayConductivity

Take Note:
While it is relatively easy to write custom middleware, we found certain cases where the middleware does something to the request and depends on the response to do something and responds to it. This came up when working on OAuth caching.
def call(env)
attempts = @retries + 1
request_body = env[:body]
reuse = true
begin
env[:body] = request_body
env[:request_headers][AUTH_HEADER] = auth_header(reuse)
response = @app.call(env)
reuse = false if expired_header?(response)
attempts -= 1
end until attempts == 0 || !expired_header?(response)
response
endChapter 4
Potential Implementations
http_services MkII
In this approach, we would keep http_services around and update it to consume Faraday, rather than a specific adapter. Further, we could use it to house common middleware that will be used by all applications and clients. There is also the added benefit of having a common connection housed here. This would still allow individual projects to create custom middleware for their own unique use-cases.

Connection Per Client
This approach is similar to the first but focuses on each client building the Faraday connection on its own. This is good because it gives each client fine control over what the connection and call stack looks like. However, it results in a lot of repeated code between clients, due to largely similar functionality.
def initialize(options)
@connection = Faraday.new options[:base_uri] do |faraday|
faraday.headers = HttpServices::HEADERS.merge(HttpServices.user_agent_header(self.to_s))
faraday.options.timeout = options[:read_timeout] || 6
faraday.options.open_timeout = options[:open_timeout]
faraday.use :abacus_timing, client_name: self.to_s
faraday.request :correlation_header
faraday.request :oauth_cache, options
faraday.request :retry, max: (options[:retries] || 2), interval: 0.05
faraday.response :faraday_logging, client_name: self.to_s
faraday.adapter Faraday.default_adapter
end
endLinks
Faraday
By Ryan Perrin
Faraday
Faraday presentation for the February Ruby Dev Meet-Up
- 732