Class: Restforce::Middleware::Caching

Inherits:
Faraday::Middleware
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/restforce/middleware/caching.rb

Overview

Public: Caches GET responses and pulls subsequent ones from the cache.

Constant Summary collapse

CACHEABLE_STATUS_CODES =

Internal: List of status codes that can be cached:

  • 200 - ‘OK’

  • 203 - ‘Non-Authoritative Information’

  • 300 - ‘Multiple Choices’

  • 301 - ‘Moved Permanently’

  • 302 - ‘Found’

  • 404 - ‘Not Found’

  • 410 - ‘Gone’

[200, 203, 300, 301, 302, 404, 410].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, cache = nil, options = {}) ⇒ Caching

Public: initialize the middleware.

cache - An object that responds to read and write (default: nil). options - An options Hash (default: {}):

:ignore_params - String name or Array names of query
                         params that should be ignored when forming
                         the cache key (default: []).
:write_options - Hash of settings that should be passed as the
                         third options parameter to the cache's #write
                         method. If not specified, no options parameter
                         will be passed.
:full_key      - Boolean - use full URL as cache key:
                         (url.host + url.request_uri)
:status_codes  - Array of http status code to be cache
                         (default: CACHEABLE_STATUS_CODE)

Yields if no cache is given. The block should return a cache object.



52
53
54
55
56
57
58
59
60
# File 'lib/restforce/middleware/caching.rb', line 52

def initialize(app, cache = nil, options = {})
  super(app)
  if cache.is_a?(Hash) && block_given?
    options = cache
    cache = nil
  end
  @cache = cache || yield
  @options = options
end

Instance Attribute Details

#cacheObject (readonly)

Returns the value of attribute cache.



20
21
22
# File 'lib/restforce/middleware/caching.rb', line 20

def cache
  @cache
end

Instance Method Details

#cache_key(env) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/restforce/middleware/caching.rb', line 86

def cache_key(env)
  url = env[:url].dup
  if url.query && params_to_ignore.any?
    params = parse_query url.query
    params.reject! { |k,| params_to_ignore.include? k }
    url.query = params.any? ? build_query(params) : nil
  end
  url.normalize!
  digest = full_key? ? url.host + url.request_uri : url.request_uri
  Digest::SHA1.hexdigest(digest)
end

#cache_on_complete(env) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/restforce/middleware/caching.rb', line 113

def cache_on_complete(env)
  key = cache_key(env)
  if (cached_response = cache.read(key))
    finalize_response(cached_response, env)
  else
    # response.status is nil at this point
    # any checks need to be done inside on_complete block
    @app.call(env).on_complete do |response_env|
      store_response_in_cache(key, response_env.response)
      response_env
    end
  end
end

#call(env) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/restforce/middleware/caching.rb', line 62

def call(env)
  # Taken from `Restforce::Middleware::Caching` implementation
  # before we switched away from the `faraday_middleware` gem.
  # See https://github.com/restforce/restforce/blob/a08b9d6c5e277bd7111ffa7ed50465dd49c05fab/lib/restforce/middleware/caching.rb.
  cache&.delete(cache_key(env)) unless use_cache?

  if env[:method] == :get
    if env[:parallel_manager]
      # callback mode
      cache_on_complete(env)
    else
      # synchronous mode
      key = cache_key(env)
      unless (response = cache.read(key)) && response
        response = @app.call(env)
        store_response_in_cache(key, response)
      end
      finalize_response(response, env)
    end
  else
    @app.call(env)
  end
end

#custom_status_codesObject



106
107
108
109
110
111
# File 'lib/restforce/middleware/caching.rb', line 106

def custom_status_codes
  @custom_status_codes ||= begin
    codes = CACHEABLE_STATUS_CODES & Array(@options[:status_codes]).map(&:to_i)
    codes.any? ? codes : CACHEABLE_STATUS_CODES
  end
end

#finalize_response(response, env) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/restforce/middleware/caching.rb', line 137

def finalize_response(response, env)
  response = response.dup if response.frozen?
  env[:response] = response
  unless env[:response_headers]
    env.update response.env
    # FIXME: omg hax
    response.instance_variable_set('@env', env)
  end
  response
end

#full_key?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/restforce/middleware/caching.rb', line 102

def full_key?
  @full_key ||= @options[:full_key]
end

#params_to_ignoreObject



98
99
100
# File 'lib/restforce/middleware/caching.rb', line 98

def params_to_ignore
  @params_to_ignore ||= Array(@options[:ignore_params]).map(&:to_s)
end

#store_response_in_cache(key, response) ⇒ Object



127
128
129
130
131
132
133
134
135
# File 'lib/restforce/middleware/caching.rb', line 127

def store_response_in_cache(key, response)
  return unless custom_status_codes.include?(response.status)

  if @options[:write_options]
    cache.write(key, response, @options[:write_options])
  else
    cache.write(key, response)
  end
end

#use_cache?Boolean

Taken from ‘Restforce::Middleware::Caching` implementation before we switched away from the `faraday_middleware` gem. See github.com/restforce/restforce/blob/a08b9d6c5e277bd7111ffa7ed50465dd49c05fab/lib/restforce/middleware/caching.rb.

Returns:

  • (Boolean)


151
152
153
# File 'lib/restforce/middleware/caching.rb', line 151

def use_cache?
  @options[:use_cache]
end