Class: Google::APIClient

Inherits:
Object
  • Object
show all
Defined in:
lib/google/api_client.rb,
lib/google/api_client/batch.rb,
lib/google/api_client/media.rb,
lib/google/api_client/errors.rb,
lib/google/api_client/result.rb,
lib/google/api_client/version.rb,
lib/google/api_client/reference.rb,
lib/google/api_client/environment.rb,
lib/google/api_client/discovery/api.rb,
lib/google/api_client/client_secrets.rb,
lib/google/api_client/discovery/media.rb,
lib/google/api_client/service_account.rb,
lib/google/api_client/discovery/method.rb,
lib/google/api_client/discovery/schema.rb,
lib/google/api_client/discovery/resource.rb

Overview

This class manages APIs communication.

Defined Under Namespace

Modules: ENV, PKCS12, Schema, VERSION Classes: API, BatchError, BatchRequest, BatchedCallResponse, ClientError, ClientSecrets, InvalidIDTokenError, JWTAsserter, MediaUpload, Method, Reference, Resource, Result, ResumableUpload, ServerError, TransmissionError, UploadIO, ValidationError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ APIClient

Creates a new Google API client.

Parameters:

  • options (Hash) (defaults to: {})

    The configuration parameters for the client.

Options Hash (options):

  • :authorization (Symbol, #generate_authenticated_request) — default: :oauth_1

    The authorization mechanism used by the client. The following mechanisms are supported out-of-the-box: <ul>

    <li><code>:two_legged_oauth_1</code></li>
    <li><code>:oauth_1</code></li>
    <li><code>:oauth_2</code></li>
    

    </ul>

  • :application_name (String)

    The name of the application using the client.

  • :application_version (String)

    The version number of the application using the client.

  • :user_agent (String) — default: "{app_name} google-api-ruby-client/{version} {os_name}/{os_version}"

    The user agent used by the client. Most developers will want to leave this value alone and use the ‘:application_name` option instead.

  • :host (String) — default: "www.googleapis.com"

    The API hostname used by the client. This rarely needs to be changed.

  • :port (String) — default: 443

    The port number used by the client. This rarely needs to be changed.

  • :discovery_path (String) — default: "/discovery/v1"

    The discovery base path. This rarely needs to be changed.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/google/api_client.rb', line 67

def initialize(options={})
  # Normalize key to String to allow indifferent access.
  options = options.inject({}) do |accu, (key, value)|
    accu[key.to_s] = value
    accu
  end
  # Almost all API usage will have a host of 'www.googleapis.com'.
  self.host = options["host"] || 'www.googleapis.com'
  self.port = options["port"] || 443
  self.discovery_path = options["discovery_path"] || '/discovery/v1'

  # Most developers will want to leave this value alone and use the
  # application_name option.
  application_string = (
    options["application_name"] ? (
      "#{options["application_name"]}/" +
      "#{options["application_version"] || '0.0.0'}"
    ) : ""
  )
  self.user_agent = options["user_agent"] || (
    "#{application_string} " +
    "google-api-ruby-client/#{VERSION::STRING} " +
     ENV::OS_VERSION
  ).strip
  # The writer method understands a few Symbols and will generate useful
  # default authentication mechanisms.
  self.authorization =
    options.key?("authorization") ? options["authorization"] : :oauth_2
  self.key = options["key"]
  self.user_ip = options["user_ip"]
  @discovery_uris = {}
  @discovery_documents = {}
  @discovered_apis = {}
  return self
end

Instance Attribute Details

#authorization#generate_authenticated_request

Returns the authorization mechanism used by the client.

Returns:



107
108
109
# File 'lib/google/api_client.rb', line 107

def authorization
  @authorization
end

#discovery_pathString

The base path used by the client for discovery.

Returns:

  • (String)

    The base path. Should almost always be ‘/discovery/v1’.



200
201
202
# File 'lib/google/api_client.rb', line 200

def discovery_path
  @discovery_path
end

#hostString

The API hostname used by the client.

Returns:



186
187
188
# File 'lib/google/api_client.rb', line 186

def host
  @host
end

#keyString

The application’s API key issued by the API console.

Returns:

  • (String)

    The API key.



166
167
168
# File 'lib/google/api_client.rb', line 166

def key
  @key
end

#portString

The port number used by the client.

Returns:

  • (String)

    The port number. Should almost always be 443.



193
194
195
# File 'lib/google/api_client.rb', line 193

def port
  @port
end

#user_agentString

The user agent used by the client.

Returns:

  • (String)

    The user agent string used in the User-Agent header.



179
180
181
# File 'lib/google/api_client.rb', line 179

def user_agent
  @user_agent
end

#user_ipString

The IP address of the user this request is being performed on behalf of.

Returns:

  • (String)

    The user’s IP address.



172
173
174
# File 'lib/google/api_client.rb', line 172

def user_ip
  @user_ip
end

Instance Method Details

#directory_documentHash

Returns the parsed directory document.

Returns:

  • (Hash)

    The parsed JSON from the directory document.



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/google/api_client.rb', line 294

def directory_document
  return @directory_document ||= (begin
    request = self.generate_request(
      :http_method => :get,
      :uri => self.directory_uri,
      :authenticated => false
    )
    response = self.transmit(:request => request)
    if response.status >= 200 && response.status < 300
      MultiJson.load(response.body)
    elsif response.status >= 400
      case response.status
      when 400...500
        exception_type = ClientError
      when 500...600
        exception_type = ServerError
      else
        exception_type = TransmissionError
      end
      url = request.to_env(Faraday.default_connection)[:url]
      raise exception_type,
        "Could not retrieve directory document at: #{url}"
    end
  end)
end

#directory_uriAddressable::URI

Returns the URI for the directory document.

Returns:

  • (Addressable::URI)

    The URI of the directory document.



231
232
233
# File 'lib/google/api_client.rb', line 231

def directory_uri
  return resolve_uri(self.discovery_path + '/apis')
end

#discovered_api(api, version = nil) ⇒ Google::APIClient::API

Returns the service object for a given service name and service version.

Parameters:

  • api (String, Symbol)

    The API name.

  • version (String) (defaults to: nil)

    The desired version of the API.

Returns:



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/google/api_client.rb', line 381

def discovered_api(api, version=nil)
  if !api.kind_of?(String) && !api.kind_of?(Symbol)
    raise TypeError,
      "Expected String or Symbol, got #{api.class}."
  end
  api = api.to_s
  version = version || 'v1'
  return @discovered_apis["#{api}:#{version}"] ||= begin
    document_base = self.discovery_uri(api, version)
    discovery_document = self.discovery_document(api, version)
    if document_base && discovery_document
      Google::APIClient::API.new(
        document_base,
        discovery_document
      )
    else
      nil
    end
  end
end

#discovered_apisArray

Returns all APIs published in the directory document.

Returns:

  • (Array)

    The list of available APIs.



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/google/api_client.rb', line 358

def discovered_apis
  @directory_apis ||= (begin
    document_base = self.directory_uri
    if self.directory_document && self.directory_document['items']
      self.directory_document['items'].map do |discovery_document|
        Google::APIClient::API.new(
          document_base,
          discovery_document
        )
      end
    else
      []
    end
  end)
end

#discovered_method(rpc_name, api, version = nil) ⇒ Google::APIClient::Method

Returns the method object for a given RPC name and service version.

Parameters:

  • rpc_name (String, Symbol)

    The RPC name of the desired method.

  • rpc_name (String, Symbol)

    The API the method is within.

  • version (String) (defaults to: nil)

    The desired version of the API.

Returns:



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/google/api_client.rb', line 410

def discovered_method(rpc_name, api, version=nil)
  if !rpc_name.kind_of?(String) && !rpc_name.kind_of?(Symbol)
    raise TypeError,
      "Expected String or Symbol, got #{rpc_name.class}."
  end
  rpc_name = rpc_name.to_s
  api = api.to_s
  version = version || 'v1'
  service = self.discovered_api(api, version)
  if service.to_h[rpc_name]
    return service.to_h[rpc_name]
  else
    return nil
  end
end

#discovery_document(api, version = nil) ⇒ Hash

Returns the parsed discovery document.

Parameters:

  • api (String, Symbol)

    The API name.

  • version (String) (defaults to: nil)

    The desired version of the API.

Returns:

  • (Hash)

    The parsed JSON from the discovery document.



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/google/api_client.rb', line 326

def discovery_document(api, version=nil)
  api = api.to_s
  version = version || 'v1'
  return @discovery_documents["#{api}:#{version}"] ||= (begin
    request = self.generate_request(
      :http_method => :get,
      :uri => self.discovery_uri(api, version),
      :authenticated => false
    )
    response = self.transmit(:request => request)
    if response.status >= 200 && response.status < 300
      MultiJson.load(response.body)
    elsif response.status >= 400
      case response.status
      when 400...500
        exception_type = ClientError
      when 500...600
        exception_type = ServerError
      else
        exception_type = TransmissionError
      end
      url = request.to_env(Faraday.default_connection)[:url]
      raise exception_type,
        "Could not retrieve discovery document at: #{url}"
    end
  end)
end

#discovery_uri(api, version = nil) ⇒ Addressable::URI

Returns the URI for the discovery document.

Parameters:

  • api (String, Symbol)

    The API name.

  • version (String) (defaults to: nil)

    The desired version of the API.

Returns:

  • (Addressable::URI)

    The URI of the discovery document.



254
255
256
257
258
259
260
261
262
263
264
# File 'lib/google/api_client.rb', line 254

def discovery_uri(api, version=nil)
  api = api.to_s
  version = version || 'v1'
  return @discovery_uris["#{api}:#{version}"] ||= (
    resolve_uri(
      self.discovery_path + '/apis/{api}/{version}/rest',
      'api' => api,
      'version' => version
    )
  )
end

#execute(*params) ⇒ Google::APIClient::Result

Executes a request, wrapping it in a Result object.

Examples:

result = client.execute(batch_request)
result = client.execute(
  :api_method => 'plus.activities.list',
  :parameters => {'collection' => 'public', 'userId' => 'me'}
)

Parameters:

  • params (Google::APIClient::BatchRequest, Hash, Array)

    Either a Google::APIClient::BatchRequest, a Hash, or an Array.

    If a Google::APIClient::BatchRequest, no other parameters are expected.

    If a Hash, the below parameters are handled. If an Array, the parameters are assumed to be in the below order:

    • (Google::APIClient::Method, String) api_method: The method object or the RPC name of the method being executed.

    • (Hash, Array) parameters: The parameters to send to the method.

    • (String) body: The body of the request.

    • (Hash, Array) headers: The HTTP headers for the request.

    • (Hash) options: A set of options for the request, of which:

      • (String) :version (default: “v1”) - The service version. Only used if ‘api_method` is a `String`.

      • (#generate_authenticated_request) :authorization (default: true) - The authorization mechanism for the response. Used only if ‘:authenticated` is `true`.

      • (TrueClass, FalseClass) :authenticated (default: true) - ‘true` if the request must be signed or somehow authenticated, `false` otherwise.

Returns:

See Also:



710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
# File 'lib/google/api_client.rb', line 710

def execute(*params)
  if params.last.kind_of?(Google::APIClient::BatchRequest) &&
      params.size == 1
    batch = params.pop
    options = batch.options
    options[:connection] ||= Faraday.default_connection
    http_request = batch.to_http_request
    request = nil

    if @authorization
      method, uri, headers, body = http_request
      method = method.to_s.downcase.to_sym

      faraday_request = options[:connection].build_request(
        method.to_s.downcase.to_sym
      ) do |req|
        req.url(Addressable::URI.parse(uri).normalize.to_s)
        req.headers = Faraday::Utils::Headers.new(headers)
        req.body = body
      end

      request = {
        :request => self.generate_authenticated_request(
          :request => faraday_request,
          :connection => options[:connection]
        ),
        :connection => options[:connection]
      }
    else
      request = {
        :request => http_request,
        :connection => options[:connection]
      }
    end

    response = self.transmit(request)
    batch.process_response(response)
    return nil
  else
    # This block of code allows us to accept multiple parameter passing
    # styles, and maintaining some backwards compatibility.
    #
    # Note: I'm extremely tempted to deprecate this style of execute call.
    if params.last.respond_to?(:to_hash) && params.size == 1
      options = params.pop
    else
      options = {}
    end

    options[:api_method] = params.shift if params.size > 0
    options[:parameters] = params.shift if params.size > 0
    options[:body] = params.shift if params.size > 0
    options[:headers] = params.shift if params.size > 0
    options[:client] = self
    options[:connection] ||= Faraday.default_connection
    reference = Google::APIClient::Reference.new(options)
    request = self.generate_request(reference)
    response = self.transmit(
      :request => request,
      :connection => options[:connection]
    )
    return Google::APIClient::Result.new(reference, request, response)
  end
end

#execute!(*params) ⇒ Object

Same as Google::APIClient#execute, but raises an exception if there was an error.

See Also:



780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
# File 'lib/google/api_client.rb', line 780

def execute!(*params)
  result = self.execute(*params)
  if result.error?
    error_message = result.error_message
    case result.response.status
      when 400...500
        exception_type = ClientError
        error_message ||= "A client error has occurred."
      when 500...600
        exception_type = ServerError
        error_message ||= "A server error has occurred."
      else
        exception_type = TransmissionError
        error_message ||= "A transmission error has occurred."
    end
    raise exception_type, error_message
  end
  return result
end

#generate_authenticated_request(options = {}) ⇒ Faraday::Request

Deprecated.

No longer used internally

Signs a request using the current authorization mechanism.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Returns:

  • (Faraday::Request)

    The signed or otherwise authenticated request.



582
583
584
# File 'lib/google/api_client.rb', line 582

def generate_authenticated_request(options={})
  return authorization.generate_authenticated_request(options)
end

#generate_request(options = {}) ⇒ Faraday::Request

Generates a request.

Examples:

request = client.generate_request(
  :api_method => 'plus.activities.list',
  :parameters =>
    {'collection' => 'public', 'userId' => 'me'}
)

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :api_method (Google::APIClient::Method, String)

    The method object or the RPC name of the method being executed.

  • :parameters (Hash, Array)

    The parameters to send to the method.

  • :headers (Hash, Array)

    The HTTP headers for the request.

  • :body (String)

    The body of the request.

  • :version (String) — default: "v1"

    The service version. Only used if ‘api_method` is a `String`.

  • :authorization (#generate_authenticated_request)

    The authorization mechanism for the response. Used only if ‘:authenticated` is `true`.

  • :authenticated (TrueClass, FalseClass) — default: true

    ‘true` if the request must be signed or somehow authenticated, `false` otherwise.

Returns:

  • (Faraday::Request)

    The generated request.



543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/google/api_client.rb', line 543

def generate_request(options={})
  # Note: The merge method on a Hash object will coerce an API Reference
  # object into a Hash and merge with the default options.

  options={
    :version => 'v1',
    :authorization => self.authorization,
    :key => self.key,
    :user_ip => self.user_ip,
    :connection => Faraday.default_connection
  }.merge(options)

  # The Reference object is going to need this to do method ID lookups.
  options[:client] = self
  # The default value for the :authenticated option depends on whether an
  # authorization mechanism has been set.
  if options[:authorization]
    options = {:authenticated => true}.merge(options)
  else
    options = {:authenticated => false}.merge(options)
  end
  reference = Google::APIClient::Reference.new(options)
  request = reference.to_request
  if options[:authenticated]
    request = options[:authorization].generate_authenticated_request(
      :request => request,
      :connection => options[:connection]
    )
  end
  return request
end

#preferred_version(api) ⇒ Google::APIClient::API

Note:

Warning: This method should be used with great care.

Returns the service object with the highest version number.

As APIs are updated, minor differences between versions may cause incompatibilities. Requesting a specific version will avoid this issue.

Parameters:

  • api (String, Symbol)

    The name of the service.

Returns:



436
437
438
439
440
441
442
443
444
445
# File 'lib/google/api_client.rb', line 436

def preferred_version(api)
  if !api.kind_of?(String) && !api.kind_of?(Symbol)
    raise TypeError,
      "Expected String or Symbol, got #{api.class}."
  end
  api = api.to_s
  return self.discovered_apis.detect do |a|
    a.name == api && a.preferred == true
  end
end

#register_discovery_document(api, version, discovery_document) ⇒ Object

Manually registers a pre-loaded discovery document for a specific version of an API.

Parameters:

  • api (String, Symbol)

    The API name.

  • version (String)

    The desired version of the API.

  • discovery_document (String, StringIO)

    The contents of the discovery document.



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/google/api_client.rb', line 274

def register_discovery_document(api, version, discovery_document)
  api = api.to_s
  version = version || 'v1'
  if discovery_document.kind_of?(StringIO)
    discovery_document.rewind
    discovery_document = discovery_document.string
  elsif discovery_document.respond_to?(:to_str)
    discovery_document = discovery_document.to_str
  else
    raise TypeError,
      "Expected String or StringIO, got #{discovery_document.class}."
  end
  @discovery_documents["#{api}:#{version}"] =
    MultiJson.load(discovery_document)
end

#register_discovery_uri(api, version, uri) ⇒ Object

Manually registers a URI as a discovery document for a specific version of an API.

Parameters:

  • api (String, Symbol)

    The API name.

  • version (String)

    The desired version of the API.

  • uri (Addressable::URI)

    The URI of the discovery document.



242
243
244
245
246
# File 'lib/google/api_client.rb', line 242

def register_discovery_uri(api, version, uri)
  api = api.to_s
  version = version || 'v1'
  @discovery_uris["#{api}:#{version}"] = uri
end

#resolve_uri(template, mapping = {}) ⇒ Addressable::URI

Resolves a URI template against the client’s configured base.

Parameters:

  • template (String, Addressable::URI, Addressable::Template)

    The template to resolve.

  • mapping (Hash) (defaults to: {})

    The mapping that corresponds to the template.

Returns:

  • (Addressable::URI)

    The expanded URI.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/google/api_client.rb', line 209

def resolve_uri(template, mapping={})
  @base_uri ||= Addressable::URI.new(
    :scheme => 'https',
    :host => self.host,
    :port => self.port
  ).normalize
  template = if template.kind_of?(Addressable::Template)
    template.pattern
  elsif template.respond_to?(:to_str)
    template.to_str
  else
    raise TypeError,
      "Expected String, Addressable::URI, or Addressable::Template, " +
      "got #{template.class}."
  end
  return Addressable::Template.new(@base_uri + template).expand(mapping)
end

#transmit(options = {}) ⇒ Faraday::Response

Transmits the request using the current HTTP adapter.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :request (Array, Faraday::Request)

    The HTTP request to transmit.

  • :method (String, Symbol)

    The method for the HTTP request.

  • :uri (String, Addressable::URI)

    The URI for the HTTP request.

  • :headers (Array, Hash)

    The headers for the HTTP request.

  • :body (String)

    The body for the HTTP request.

  • :connection (Faraday::Connection)

    The HTTP connection to use.

Returns:

  • (Faraday::Response)

    The response from the server.



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
# File 'lib/google/api_client.rb', line 603

def transmit(options={})
  options[:connection] ||= Faraday.default_connection
  if options[:request]
    if options[:request].kind_of?(Array)
      method, uri, headers, body = options[:request]
    elsif options[:request].kind_of?(Faraday::Request)
      unless options[:connection]
        raise ArgumentError,
          "Faraday::Request used, requires a connection to be provided."
      end
      method = options[:request].method.to_s.downcase.to_sym
      uri = options[:connection].build_url(
        options[:request].path, options[:request].params
      )
      headers = options[:request].headers || {}
      body = options[:request].body || ''
    end
  else
    method = options[:method] || :get
    uri = options[:uri]
    headers = options[:headers] || []
    body = options[:body] || ''
  end
  headers = headers.to_a if headers.kind_of?(Hash)
  request_components = {
    :method => method,
    :uri => uri,
    :headers => headers,
    :body => body
  }
  # Verify that we have all pieces required to transmit an HTTP request
  request_components.each do |(key, value)|
    unless value
      raise ArgumentError, "Missing :#{key} parameter."
    end
  end

  if self.user_agent != nil
    # If there's no User-Agent header, set one.
    unless headers.kind_of?(Enumerable)
      # We need to use some Enumerable methods, relying on the presence of
      # the #each method.
      class << headers
        include Enumerable
      end
    end
    if self.user_agent.kind_of?(String)
      unless headers.any? { |k, v| k.downcase == 'User-Agent'.downcase }
        headers = headers.to_a.insert(0, ['User-Agent', self.user_agent])
      end
    elsif self.user_agent != nil
      raise TypeError,
        "Expected User-Agent to be String, got #{self.user_agent.class}"
    end
  end

  request = options[:connection].build_request(
    method.to_s.downcase.to_sym
  ) do |req|
    req.url(Addressable::URI.parse(uri).normalize.to_s)
    req.headers = Faraday::Utils::Headers.new(headers)
    req.body = body
  end
  request_env = request.to_env(options[:connection])
  response = options[:connection].app.call(request_env)
  return response
end

#verify_id_token!Object

Verifies an ID token against a server certificate. Used to ensure that an ID token supplied by an untrusted client-side mechanism is valid. Raises an error if the token is invalid or missing.



451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# File 'lib/google/api_client.rb', line 451

def verify_id_token!
  gem 'jwt', '~> 0.1.4'
  require 'jwt'
  require 'openssl'
  @certificates ||= {}
  if !self.authorization.respond_to?(:id_token)
    raise ArgumentError, (
      "Current authorization mechanism does not support ID tokens: " +
      "#{self.authorization.class.to_s}"
    )
  elsif !self.authorization.id_token
    raise ArgumentError, (
      "Could not verify ID token, ID token missing. " +
      "Scopes were: #{self.authorization.scope.inspect}"
    )
  else
    check_cached_certs = lambda do
      valid = false
      for key, cert in @certificates
        begin
          self.authorization.decoded_id_token(cert.public_key)
          valid = true
        rescue JWT::DecodeError, Signet::UnsafeOperationError
          # Expected exception. Ignore, ID token has not been validated.
        end
      end
      valid
    end
    if check_cached_certs.call()
      return true
    end
    request = self.generate_request(
      :http_method => :get,
      :uri => 'https://www.googleapis.com/oauth2/v1/certs',
      :authenticated => false
    )
    response = self.transmit(:request => request)
    if response.status >= 200 && response.status < 300
      @certificates.merge!(
        Hash[MultiJson.load(response.body).map do |key, cert|
          [key, OpenSSL::X509::Certificate.new(cert)]
        end]
      )
    elsif response.status >= 400
      case response.status
      when 400...500
        exception_type = ClientError
      when 500...600
        exception_type = ServerError
      else
        exception_type = TransmissionError
      end
      url = request.to_env(Faraday.default_connection)[:url]
      raise exception_type,
        "Could not retrieve certificates from: #{url}"
    end
    if check_cached_certs.call()
      return true
    else
      raise InvalidIDTokenError,
        "Could not verify ID token against any available certificate."
    end
  end
  return nil
end