Skip to content

Commit

Permalink
feat: Add support for static discovery documents
Browse files Browse the repository at this point in the history
  • Loading branch information
parthea committed Nov 26, 2020
1 parent af918e8 commit 130a961
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 19 deletions.
60 changes: 42 additions & 18 deletions googleapiclient/discovery.py
Expand Up @@ -193,6 +193,7 @@ def build(
adc_cert_path=None,
adc_key_path=None,
num_retries=1,
static_discovery=True,
):
"""Construct a Resource for interacting with an API.
Expand Down Expand Up @@ -246,6 +247,9 @@ def build(
https://google.aip.dev/auth/4114
num_retries: Integer, number of times to retry discovery with
randomized exponential backoff in case of intermittent/connection issues.
static_discovery: Boolean, whether or not to use the static discovery docs
included in the package when the discovery doc is not available in the
cache.
Returns:
A Resource object with methods for interacting with the service.
Expand Down Expand Up @@ -274,6 +278,7 @@ def build(
cache,
developerKey,
num_retries=num_retries,
static_discovery=static_discovery,
)
service = build_from_document(
content,
Expand Down Expand Up @@ -330,7 +335,13 @@ def _discovery_service_uri_options(discoveryServiceUrl, version):


def _retrieve_discovery_doc(
url, http, cache_discovery, cache=None, developerKey=None, num_retries=1
url,
http,
cache_discovery,
cache=None,
developerKey=None,
num_retries=1,
static_discovery=True
):
"""Retrieves the discovery_doc from cache or the internet.
Expand All @@ -345,35 +356,48 @@ def _retrieve_discovery_doc(
from the API Console.
num_retries: Integer, number of times to retry discovery with
randomized exponential backoff in case of intermittent/connection issues.
static_discovery: Boolean, whether or not to use the static discovery docs
included in the package when the discovery doc is not available in the
cache.
Returns:
A unicode string representation of the discovery document.
"""
if cache_discovery:
from . import discovery_cache
from . import discovery_cache

content = None

if cache_discovery:
if cache is None:
cache = discovery_cache.autodetect()
if cache:
content = cache.get(url)
if content:
return content

actual_url = url
# REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
# variable that contains the network address of the client sending the
# request. If it exists then add that to the request for the discovery
# document to avoid exceeding the quota on discovery requests.
if "REMOTE_ADDR" in os.environ:
actual_url = _add_query_parameter(url, "userIp", os.environ["REMOTE_ADDR"])
if developerKey:
actual_url = _add_query_parameter(url, "key", developerKey)
logger.debug("URL being requested: GET %s", actual_url)

# Execute this request with retries build into HttpRequest
# Note that it will already raise an error if we don't get a 2xx response
req = HttpRequest(http, HttpRequest.null_postproc, actual_url)
resp, content = req.execute(num_retries=num_retries)
# At this point, the discovery document was not found in the cache so
# we can attempt to retreive the static discovery document from the library.
if static_discovery:
content = discovery_cache.get_static_doc(url)

# If the content is None, retrieve the discovery doc from the internet
# because it is not in the cache or the static doc directory.
if content is None:
actual_url = url
# REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
# variable that contains the network address of the client sending the
# request. If it exists then add that to the request for the discovery
# document to avoid exceeding the quota on discovery requests.
if "REMOTE_ADDR" in os.environ:
actual_url = _add_query_parameter(url, "userIp", os.environ["REMOTE_ADDR"])
if developerKey:
actual_url = _add_query_parameter(url, "key", developerKey)
logger.debug("URL being requested: GET %s", actual_url)

# Execute this request with retries build into HttpRequest
# Note that it will already raise an error if we don't get a 2xx response
req = HttpRequest(http, HttpRequest.null_postproc, actual_url)
resp, content = req.execute(num_retries=num_retries)

try:
content = content.decode("utf-8")
Expand Down
34 changes: 33 additions & 1 deletion googleapiclient/discovery_cache/__init__.py
Expand Up @@ -23,7 +23,8 @@
LOGGER = logging.getLogger(__name__)

DISCOVERY_DOC_MAX_AGE = 60 * 60 * 24 # 1 day

DISCOVERY_DOC_DIR = os.path.join(os.path.dirname(
os.path.realpath(__file__)), 'documents')

def autodetect():
"""Detects an appropriate cache module and returns it.
Expand All @@ -47,3 +48,34 @@ def autodetect():
except Exception as e:
LOGGER.warning(e, exc_info=True)
return None

def get_static_doc(uri):
"""Retrieves the discovery document from the directory defined in
DISCOVERY_DOC_STATIC_DIR corresponding to the uri provided.
Args:
uri: string, The URI of the discovery document in the format
https://{domain}/discovery/{discoveryVer}/apis/{api}/{apiVersion}/rest
Returns:
A string containing the contents of the JSON discovery document,
otherwise None if the JSON discovery document was not found.
"""

doc_name = None

# Extract the {apiVersion} and {api} from the uri which are the 2nd and 3rd
# last parts of the uri respectively.
# https://www.googleapis.com/discovery/v1/apis/{api}/{apiVersion}/rest
uri_parts = uri.split('/')
if len(uri_parts) > 3:
doc_name = "{}.{}.json".format(uri_parts[-3], uri_parts[-2])

try:
with open(os.path.join(DISCOVERY_DOC_DIR, doc_name), 'r') as f:
content = f.read()
except FileNotFoundError:
content = None

return content

0 comments on commit 130a961

Please sign in to comment.