require 'faraday' module Faraday class EdsMiddleware < Faraday::Middleware INFO_URI = URI.parse('https://eds-api.ebscohost.com/edsapi/rest/Info') AUTH_URI = URI.parse('https://eds-api.ebscohost.com/authservice/rest/uidauth') def initialize(app, *args) super(app) options = args.first || {} @expires_in = options.fetch(:expires_in, 30) @logger = options.fetch(:logger, nil) @namespace = options.fetch(:namespace, 'faraday-eds-cache') @store = options.fetch(:store, :memory_store) @store_options = options.fetch(:store_options, {}) @store_options[:namespace] ||= @namespace initialize_store end def call(env) dup.call!(env) end protected def call!(env) response_env = cached_response(env) if response_env response_env.response_headers['x-faraday-eds-cache'] = 'HIT' to_response(response_env) else @app.call(env).on_complete do |response_env| case response_env.status when 200 response_env.response_headers['x-faraday-eds-cache'] = 'MISS' cache_response(response_env) when 400 raise EBSCO::EDS::BadRequest.new(error_message(response_env)) # when 401 # raise EBSCO::EDS::Unauthorized.new # when 403 # raise EBSCO::EDS::Forbidden.new # when 404 # raise EBSCO::EDS::NotFound.new # when 429 # raise EBSCO::EDS::TooManyRequests.new # when 500 # raise EBSCO::EDS::InternalServerError.new # when 503 # raise EBSCO::EDS::ServiceUnavailable.new else raise EBSCO::EDS::BadRequest.new(error_message(response_env)) end end end end def cache_response(env) return unless cacheable?(env) && !env.request_headers['x-faraday-eds-cache'] info "Cache WRITE: #{key(env)}" custom_expires_in = @expires_in uri = env.url if uri == AUTH_URI custom_expires_in = 1800 # 30 minutes info "#{uri} - Setting custom expires: #{custom_expires_in}" end if uri == INFO_URI custom_expires_in = 86400 # 24 hours info "#{uri} - Setting custom expires: #{custom_expires_in}" end @store.write(key(env), env, expires_in: custom_expires_in) end def cacheable?(env) uri = env.url if uri == AUTH_URI || uri == INFO_URI info "CACHEABLE URI: #{uri}" true else info "NOT CACHEABLE URI: #{uri}" false end end def cached_response(env) if cacheable?(env) && !env.request_headers['x-faraday-eds-cache'] response_env = @store.fetch(key(env)) end if response_env info "Cache HIT: #{key(env)}" else info "Cache MISS: #{key(env)}" end # info "CACHE: #{response_env.inspect}" response_env end def info(message) @logger.info(message) unless @logger.nil? end def key(env) env.url end def initialize_store return unless @store.is_a? Symbol require 'active_support/cache' @store = ActiveSupport::Cache.lookup_store(@store, @store_options) end def to_response(env) env = env.dup env.response_headers['x-faraday-eds-cache'] = 'HIT' response = Response.new response.finish(env) unless env.parallel? env.response = response end def error_message(response) # puts response.inspect { method: response.method, url: response.url, status: response.status, error_body: response.body } end end end