Class: NexusMods::ApiClient

Inherits:
Object
  • Object
show all
Includes:
CacheableApi
Defined in:
lib/nexus_mods/api_client.rb

Overview

Base class handling HTTP calls to the NexusMods API. Handle caching if needed.

Constant Summary collapse

DEFAULT_API_CACHE_EXPIRY =

Default expiry times, in seconds

{
  games: 24 * 60 * 60,
  mod: 24 * 60 * 60,
  mod_files: 24 * 60 * 60
}

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CacheableApi

included

Constructor Details

#initialize(api_key: nil, api_cache_expiry: DEFAULT_API_CACHE_EXPIRY, api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json", logger: Logger.new($stdout)) ⇒ ApiClient

Constructor

Parameters
  • api_key (String or nil): The API key to be used, or nil for another authentication [default: nil]

  • api_cache_expiry (Hash<Symbol,Integer>): Expiry times in seconds, per expiry key. Possible keys are:

    • games: Expiry associated to queries on games [default: 1 day]

    • mod: Expiry associated to queries on mod [default: 1 day]

    • mod_files: Expiry associated to queries on mod files [default: 1 day]

  • api_cache_file (String): File used to store the NexusMods API cache, or nil for no cache [default: “#Dir.tmpdir/nexus_mods_api_cache.json”]

  • logger (Logger): The logger to be used for log messages [default: Logger.new(STDOUT)]



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/nexus_mods/api_client.rb', line 31

def initialize(
  api_key: nil,
  api_cache_expiry: DEFAULT_API_CACHE_EXPIRY,
  api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json",
  logger: Logger.new($stdout)
)
  @api_key = api_key
  @api_cache_expiry = DEFAULT_API_CACHE_EXPIRY.merge(api_cache_expiry)
  @api_cache_file = api_cache_file
  ApiClient.api_client = self
  @logger = logger
  # Initialize our HTTP client
  @http_client = Faraday.new
  Cacheable.cache_adapter = :persistent_json
  load_api_cache
end

Class Attribute Details

.api_clientObject

ApiClient: The API client to be used by the cacheable adapter (singleton pattern)



131
132
133
# File 'lib/nexus_mods/api_client.rb', line 131

def api_client
  @api_client
end

Instance Attribute Details

#api_cache_expiryObject (readonly)

Some attributes exposed for the cacheable feature to work



124
125
126
# File 'lib/nexus_mods/api_client.rb', line 124

def api_cache_expiry
  @api_cache_expiry
end

Class Method Details

.cache_key(path, parameters:, verb:) ⇒ Object

Get the cache key to be used for a given API query

Parameters
  • path (String): API path to contact (from v1/ and without .json)

  • parameters (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]

  • verb (Symbol): Verb to be used (:get, :post…) [default: :get]

Result
  • String: The corresponding cache key



141
142
143
# File 'lib/nexus_mods/api_client.rb', line 141

def cache_key(path, parameters:, verb:)
  "#{verb}/#{path}#{parameters.empty? ? '' : "/#{parameters.map { |param, value| "#{param}=#{value}" }.sort.join('/')}"}"
end

Instance Method Details

#api(path, parameters: {}, verb: :get, clear_cache: false) ⇒ Object

Send an HTTP request to the API and get back the answer as a JSON. Use caching.

Parameters
  • path (String): API path to contact (from v1/ and without .json)

  • parameters (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]

  • verb (Symbol): Verb to be used (:get, :post…) [default: :get]

  • clear_cache (Boolean): Should we clear the API cache for this resource? [default: false]

Result
  • Object: The JSON response



58
59
60
61
# File 'lib/nexus_mods/api_client.rb', line 58

def api(path, parameters: {}, verb: :get, clear_cache: false)
  clear_cached_api_cache(path, parameters:, verb:) if clear_cache
  cached_api(path, parameters:, verb:)
end

#api_cache_timestamp(path, parameters: {}, verb: :get) ⇒ Object

Get the timestamp of the cached data linked to a given API call

Parameters
  • path (String): API path to contact (from v1/ and without .json)

  • parameters (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]

  • verb (Symbol): Verb to be used (:get, :post…) [default: :get]

Result
  • Time or nil: The refresh time of the data, or nil if not part of the cache



71
72
73
74
75
76
77
# File 'lib/nexus_mods/api_client.rb', line 71

def api_cache_timestamp(path, parameters: {}, verb: :get)
  key = ApiClient.cache_key(path, parameters:, verb:)
  return unless Cacheable.cache_adapter.exist?(key)

  str_time = Cacheable.cache_adapter.context.dig(key, 'invalidate_time')
  str_time.nil? ? nil : Time.parse(str_time)
end

#http(path, parameters: {}, verb: :get) ⇒ Object

Send an HTTP request to the API and get back the HTTP response

Parameters
  • path (String): API path to contact (from v1/ and without .json)

  • parameters (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]

  • verb (Symbol): Verb to be used (:get, :post…) [default: :get]

Result
  • Faraday::Response: The HTTP response



102
103
104
105
106
107
108
# File 'lib/nexus_mods/api_client.rb', line 102

def http(path, parameters: {}, verb: :get)
  @http_client.send(verb) do |req|
    req.url api_uri(path, parameters:)
    req.headers['apikey'] = @api_key
    req.headers['User-Agent'] = "nexus_mods/#{NexusMods::VERSION} (#{RUBY_PLATFORM}) Ruby/#{RUBY_VERSION}"
  end
end

#load_api_cacheObject

Load the API cache if a file was given to this client



111
112
113
# File 'lib/nexus_mods/api_client.rb', line 111

def load_api_cache
  Cacheable.cache_adapter.load(@api_cache_file) if @api_cache_file && File.exist?(@api_cache_file)
end

#save_api_cacheObject

Save the API cache if a file was given to this client



116
117
118
119
120
121
# File 'lib/nexus_mods/api_client.rb', line 116

def save_api_cache
  return unless @api_cache_file

  FileUtils.mkdir_p(File.dirname(@api_cache_file))
  Cacheable.cache_adapter.save(@api_cache_file)
end

#set_api_cache_timestamp(path, cache_timestamp:, parameters: {}, verb: :get) ⇒ Object

Set the timestamp of the cached data linked to a given API call. This should be used only to update the cache timestamp of a resource we know is still up-to-date without fetching the resource for real again.

Parameters
  • path (String): API path to contact (from v1/ and without .json)

  • parameters (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]

  • verb (Symbol): Verb to be used (:get, :post…) [default: :get]

  • cache_timestamp (Time): The cache timestamp to set for this resource



87
88
89
90
91
92
# File 'lib/nexus_mods/api_client.rb', line 87

def set_api_cache_timestamp(path, cache_timestamp:, parameters: {}, verb: :get)
  key = ApiClient.cache_key(path, parameters:, verb:)
  Cacheable.cache_adapter.context[key] = {} unless Cacheable.cache_adapter.context.key?(key)
  Cacheable.cache_adapter.context[key]['invalidate_time'] = cache_timestamp.utc.strftime('%FT%T.%9NUTC')
  save_api_cache
end