Repository: googleapis/google-api-python-client

Issue:
Unable to access private APIs
There is no possibility to use `earthengine` api with default behavior (static_discovery=True), because corresponded file is missed in discovery_cache. 

In addition this changes broke **earthengine-api**, see [issues/157](https://github.com/google/earthengine-api/issues/157)



Discussion:
Hi,

I think from the perspective of this library things are working as intended. `static_discovery=True` can only be used with APIs listed in the public directory of Google APIs: https://www.googleapis.com/discovery/v1/apis.

If an API is outside that list (API is **private** and/or **not listed in the directory**), there are two options:

**1.  Use `discovery.build_from_document()` with a copy of a discovery doc JSON for the API.**  

It looks like https://github.com/google/earthengine-api/blob/114dcad4bdd2edd7cf604c39e33019baab15436d/python/ee/_cloud_api_utils.py#L156-L179 does this, but only for tests.

Pros:
- Library will not change unexpectedly.
- No dependency on the live discovery document being available.

Cons:
- Need to update the JSON file manually.

**2. Use `discovery.build()` and pass *both* `discoveryServiceUrl` and `static_discovery=False`.** 

```py
from googleapiclient import discovery

client = discovery.build(
    "commentanalyzer",
    "v1alpha1",
    discoveryServiceUrl="https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1",
    static_discovery=False,
)
```

This results in behavior equivalent to 1.x of this library. 

Pros:
- Library always matches the latest version of the API.

Cons:
- If the discovery doc is unavailable for some period of time, you cannot use the Python library.
- The discovery doc may change in unexpected ways, resulting in different results from running the same code with the same dependencies multiple times. 


@parthea Would you mind adding some information to the docs clarifying which APIs are available with `static_discovery=True`?
Will do. In addition, there is an internal inquiry open for making the EarthEngine API discovery document public. Googlers see b/179047744
Googlers,

If you're an API owner and your users are broken by v2 please make sure:

1.  The discovery document [is public](https://g3doc.corp.google.com/google/g3doc/oneplatform/discovery.md?cl=head#making-your-discovery-document-public)
2.  The API [is listed](https://g3doc.corp.google.com/google/g3doc/oneplatform/discovery.md?cl=head#discovery-directory) in the discovery directory. 


As an added bonus you will get client libraries in the other languages with Discovery-based generators. :) 
> If you're an API owner and your users are broken by v2 please make sure:
> 
> 1. The discovery document [is public](https://g3doc.corp.google.com/google/g3doc/oneplatform/discovery.md?cl=head#making-your-discovery-document-public)

What can we do for private APIs?
Hi @Ark-kun,

Please see https://github.com/googleapis/google-api-python-client/issues/1225#issuecomment-791045487. 


_Right now_, you would do something like this to call a private API:

```py
from googleapiclient import discovery

client = discovery.build(
    "myapi",
    "v1alpha1",
    discoveryServiceUrl="https://myapi.googleapis.com/$discovery/rest?version=v1alpha1",
    static_discovery=False,
)
```

@parthea and I were discussing automatically setting `static_discovery=False` if `discoveryServiceUrl` is passed. With that change folks would do something like this:

```py
from googleapiclient import discovery

client = discovery.build(
    "myapi",
    "v1alpha1",
    discoveryServiceUrl="https://myapi.googleapis.com/$discovery/rest?version=v1alpha1",
)
```
@busunkim96 Is there an ETA on when we can call private API without specifying `static_discovery=False` (i.e. entirely backward compatible for client library 2.0 in terms of building the discovery client) ?
@wyk9787 I think by the end of this month. It should be a relatively small change in `discovery.build()`.



Resolving patch:
diff --git a/googleapiclient/discovery.py b/googleapiclient/discovery.py
--- a/googleapiclient/discovery.py
+++ b/googleapiclient/discovery.py
@@ -182,7 +182,7 @@ def build(
     serviceName,
     version,
     http=None,
-    discoveryServiceUrl=DISCOVERY_URI,
+    discoveryServiceUrl=None,
     developerKey=None,
     model=None,
     requestBuilder=HttpRequest,
@@ -193,7 +193,7 @@ def build(
     adc_cert_path=None,
     adc_key_path=None,
     num_retries=1,
-    static_discovery=True,
+    static_discovery=None,
 ):
     """Construct a Resource for interacting with an API.
 
@@ -248,7 +248,10 @@ def build(
     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 library.
+      included in the library. The default value for `static_discovery` depends
+      on the value of `discoveryServiceUrl`. `static_discovery` will default to
+      `True` when `discoveryServiceUrl` is also not provided, otherwise it will
+      default to `False`.
 
   Returns:
     A Resource object with methods for interacting with the service.
@@ -259,6 +262,21 @@ def build(
   """
     params = {"api": serviceName, "apiVersion": version}
 
+    # The default value for `static_discovery` depends on the value of
+    # `discoveryServiceUrl`. `static_discovery` will default to `True` when
+    # `discoveryServiceUrl` is also not provided, otherwise it will default to
+    # `False`. This is added for backwards compatability with
+    # google-api-python-client 1.x which does not support the `static_discovery`
+    # parameter.
+    if static_discovery is None:
+        if discoveryServiceUrl is None:
+            static_discovery = True
+        else:
+            static_discovery = False
+
+    if discoveryServiceUrl is None:
+        discoveryServiceUrl = DISCOVERY_URI
+
     if http is None:
         discovery_http = build_http()
     else:


Test patch:
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -592,7 +592,7 @@ def test_building_with_context_manager(self):
 
     def test_resource_close(self):
         discovery = read_datafile("plus.json")
-        
+
         with mock.patch("httplib2.Http", autospec=True) as httplib2_http:
             http = httplib2_http()
             plus = build_from_document(
@@ -927,8 +927,7 @@ def test_userip_is_added_to_discovery_uri(self):
                 "v1",
                 http=http,
                 developerKey=None,
-                discoveryServiceUrl="http://example.com",
-                static_discovery=False,
+                discoveryServiceUrl="http://example.com"
             )
             self.fail("Should have raised an exception.")
         except HttpError as e:
@@ -946,8 +945,7 @@ def test_userip_missing_is_not_added_to_discovery_uri(self):
                 "v1",
                 http=http,
                 developerKey=None,
-                discoveryServiceUrl="http://example.com",
-                static_discovery=False,
+                discoveryServiceUrl="http://example.com"
             )
             self.fail("Should have raised an exception.")
         except HttpError as e: