Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Faraday Http Cache

Gem Version Build

A Faraday middleware that respects HTTP cache, by checking expiration and validation of the stored responses.


Add it to your Gemfile:

gem 'faraday-http-cache'

Usage and configuration

You have to use the middleware in the Faraday instance that you want to, along with a suitable store to cache the responses. You can use the new shortcut using a symbol or passing the middleware class

client = do |builder|
  builder.use :http_cache, store: Rails.cache
  # or
  builder.use Faraday::HttpCache, store: Rails.cache

  builder.adapter Faraday.default_adapter

The middleware accepts a store option for the cache backend responsible for recording the API responses that should be stored. Stores should respond to write, read and delete, just like an object from the ActiveSupport::Cache API.

# Connect the middleware to a Memcache instance.
store = ActiveSupport::Cache.lookup_store(:mem_cache_store, ['localhost:11211'])

client = do |builder|
  builder.use :http_cache, store: store
  builder.adapter Faraday.default_adapter

# Or use the Rails.cache instance inside your Rails app.
client = do |builder|
  builder.use :http_cache, store: Rails.cache
  builder.adapter Faraday.default_adapter

The default store provided is a simple in memory cache that lives on the client instance. This type of store might not be persisted across multiple processes or connection instances so it is probably not suitable for most production environments. Make sure that you configure a store that is suitable for you.

The stdlib JSON module is used for serialization by default, which can struggle with unicode characters in responses in Ruby < 3.1. For example, if your JSON returns "name": "Raül" then you might see errors like:

Response could not be serialized: "\xC3" from ASCII-8BIT to UTF-8. Try using Marshal to serialize.

For full unicode support, or if you expect to be dealing with images, you can use the stdlib Marshal instead. Alternatively you could use another json library like oj or yajl-ruby.

client = do |builder|
  builder.use :http_cache, store: Rails.cache, serializer: Marshal
  builder.adapter Faraday.default_adapter


You can provide a :strategy option to the middleware to specify the strategy to use.

client = do |builder|
  builder.use :http_cache, store: Rails.cache, strategy: Faraday::HttpCache::Strategies::ByVary
  builder.adapter Faraday.default_adapter

Available strategies are:


The default strategy. It Uses URL + HTTP method to generate cache keys and stores an array of request + response for each key.


This strategy uses headers from Vary header to generate cache keys. It also uses cache to store Vary headers mapped to the request URL. This strategy is more suitable for caching private responses with the same URLs but different results for different users, like

Note: To automatically remove stale cache keys, you might want to use the :expires_in option.

store = ActiveSupport::Cache.lookup_store(:redis_cache_store, expires_in:, url: 'redis://localhost:6379/0')
client = do |builder|
  builder.use :http_cache, store: store, strategy: Faraday::HttpCache::Strategies::ByVary
  builder.adapter Faraday.default_adapter

Custom strategies

You can write your own strategy by subclassing Faraday::HttpCache::Strategies::BaseStrategy and implementing #write, #read and #delete methods.


You can provide a :logger option that will receive debug information based on the middleware operations:

client = do |builder|
  builder.use :http_cache, store: Rails.cache, logger: Rails.logger
  builder.adapter Faraday.default_adapter

# logs "HTTP Cache: [GET users] miss, store"


In addition to logging you can instrument the middleware by passing in an :instrumenter option such as ActiveSupport::Notifications (compatible objects are also allowed).

The event http_cache.faraday will be published every time the middleware processes a request. In the event payload, :env contains the response Faraday env and :cache_status contains a Symbol indicating the status of the cache processing for that request:

  • :unacceptable means that the request did not go through the cache at all.
  • :miss means that no cached response could be found.
  • :invalid means that the cached response could not be validated against the server.
  • :valid means that the cached response could be validated against the server.
  • :fresh means that the cached response was still fresh and could be returned without even calling the server.
client = do |builder|
  builder.use :http_cache, store: Rails.cache, instrumenter: ActiveSupport::Notifications
  builder.adapter Faraday.default_adapter

# Subscribes to all events from Faraday::HttpCache.
ActiveSupport::Notifications.subscribe "http_cache.faraday" do |*args|
  event =*args)
  cache_status = event.payload[:cache_status]
  statsd =

  case cache_status
  when :fresh, :valid
  when :invalid, :miss
  when :unacceptable

See it live

You can clone this repository, install its dependencies with Bundler (run bundle install) and execute the files under the examples directory to see a sample of the middleware usage.

What gets cached?

The middleware will use the following headers to make caching decisions:

  • Vary
  • Cache-Control
  • Age
  • Last-Modified
  • ETag
  • Expires


The max-age, must-revalidate, proxy-revalidate and s-maxage directives are checked.

Shared vs. non-shared caches

By default, the middleware acts as a "shared cache" per RFC 2616. This means it does not cache responses with Cache-Control: private. This behavior can be changed by passing in the :shared_cache configuration option:

client = do |builder|
  builder.use :http_cache, shared_cache: false
  builder.adapter Faraday.default_adapter

client.get('https://site/api/some-private-resource') # => will be cached


Copyright (c) 2012-2018 Plataformatec. Copyright (c) 2019 SourceLevel and contributors.