Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Faraday HTTP Cache (or just using Faraday middleware) #51

Closed
jagregory opened this issue Dec 16, 2013 · 7 comments
Closed

Using Faraday HTTP Cache (or just using Faraday middleware) #51

jagregory opened this issue Dec 16, 2013 · 7 comments

Comments

@jagregory
Copy link

I'm trying to use faraday-http-cache with Hyperclient, but it isn't proving easy.

faraday-http-cache expects to sit before :net_http in the middleware stack. A working example from their docs looks like this:

client = Faraday.new('https://api.github.com') do |stack|
  stack.response :json, content_type: /\bjson$/
  stack.use :http_cache, logger: ActiveSupport::Logger.new(STDOUT)
  stack.adapter Faraday.default_adapter
end

# which has this middleware:
[FaradayMiddleware::ParseJson, Faraday::HttpCache, Faraday::Adapter::NetHttp]

However, trying to achieve the same thing in Hyperclient doesn't work as expected. The following setup, which I would expect to work, results in duplicate :net_http in the middleware.

client = Hyperclient.new('https://api.github.com')
client.connection.use :http_cache, logger: ActiveSupport::Logger.new(STDOUT)
client.connection.adapter Faraday.default_adapter

# which has this middleware (see the duplicate NetHttp):
[FaradayMiddleware::EncodeJson, FaradayMiddleware::ParseJson, Faraday::Adapter::NetHttp, Faraday::HttpCache, Faraday::Adapter::NetHttp]

This is because of the way Hyperclient initialises the Faraday connection (see default_faraday_block) with the :net_http adapter when it creates the connection.

The only way I've got this working was by monkey patching or subclassing EntryPoint and overriding the default_faraday_block so the :http_cache middleware is inserted before :net_http.

class Hyperclient::EntryPoint
  def default_faraday_block
    lambda do |faraday|
      faraday.request  :json
      faraday.response :json, content_type: /\bjson$/
      faraday.use :http_cache, logger: ActiveSupport::Logger.new(STDOUT)
      faraday.adapter :net_http
    end
  end
end

Advice? This is less than ideal.

@oriolgual
Copy link
Member

I'm not sure if it will work, but what happens if you use insert_after or 'insert_before ?

client = Hyperclient.new('https://api.github.com')
client.connection.insert_after :json, :http_cache, logger: ActiveSupport::Logger.new(STDOUT)

Or

client = Hyperclient.new('https://api.github.com')
client.connection.insert_before Faraday::Adapter::NetHttp, :http_cache, logger: ActiveSupport::Logger.new(STDOUT)

@jagregory
Copy link
Author

Thanks, insert_before seems to do the trick, except it has to be called on client.connection.builder.

This still seems less obvious than it should be. Should a better programmatic solution exist, or should this use case be documented in the readme?

I'm thinking we could modify EntryPoint to take a block in the constructor, and call that when initialising faraday. Something like:

class EntryPoint < Link
  def initialize(url, &block)
    @link = {'href' => url}
    @entry_point = self
    @faraday_block = block
  end

  def default_faraday_block
    lambda do |faraday|
      faraday.request  :json
      faraday.response :json, content_type: /\bjson$/
      @faraday_block.call(faraday) if @faraday_block
      faraday.adapter :net_http
    end
  end
end

Which would let you use faraday.use before the adapter has been set. e.g.

Hyperclient.new('url') do |faraday|
  faraday.use :http_cache
end

Alternatively, the constructor block could just replace default_faraday_block entirely when present.

Thoughts?

@oriolgual
Copy link
Member

I agree that there should be a better way to do this. Initializing Hyperclient with a faraday block seems like the best option, or maybe we could do it as an accessor:

client = Hyperclient.new('https://api.github.com')
client.faraday_block = lambda do |faraday|
  faraday.use :http_cache
end

In any case, if you provide a block I would ignore the default block, it feels more natural.

@jagregory
Copy link
Author

The only downside I can think of with ignoring the block, is anyone who provides their own block will have to also specify the defaults that Hyperclient expects (as in, the request and response :json options). Is that acceptable?

Either way, I'll put together a pull request with these changes in.

@oriolgual
Copy link
Member

What if we keep the default block, but provide a way to add middlewares and adapter? Like:

client = Hyperclient.new('https://api.github.com')
client.faraday_middlewares << :http_cache
clent.adapter = MyCustomAdapter

And then the deafult_faraday_block uses this values to initialize Faraday.

@dblock
Copy link
Collaborator

dblock commented Sep 30, 2014

Maybe just letting one assign a connection?

client = Hyperclient.new
client.connection = Faraday.new 'https://api.github.com', headers: ... do |f|
   f.use ....
end

Looking forward to a PR.

@dblock
Copy link
Collaborator

dblock commented Oct 16, 2014

Custom Faraday blocks are now fully supported via #75.

Hyperclient.new('https://api.github.com') do |client|
  client.connection(default: false) do |conn|
     conn.request  :json
     conn.response :json, content_type: /\bjson$/
     conn.use :http_cache
     conn.adapter :net_http    
     # etc.
  end
end

@dblock dblock closed this as completed Oct 16, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants