Giter Club home page Giter Club logo

elixir-google-api's Introduction

GoogleApis

This repository contains all the client libraries to interact with Google APIs. These client libraries are created under clients/ and each should contain its own README.

The main folder contains the code necessary to generate these client libraries.

NOTE: These generated clients are under development and should be considered experimental!

Usage

Installation

All available Google API clients can be found on hex.pm. Add a client to your project's mix.exs under deps:

defmodule YourApplication.Mixfile do
  use Mix.Project
  #...

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:google_api_storage, "~> 0.19.0"},
      {:goth, "~> 1.2.0"}
    ]
  end
end

Note the goth package, which handles Google Authentication, is also required.

Next, run mix deps.get to pull down the dependencies:

$ mix deps.get

Now you can make an API call by obtaining an access token and using the generated modules.

Obtaining an Access Token

Service Accounts

Authentication is typically done through Application Default Credentials which means you do not have to change the code to authenticate as long as your environment has credentials. Start by creating a Service Account key file. This file can be used to authenticate to Google Cloud Platform services from any environment. To use the file, set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path to the key file, for example:

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json

If you are deploying to App Engine, Compute Engine, or Container Engine, your credentials will be available by default.

OAuth 2.0

Many APIs (like Drive, Gmail, and YouTube) require you to use OAuth 2.0 to authorize requests on behalf of an authenticated user. For an example using the oauth2-library, see the auth sample.

We've also provided a mix task to fetch a token for testing. The following command requests a token for the Drive full access scope:

$ export GOOGLE_CLIENT_ID=[YOUR-OAUTH-CLIENT-ID]
$ export GOOGLE_CLIENT_SECRET=[YOUR-OAUTH-CLIENT-SECRET]
$ mix google_apis.auth https://www.googleapis.com/auth/drive
Open the following link in your brower:
https://accounts.google.com/o/oauth2/auth?[some-long-url]
Enter verification code:

Once you've logged in and authorized the application, copy the code param from the web browser's url and paste into the console. The script will then fetch your OAuth access token.

Token: [your-oauth-token]

You can then use this token for your testing:

connection = GoogleApi.Drive.V3.Connection.new("your-oauth-token")
{:ok, file_list} = GoogleApi.Drive.V3.Api.Files.drive_files_list(conn)

Making a Request

# Obtain an access token using goth
{:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
conn = GoogleApi.Storage.V1.Connection.new(token.token)

# Call the Storage V1 API (for example) to list buckets
{:ok, response} = GoogleApi.Storage.V1.Api.Buckets.storage_buckets_list(conn, project_id)

# Print the response
Enum.each(response.items, &IO.puts(&1.id))

What's Next?

Take a look at our elixir-samples repository repository for examples of calling individual APIs and a getting started tutorial app.

Generating Clients

Setup

  1. Install nodejs if not already installed.
  2. Install nodejs dependencies:
$> npm install
  1. Install elixir dependencies:
$> mix deps.get

This project provides 4 mix tasks to componentize the build process:

  1. mix google_apis.discover - Select which APIs to build
  2. mix google_apis.fetch - Download the selected API specifications in Google discovery format
  3. mix google_apis.convert - Convert the selected API specifications from Google discovery format to OpenApi v2 (formerly known as Swagger)
  4. mix google_apis.build - Generate API clients

Selecting APIs

The mix google_apis.discover task queries Google's API discovery directory. The contents of this file are downloaded to a staging file (api-candidate.json) under the config directory.

You can change the name of the file by providing a filename argument to the mix task:

$> mix google_apis.discover foo.json

Note that this task is not one that should be run often, as the config/api.json is considered configuration regarding which APIs to generate.

Fetching API Specifications

The mix google_apis.fetch task iterates through the list of API specifications in the config/api.json file and downloads the specification to the specifications/gdd folder with the format of <name>-<version>.json.

You can limit which APIs to fetch by providing an API name argument to the mix task:

$> mix google_apis.fetch CloudTrace

Converting API Specifications

The next step is to convert the API specifications from Google's discovery format to OpenApi format. The mix google_apis.convert task iterates through the list of API specifications in the config/api.json file and converts each found Google discovery specification to an equivalent* OpenApi version.

You can configure the converter by modifying the config/config.exs setting:

config :google_apis, spec_converter: <some converter implementation>

The default converter uses the node package api-spec-converter. You can also limit which APIs to convert by providing an API name argument to the mix task:

$> mix google_apis.convert CloudTrace

Building API Clients

The mix google_apis.build task iterates through the list of API specifications in the config/api.json file and generates an Elixir client library in the clients folder.

You can configure the converter by modifying the config/config.exs setting:

config :google_apis, client_generator: GoogleApis.Generator.SwaggerCli

The default generator uses Docker and an image based off the swagger-codegen project. You can further configure this converter by modifying the config/config.exs setting:

config :google_apis, swagger_cli_image: "swagger-cli"

You can also limit which APIs to generate by providing an API name argument to the mix task:

$> mix google_apis.generate CloudTrace

Contributing

Contributions to this library are always welcome and highly encouraged.

See CONTRIBUTING for more information on how to get started.

License

Apache 2.0 - See LICENSE for more information.

Disclaimer

This is not an officially supported Google product.

elixir-google-api's People

Contributors

ashardweedar avatar bshaffer avatar chingor13 avatar dazuma avatar doerge avatar google-cloud-policy-bot[bot] avatar jaegerpicker avatar jamesvl avatar justinbeckwith avatar leandrocp avatar milmazz avatar phineas avatar pojiro avatar renovate-bot avatar rwhogg avatar shavit avatar surferjeffatgoogle avatar theacodes avatar tyler-eon avatar yoshi-automation avatar yoshi-code-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elixir-google-api's Issues

Please update firestore API to include missing endpoints

Using the Google APIs Explorer, I see that firestore has the following endpoint:
https://developers.google.com/apis-explorer/#search/firestore/m/firestore/v1beta1/firestore.projects.databases.documents.get

However, the Elixir client library does not appear to have that yet:

https://github.com/GoogleCloudPlatform/elixir-google-api/blob/master/clients/firestore/lib/google_api/firestore/v1beta1/api/projects.ex

@chingor13 - is this the correct way to request updates?

Thank you!

Synthesis failed for AcceleratedMobilePageUrl

Hello! Autosynth couldn't regenerate AcceleratedMobilePageUrl. 💔

Here's the output from running synth.py:

Cloning into 'working_repo'...
Switched to branch 'autosynth-acceleratedmobilepageurl'
�[35msynthtool > �[31m�[43mYou are running the synthesis script directly, this will be disabled in a future release of Synthtool. Please use python3 -m synthtool instead.�[0m
�[35msynthtool > �[36mCloning https://github.com/googleapis/elixir-google-api.git.�[0m
�[35msynthtool > �[36mRunning in docker: docker run --rm -v/home/kbuilder/.cache/synthtool/elixir-google-api:/workspace -v/var/run/docker.sock:/var/run/docker.sock -w /workspace gcr.io/cloud-devrel-public-resources/elixir16 scripts/generate_client.sh AcceleratedMobilePageUrl�[0m

Changed files:

On branch autosynth-acceleratedmobilepageurl
nothing to commit, working tree clean
Traceback (most recent call last):
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 166, in <module>
    main()
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 151, in main
    commit_changes(pr_title)
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 95, in commit_changes
    subprocess.check_call(["git", "commit", "-m", message])
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/subprocess.py", line 291, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['git', 'commit', '-m', 'Regenerate AcceleratedMobilePageUrl client']' returned non-zero exit status 1.

Google internal developers can see the full log here.

Rename this repository to "elixir-api-client"

The name elixir-google-api seems like Google has a product called Elixir and this code exposes the API for it. Rather, this repository is the client library for google apis, so I think it would be a much better name elixir-api-client, with "google` being explicit via the Org name.

Alternatively we could name it elixir-google-api-client or elixir-google-client

What should the name of this repo be?




Google Storage Objects API does not support file downloads.

The Storage Objects API storage_objects_get does not currently support objects in the response body. It's available under the alt=media param

expected

iex(1)> GoogleApi.Storage.V1.Api.Objects.storage_objects_get(conn, "buck_name", 
"file.json", [{:alt, "media"}])
{:ok, response_object}

actual

iex(1)> GoogleApi.Storage.V1.Api.Objects.storage_objects_get(conn, "buck_name", 
"file.json", [{:alt, "media"}])
{:ok,
 %GoogleApi.Storage.V1.Model.Object{acl: nil, bucket: nil, cacheControl: nil,
  componentCount: nil, contentDisposition: nil, contentEncoding: nil,
  contentLanguage: nil, contentType: nil, crc32c: nil, customerEncryption: nil,
  etag: nil, generation: nil, id: nil, kind: nil, kmsKeyName: nil, md5Hash: nil,
  mediaLink: nil, metadata: nil, metageneration: nil, name: nil, owner: nil,
  selfLink: nil, size: nil, storageClass: nil, timeCreated: nil,
  timeDeleted: nil, timeStorageClassUpdated: nil, updated: nil}}

Also, open to the suggestion that the client should only support a handful of "content-type" flags.

Would be happy to put together a PR for this one if the community sees value.

dialyzer has a lot to complain

In a thread in the elixirforum we discovered some issues with the specs of your library.

A quick run against the sheet library (which ultimatively had the problems in the aforementioned thread) revealed the following warnings:

:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.AppendValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.BatchClearValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.BatchGetValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.BatchUpdateSpreadsheetResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.BatchUpdateValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.ClearValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.SheetProperties':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.Spreadsheet':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.UpdateValuesResponse':t/0
:0: Unknown type 'Elixir.GoogleApi.Sheets.V4.Model.ValueRange':t/0
:0: Unknown type 'Elixir.Integer':t/0
:0: Unknown type 'Elixir.Map':t/0
lib/google_api/sheets/v4/api/spreadsheets.ex:58: Function sheets_spreadsheets_batch_update/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:58: Function sheets_spreadsheets_batch_update/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:76: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:114: Function sheets_spreadsheets_create/1 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:114: Function sheets_spreadsheets_create/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:132: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:170: Function sheets_spreadsheets_get/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:170: Function sheets_spreadsheets_get/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:189: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'get') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:229: Function sheets_spreadsheets_sheets_copy_to/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:229: Function sheets_spreadsheets_sheets_copy_to/4 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:247: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:293: Function sheets_spreadsheets_values_append/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:293: Function sheets_spreadsheets_values_append/4 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:316: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:356: Function sheets_spreadsheets_values_batch_clear/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:356: Function sheets_spreadsheets_values_batch_clear/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:374: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:416: Function sheets_spreadsheets_values_batch_get/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:416: Function sheets_spreadsheets_values_batch_get/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:437: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'get') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:476: Function sheets_spreadsheets_values_batch_update/2 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:476: Function sheets_spreadsheets_values_batch_update/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:494: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:534: Function sheets_spreadsheets_values_clear/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:534: Function sheets_spreadsheets_values_clear/4 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:552: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'post') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:595: Function sheets_spreadsheets_values_get/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:595: Function sheets_spreadsheets_values_get/4 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:615: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'get') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/api/spreadsheets.ex:660: Function sheets_spreadsheets_values_update/3 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:660: Function sheets_spreadsheets_values_update/4 has no local return
lib/google_api/sheets/v4/api/spreadsheets.ex:682: The call 'Elixir.GoogleApi.Sheets.V4.RequestBuilder':method(#{},'put') breaks the contract (map(),'Elixir.String':t()) -> map()
lib/google_api/sheets/v4/deserializer.ex:28: Invalid type specification for function 'Elixir.GoogleApi.Sheets.V4.Deserializer':deserialize/5. The success typing is (_,_,'date' | 'list' | 'map' | 'struct',_,_) -> any()
lib/google_api/sheets/v4/deserializer.ex:45: The pattern {'ok', Vdatetime@1} can never match the type {'error','invalid_date' | 'invalid_format' | 'invalid_time' | 'missing_offset'} | {'ok',#{'__struct__':='Elixir.DateTime', 'calendar':=atom(), 'day':=integer(), 'hour':=integer(), 'microsecond':={char(),0 | 1 | 2 | 3 | 4 | 5 | 6}, 'minute':=integer(), 'month':=integer(), 'second':=integer(), 'std_offset':=integer(), 'time_zone':=binary(), 'utc_offset':=integer(), 'year':=integer(), 'zone_abbr':=binary()},integer()}

I do assume, that it is not better with the other libraries.

Define an API for HTTP clients

Hi everyone!

Thanks for making those libraries available as they really help many Elixir projects bootstrap on Google Cloud. 👍

It seems today Google API is built on Tesla but I would like to request a feature where Google API actually defines an HTTP Client contract that should be implemented. My main concern is the cascading layers that we go through to do any sort of HTTP connection/polling customization or instrumentation.

For example, if I am using Google PubSub, it is built on top of Google.Gax:

https://github.com/GoogleCloudPlatform/elixir-google-api/blob/master/clients/pub_sub/lib/google_api/pub_sub/v1/connection.ex

Google.Gax connection is built on top of Tesla:

https://github.com/GoogleCloudPlatform/elixir-google-api/blob/bbf9cf4007852d1d9108fe43608afe5c74179bb6/clients/gax/lib/google_api/gax/connection.ex

And tesla itself is a "meta" client with multiple adapters:

https://github.com/teamon/tesla/#adapters

Inside the adapters, then we can find the actual HTTP client implementation, which defaults to httpc (which is not recommended for production). Tesla has information on how to change the adapters but it has no information on how to control the pool size, set connection wide settings, etc (or at least I couldn't find any).

Therefore, for me to do any customization, metrics, monitoring, etc on how HTTP requests come and go in my system, we need to go through all of those layers, and it is still not clear how this can be achieved.

This may be perhaps what Tesla aims to achieve but custom adapters are not strongly highlighted in their docs at the moment. Plus it seems that you already have your own request builder and a very thin contract around the connection, so from a glance it makes sense to expose it rather than force users to go through gax -> tesla -> adapter.

To clarify, I am not saying that Gax.Connection should be replaceable, as it still has some domain information, but rather that the places you call Tesla inside Gax.Connection could be abstracted in favor of a simpler contract. Since you already pass the Gax.Connection around, you could keep the "connection backend" stored there too. Thanks for reading!

EDIT: Removed incorrect suggestion to pass :connection as option as it is already passed as argument.

Google Beacon Proximity API activate/deactivate beacon error: no function clause matching in :httpc.request/5

Awesome that there's an elixir api client now!

I've started testing the API client and got most calls working but got the following error in the activate/deactivate calls:

* (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in :httpc.request/5
        (inets) httpc.erl:149: :httpc.request(:post, {'https://proximitybeacon.googleapis.com/v1beta1/beacons/3!0123456789abcdef1123000000000003:activate', [{'authorization', 'Bearer ya29.c.Elo8BZjAwNexF3gkUrKn9m-3VGwtAl-s3TTxfvxQvtRziNh-TpRZTJ9DAY_-18zIi0kRFSEsNQWuiCwK6kRFAY_aD3aLQAv_BGAx74sua2AAuTC1yK0xpzLPXZw'}, {'user-agent', 'Elixir'}]}, [autoredirect: false], [], :default)
        (tesla) lib/tesla/adapter/httpc.ex:32: Tesla.Adapter.Httpc.request/2
        (tesla) lib/tesla/adapter/httpc.ex:19: Tesla.Adapter.Httpc.call/2
        (tesla) lib/tesla/middleware/core.ex:6: Tesla.Middleware.Normalize.call/3
        (stdlib) timer.erl:197: :timer.tc/3
        (tesla) lib/tesla/middleware/logger.ex:29: Tesla.Middleware.Logger.call/3

I'm aware that this is similar to an already reported issue #26, but the workaround cannot be applied in this case since the function signature doesn't let me pass a body argument.

Any help/advice would be appreciated. Many thanks in advance!

Complex paths causing syntax error

Urls have "+" in the string interpolation.

Affected API clients:

  • AndroidDeviceProvisioning
  • AndroidManagement
  • BigQueryDataTransfer
  • Datastore
  • DLP
  • FirebaseRules
  • Genomics
  • Manufacturers
  • OSLogin
  • ProximityBeacon
  • ServiceManagement
  • ServiceUsers
  • Slides
  • SourceRepo
  • Spanner
  • Speech
  • StorageTransfer
  • TagManager
  • YouTubeReporting

RequestBuilder should allow 2xx status codes beyond just 200

The current RequestBuilder.decode methods assume that the only successful status code that should result in decoding the response is an HTTP 200 code. I believe that this should be expanded such that other 200-level status codes are also treated as successful responses that can be decoded. For example:

  defmacro is_success(code) do
    quote do: unquote(code) in [200, 201, 202, 203, 204, 205, 206, 207, 208, 226]
  end

  @spec decode(Tesla.Env.t | term()) :: {:ok, struct()} | {:error, Tesla.Env.t} | {:error, term()}
  def decode(%Tesla.Env{status: code, body: body}) when is_success(code), do: Poison.decode(body)
  def decode(response), do: {:error, response}

  @spec decode(Tesla.Env.t | term(), :false | struct() | [struct()]) :: {:ok, struct()} | {:error, Tesla.Env.t} | {:error, term()}
  def decode(%Tesla.Env{status: code} = env, false) when is_success(code), do: {:ok, env}
  def decode(%Tesla.Env{status: code, body: body}, struct) when is_success(code), do: Poison.decode(body, as: struct)
  def decode(response, _struct), do: {:error, response}

Investigate file upload definitions without request object

Some discovery documents do not specify a request type (e.g. Analytics).

 "response": {
  "$ref": "Upload"
 },
 "scopes": [
  "https://www.googleapis.com/auth/analytics",
  "https://www.googleapis.com/auth/analytics.edit"
 ],
 "supportsMediaUpload": true,
 "mediaUpload": {
  "accept": [
   "application/octet-stream"
  ],
  "maxSize": "1GB",
  "protocols": {
   "simple": {
    "multipart": true,
    "path": "/upload/analytics/v3/management/accounts/{accountId}/webproperties/{webPropertyId}/customDataSources/{customDataSourceId}/uploads"
   },
   "resumable": {
    "multipart": true,
    "path": "/resumable/upload/analytics/v3/management/accounts/{accountId}/webproperties/{webPropertyId}/customDataSources/{customDataSourceId}/uploads"
   }
  }
 }

It's not clear whether we should assume the request metadata should be the same as the response object ("Upload" in this case)

Improve generated code documentation

Hi there,

Even though it's not fully related to this repo, I think It's important to have nice and readable docs even for generated documentation.

You can see here that there are html tags and other artifacts that can be easily replaced with supported markdown syntax helpers.

This can be addressed by either improving code generator for https://github.com/swagger-api/swagger-codegen or by using custom code generator in this repo.

Add Cloud Tasks support

Please support the Google Cloud Tasks API, like it is supported by the Python library. Thank you!

Module names too long for Distillery

Hi, I'm using Distillery to package a release, but when I add

{:google_api_machine_learning, "~> 0.0.1"},

to my deps and then run MIX_ENV=prod mix release I get the following error.

==> Assembling release..
==> Building release gigalixir_getting_started:0.0.1 using environment prod
==> Including ERTS 8.3 from /home/js/.asdf/installs/erlang/19.3/lib/erlang/erts-8.3
==> Packaging release..
==> Release packaging failed due to errors:
    {{case_clause,
     {'EXIT',
         {function_clause,
             [{filename,join,[[]],[{file,"filename.erl"},{line,396}]},
              {erl_tar,split_filename,4,[{file,"erl_tar.erl"},{line,471}]},
              {erl_tar,create_header,3,[{file,"erl_tar.erl"},{line,400}]},
              {erl_tar,add1,4,[{file,"erl_tar.erl"},{line,323}]},
              {systools_make,add_to_tar,3,
                  [{file,"systools_make.erl"},{line,1907}]},
              {lists,foreach,2,[{file,"lists.erl"},{line,1338}]},
              {systools_make,'-add_applications/5-fun-0-',6,
                  [{file,"systools_make.erl"},{line,1597}]},
              {lists,foldl,3,[{file,"lists.erl"},{line,1263}]}]}}},
 [{systools_make,'-add_applications/5-fun-0-',6,
      [{file,"systools_make.erl"},{line,1597}]},
  {lists,foldl,3,[{file,"lists.erl"},{line,1263}]},
  {systools_make,add_applications,5,[{file,"systools_make.erl"},{line,1596}]},
  {systools_make,mk_tar,6,[{file,"systools_make.erl"},{line,1590}]},
  {systools_make,mk_tar,5,[{file,"systools_make.erl"},{line,1566}]},
  {systools_make,make_tar,2,[{file,"systools_make.erl"},{line,339}]},
  {'Elixir.Mix.Releases.Archiver',make_tar,1,
      [{file,"lib/mix/lib/releases/archiver.ex"},{line,64}]},
  {'Elixir.Mix.Releases.Archiver',archive,1,
      [{file,"lib/mix/lib/releases/archiver.ex"},{line,17}]}]}

I found the issue here which suggests that it is because some module names are too long. Indeed, I found some modules such as this one that are well over 100 characters.

Elixir.Poison.Encoder.GoogleApi.MachineLearning.V1.Model.GoogleCloudMlV1_HyperparameterOutput_HyperparameterMetric.beam

Is there anything that can be done about this?

Can scopes be a dictionary?

It would be great if the scopes could be:

  @scopes %{
    :cloud_platform => "https://www.googleapis.com/auth/cloud-platform", # View and manage your data across Google Cloud Platform services
    :cloud_platform_read_only => "https://www.googleapis.com/auth/cloud-platform.read-only", # View your data across Google Cloud Platform services
    :devstorage_full_control => "https://www.googleapis.com/auth/devstorage.full_control", # Manage your data and permissions in Google Cloud Storage
    :devstorage_read_only => "https://www.googleapis.com/auth/devstorage.read_only", # View your data in Google Cloud Storage
    :devstorage_read_write => "https://www.googleapis.com/auth/devstorage.read_write" # Manage your data in Google Cloud Storage
  ]

instead of

  @scopes [
    "https://www.googleapis.com/auth/cloud-platform", # View and manage your data across Google Cloud Platform services
    "https://www.googleapis.com/auth/cloud-platform.read-only", # View your data across Google Cloud Platform services
    "https://www.googleapis.com/auth/devstorage.full_control", # Manage your data and permissions in Google Cloud Storage
    "https://www.googleapis.com/auth/devstorage.read_only", # View your data in Google Cloud Storage
    "https://www.googleapis.com/auth/devstorage.read_write" # Manage your data in Google Cloud Storage
  ]

Standardize parameter order

When rebuilding APIs, sometimes the (optional) parameters ordering changes. This adds unnecessary noise when reviewing changes.

This is due to the fact that swagger-codegen and the api spec converter do not sort the parameters. The discovery endpoints can return discovery docs with differing ordering.

Issue with oauth and id tokens

I'm having a hard time getting the same error as #26 when trying to use GoogleApi.OAuth2.V2.Api.Default.oauth2_tokeninfo

When switching to hackney i get

<b>411.</b> <ins>That’s an error.</ins>\n  <p>POST requests require a <code>Content-length</code> header.  <ins>That’s all we know.</ins>\n

Headers

  headers: %{
     "content-length" => "1564",
     "content-type" => "text/html; charset=UTF-8",
     "date" => "Sun, 13 May 2018 02:51:41 GMT",
     "referrer-policy" => "no-referrer"
   },

Code

GoogleApi.OAuth2.V2.Api.Default.oauth2_tokeninfo(GoogleApi.OAuth2.V2.Connection.new, id_token: id_token, oauth_token: google_client_id)

Firestore batchGet decoding breaks

When retrieving documents from the batchGet endpoint it returns a body as such:

"[{\n  \"found\": {\n    \"name\": \"projects/xxxxx/databases/(default)/documents/xxxxx\",\n    \"fields\": {...},\n    \"createTime\": \"2018-xxxxxxxZ\",\n    \"updateTime\": \"2018-xxxxxxxZ\"\n  },\n  \"readTime\": \"2018-xxxxxxxZ\"\n}\n]"

When reaching the decoder here it breaks because of the brackets the body is wrapped in when getting here because of this.

calendar_events_insert "Missing end time"

Im trying to create an event, but get the response:
"Missing end time."

event = %{
      "start" => %{"dateTime" => Timex.now},
      "end" => %{"dateTime" => Timex.now |> Timex.shift(minutes: 15)},
      "summary" => event_name
    }

    {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/calendar")
    calendar_api = GoogleApi.Calendar.V3.Connection.new(token.token)

    GoogleApi.Calendar.V3.Api.Events.calendar_events_insert(calendar_api, "primary", [body: Poison.encode!(event)])

The event looks like this once encoded:
{ "summary": "hello world!", "start": { "dateTime": "2018-05-12T16:10:59.156000Z" }, "end": { "dateTime": "2018-05-12T16:25:59.161000Z" } }

works with the API explorer.

Sheets documentation

There's a lack of documentation in these client's,
I'm trying to use the google_api_sheets app...

Could you add more documentation, examples like, how to fetch a (private) google spreadsheet... ?

delete from STORAGE generates {:error, info} instead of {:ok, _}

Even that the deletion is successful, and server returns a HTTP 204 reponse, the correct tuple should be {:ok, _} instead {:error, info}

iex(23)>  Cloud.Storage.delete_file("jim-test", "z.txt")
** (MatchError) no match of right hand side value: {:error, %Tesla.Env{__client__: %Tesla.Client{fun: nil, post: [], pre: [{Tesla.Middleware.Headers, :call, [%{"Authorization" => "Bearer ya29.c.ElpXBc-zLbh7YmuuD8VLk0U0Hyc6vHbhau6iUydQ9Dlv1RFtuIQjwyMsePCTbZ27ClduezRONBHOYToP4P2S1tsN0olVv_3V0PyLnFhDMuIbawZwp6OwK6jmdaA"}]}]}, __module__: GoogleApi.Storage.V1.Connection, body: "", headers: %{"alt-svc" => "hq=\":443\"; ma=2592000; quic=51303431; quic=51303339; quic=51303338; quic=51303337; quic=51303335,quic=\":443\"; ma=2592000; v=\"41,39,38,37,35\"", "cache-control" => "no-cache, no-store, max-age=0, must-revalidate", "content-length" => "0", "content-type" => "application/json", "date" => "Sun, 04 Feb 2018 02:23:32 GMT", "expires" => "Mon, 01 Jan 1990 00:00:00 GMT", "pragma" => "no-cache", "server" => "UploadServer", "vary" => "Origin", "x-guploader-uploadid" => "AEnB2UobDiRXY-UCxHYq48Ij7y6Vqcc9mk8G8FG6TQDFtkLtWBonGgr2O4Uyq9uMRcjd1LILV6NhbsM67fAaH4mbzJjKdVk1bQ"}, method: :delete, opts: [], query: [], status: 204, url: "https://www.googleapis.com/storage/v1/b/jim-test/o/z.txt"}}
    (cloud) lib/storage/storage.ex:56: Cloud.Storage.delete_file/2

Better README

We need to update the README to be instructions on how to make calls with an API client, and move the build instructions to a different doc or wiki.

Translate API responses not deserializing properly due to wrapping

The response objects for the Translate V2 API are not deserializing properly. This is because the responses are wrapped in a data field. That is, the JSON response, instead of:

{
   "field1":"data1"
}

Instead looks like this:

{
  "data": {
    "field1":"data1"
  }
}

As far as I can tell (based on the Ruby Apiary client), this is controlled by the following property in the discovery doc:

{
  ...
  "features": [
    "dataWrapper"
  ],
  ...
}

And as far as I can tell, Translate V2 is the only API with this property.

Error in deserializer when receiving a list of buckets (STORAGE)

iex(18)> GoogleApi.Storage.V1.Api.Buckets.storage_buckets_list(conn, "my-project")
** (FunctionClauseError) no function clause matching in DateTime.from_iso8601/2

    The following arguments were given to DateTime.from_iso8601/2:

        # 1
        nil

        # 2
        Calendar.ISO

    (elixir) lib/calendar/datetime.ex:509: DateTime.from_iso8601/2
    (google_api_storage) lib/google_api/storage/v1/deserializer.ex:42: GoogleApi.Storage.V1.Deserializer.deserialize/5
    (elixir) lib/map.ex:734: Map.update!/3
    (poison) lib/poison/decoder.ex:24: anonymous fn/5 in Poison.Decode.transform/4
    (elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3 
    (poison) lib/poison/decoder.ex:24: Poison.Decode.transform/4
    (elixir) lib/map.ex:734: Map.update!/3
    (google_api_storage) lib/google_api/storage/v1/model/bucket.ex:61: Poison.Decoder.GoogleApi.Storage.V1.Model.Bucket.decode/2

Speech client references nonexistent `GoogleApi.Speech.V1.Model.Object`

Creating a longrunning recognize speech request currently errors when decoding the operation result.

** (UndefinedFunctionError) function GoogleApi.Speech.V1.Model.Object.__struct__/0 is undefined (module GoogleApi.Speech.V1.Model.Object is not available)
    GoogleApi.Speech.V1.Model.Object.__struct__()
    (google_api_speech) lib/google_api/speech/v1/deserializer.ex:36: anonymous fn/3 in GoogleApi.Speech.V1.Deserializer.deserialize/5
    (elixir) lib/map.ex:727: Map.update!/3
    (google_api_speech) lib/google_api/speech/v1/model/operation.ex:47: Poison.Decoder.GoogleApi.Speech.V1.Model.Operation.decode/2
    (poison) lib/poison.ex:70: Poison.decode/2

GoogleApi.Speech.V1.Model.Operation attempts to deserialize metadata and the response with GoogleApi.Speech.V1.Model.Object, which doesn't exist.

The operation documentation references object. I'm not too familiar with Swagger/OpenAPI, so I'm not sure if the issue lies in the schema or the Elixir code generation.

Storage: URI encoding fails for spaces

Hi!

Elixir's URI.encode_www_form is used throughout this client library. Unfortunately this fails for Storage Object names containing spaces. Apparently, this is because encode_www_form has special handling for spaces and replaces it with a + instead of the expected percent-encoded %20.

This seems to be the wanted encoding method:

iex> URI.encode("some/path/File with späces.zip", &URI.char_unreserved?/1)
"some%2Fpath%2FFile%20with%20sp%C3%A4ces.zip"

I am not sure if a change to the generator template would affect the other APIs, but that would appear to be the easiest way to fix this.

DataStore Sample

For petes sake can you include a sample entity fetch and query. Inline code documentation is fairly robust but end users shoudn't need to pour over module definitions to figure out the module responsible for running queries, the setup needed to get it to work and how to setup a basic call.

;)

Codegen should create the LICENSE file

Currently, the swagger codegen doesn't create the LICENSE file which is necessary for both copyright and to publish to hex (a declared file in the mix.exs)

Decide how to tombstone removed APIs

  • CloudMonitoring
  • CloudUserAccounts
  • ConsumerSurveys
  • PlayMoviesPartner
  • Prediction
  • QpxExpress
  • ResourceViews
  • TaskQueue

are all turned-down services where the APIs will no longer function.

Can someone provide an example?

Sorry for the basic question, but I cant get Firestore to work. In my IEX session, I type the following:

iex(16)> GoogleApi.Firestore.V1beta1.Api.Projects.firestore_projects_databases_documents_list(
...(16)> (GoogleApi.Firestore.V1beta1.Connection),
...(16)> "projects/rndm-49de0/databases/(default)",
...(16)> "thoughts",
...(16)> [oauth_token: "my_oauth_key.apps.googleusercontent.com"])

I Get the following errors:

** (FunctionClauseError) no function clause matching in GoogleApi.Gax.Request.add_optional_params/3

The following arguments were given to GoogleApi.Gax.Request.add_optional_params/3:

    # 1
    %GoogleApi.Gax.Request{
      body: [],
      file: [],
      header: [],
      method: :get,
      query: [],
      url: "/v1beta1/projects/rndm-49de0/databases/(default)/thoughts"
    }

    # 2
    %{
      "$.xgafv": :query,
      access_token: :query,
      alt: :query,
      callback: :query,
      fields: :query,
      key: :query,
      "mask.fieldPaths": :query,
      oauth_token: :query,
      orderBy: :query,
      pageSize: :query,
      pageToken: :query,
      prettyPrint: :query,
      quotaUser: :query,
      readTime: :query,
      showMissing: :query,
      transaction: :query,
      uploadType: :query,
      upload_protocol: :query
    }

    # 3
    [:oauth_token,
     "my_oauth_token.apps.googleusercontent.com"]

Attempted function clauses (showing 2 out of 2):

    def add_optional_params(request, _, [])
    def add_optional_params(request, definitions, [{key, value} | tail])

(google_gax) lib/google_api/gax/request.ex:116: GoogleApi.Gax.Request.add_optional_params/3
(google_api_firestore) lib/google_api/firestore/v1beta1/api/projects.ex:350: GoogleApi.Firestore.V1beta1.Api.Projects.firestore_projects_databases_documents_list/4

not sure if this is the right place to ask this question, but Im at a standstill until I figure this out. Any help would be appreciated. Thanks in advance.

FunctionClauseError when creating session using Spanner API

Steps to Reproduce:

> connection = GoogleApi.Spanner.V1.Connection.new("some-access-token")
> GoogleApi.Spanner.V1.Api.Projects.spanner_projects_instances_databases_sessions_create(connection, "some-database")

Error:

** (FunctionClauseError) no function clause matching in :httpc.request/5    
    
    The following arguments were given to :httpc.request/5:
    
        # 1
        :post
    
        # 2
        {'https://spanner.googleapis.com/v1/projects/cp100-198217instances/test-instance/databases/test-database/sessions',
         [
           {'authorization',
            'Bearer ya29.c.ElqGBVEgAdjJQ_TJ9yUkX91rbTOLpuJo_16dDoarmho8rEzLp0lYzoFSbFSP5h8Ol8OeaEcewVp7CY-nW01B8kj-rDAssoMu3DhdLMumLML7lXQeXEjfdOH9zp8'},
           {'user-agent', 'Elixir'}
         ]}
    
        # 3
        [autoredirect: false]
    
        # 4
        []
    
        # 5
        :default
    
    (inets) httpc.erl:149: :httpc.request/5
    (tesla) lib/tesla/adapter/httpc.ex:32: Tesla.Adapter.Httpc.request/2
    (tesla) lib/tesla/adapter/httpc.ex:19: Tesla.Adapter.Httpc.call/2
    (tesla) lib/tesla/middleware/core.ex:6: Tesla.Middleware.Normalize.call/3
    (google_api_spanner) lib/google_api/spanner/v1/api/projects.ex:764: GoogleApi.Spanner.V1.Api.Projects.spanner_projects_instances_databases_sessions_create/3

I also tried
GoogleApi.Spanner.V1.Api.Projects.spanner_projects_instances_databases_sessions_create(connection, "projects/cp100-198217instances/test-instance/databases/test-database", [body: %GoogleApi.Spanner.V1.Model.Empty{}])
which doesn't work either.

It seems that it's missing a request body for the POST request.

One way to fix the problem is to add
:"body"=> :body
in the optional parameters here: https://github.com/GoogleCloudPlatform/elixir-google-api/blob/master/clients/spanner/lib/google_api/spanner/v1/api/projects.ex#L742

With this fix, the following code will work:
GoogleApi.Spanner.V1.Api.Projects.spanner_projects_instances_databases_sessions_create(connection, "projects/cp100-198217instances/test-instance/databases/test-database", [body: %GoogleApi.Spanner.V1.Model.Empty{}])

File uploads not functional

  • Tesla client does not yet support multipart file upload, but a pull request is in progress. See: elixir-tesla/tesla#87
  • Google Discovery -> OpenApi specification conversion loses data about upload types and paths

This currently affects the following APIs:

  • Analytics
  • AndroidPublisher
  • BigQuery
  • ChromeWebStore
  • DFAReporting
  • Discovery
  • Drive
  • FusionTables
  • GamesConfiguration
  • Gmail
  • GroupsMigration
  • Mirror
  • PlayCustomApp
  • PlusDomains
  • Storage
  • YouTube

get {:ok, ...} when in fact it was an insert error

We get

{:ok,   
 %GoogleApi.BigQuery.V2.Model.TableDataInsertAllResponse{
   insertErrors: [
     %GoogleApi.BigQuery.V2.Model.TableDataInsertAllResponseInsertErrors{
       errors: [
         %GoogleApi.BigQuery.V2.Model.ErrorProto{
           debugInfo: "",
           location: "amount",
           message: "no such field.",
           reason: "invalid"
         }
       ],
       index: 0
     }
   ],
   kind: "bigquery#tableDataInsertAllResponse"
 }}

when trying to insert, but in fact, the data were not inserted, and the message should be
{:error, reason}

CalendarApi.Events.calendar_events_list wrong documentation

GoogleApi.Calendar.V3.Api.Events.calendar_events_list optional parameter: privateExtendedProperty: is of type String.t but docs specify [String.t] (with list)

using the list version will cause the url to look like this:
?privateExtendedProperty%5b%5d=x%3Dx
notice the %5b%5d after the parameter name.

GoogleApi just ignores this parameter.

Strange error at httpc layer

Getting the following error when making a very simple elixir call:

iex(1)> GoogleApi.PubSub.Samples.create_topic("elixir-samples", "test-topic") 
** (FunctionClauseError) no function clause matching in :httpc.request/5    
    
    The following arguments were given to :httpc.request/5:
    
        # 1
        :put
    
        # 2
        {'https://pubsub.googleapis.com/v1/projects/elixir-samples/topics/test-topic',
     [{'authorization',
       'Bearer ya29.ElrcBL7642bylIYc01Ili5grvhVG8T0W2xC9HAcVLZifRnBWNBmqb2in-Q087flQPVkmL9JV0wMwtEeU8M5043UifxcKIYkXdQswTSQK_cFJXtyyaLHxcPyjLDc'},
      {'user-agent', 'Elixir'}]}
    
        # 3
        [autoredirect: false]
    
        # 4
        []
    
        # 5
        :default
    
    (inets) httpc.erl:149: :httpc.request/5
    (tesla) lib/tesla/adapter/httpc.ex:30: Tesla.Adapter.Httpc.request/2
    (tesla) lib/tesla/adapter/httpc.ex:17: Tesla.Adapter.Httpc.call/2
    (tesla) lib/tesla/middleware/core.ex:5: Tesla.Middleware.Normalize.call/3
    (google_api_pub_sub) lib/google_api/pub_sub/v1/api/projects.ex:858: GoogleApi.PubSub.V1.Api.Projects.pubsub_projects_topics_create/4
    (pubsub_sample) lib/pubsub_samples.ex:21: GoogleApi.PubSub.Samples.create_topic/2

The code that throws the error is from google_api_pub_sub, and looks like this:

{:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
conn = GoogleApi.PubSub.V1.Connection.new(token.token)

# Make the API request.
{:ok, response} = GoogleApi.PubSub.V1.Api.Projects.pubsub_projects_topics_create(
  conn,
  project_id,
  topic_name
)

EventDateTime decoder will not decode when date is null

When creating an event in the calendar api the response contains an Event which contains EventDateTime.
Inside it, thers an optional field called "date"
for some reason, EventDateTime decoder will try to deserialize the date explicitly

defimpl Poison.Decoder, for: GoogleApi.Calendar.V3.Model.EventDateTime do
  import GoogleApi.Calendar.V3.Deserializer
  def decode(value, options) do
    value
    |> deserialize(:"date", :date, nil, options)
  end
end

but there is no deserialize function with nil 3rd argument in calendar/deserializer.ex

By adding one, I managed to get the code to work.
Thats not a fix though, I need the generator to do that automatically.. And im not sure how the code works.

connection error in Storage api

Hi, i'm getting this error when using service authentication.
I'm calling this in my code like this as specified in the repo.
I have exported the variable using: export GOOGLE_APPLICATION_CREDENTIALS=/path_to_jsonfile
can someone please help, why this is happening.

 {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform") #works fine
 conn = GoogleApi.Storage.V1.Connection.new(token.token)

[error] #PID<0.699.0> running ParserWeb.Endpoint (cowboy_protocol) terminated
Server: localhost:4000 (http)
Request: GET /api/v1/start/1111/2222
** (exit) an exception was raised:
** (KeyError) key :status not found in: %Tesla.Client{fun: nil, post: [], pre: [{Tesla.Middleware.Headers, :call, [%{"Authorization" => "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}]}
(phoenix) lib/phoenix/controller.ex:367: Phoenix.Controller.text/2
(parser) lib/parser_web/controllers/page_controller.ex:1: ParserWeb.PageController.action/2
(parser) lib/parser_web/controllers/page_controller.ex:1: ParserWeb.PageController.phoenix_controller_pipeline/2
(parser) lib/parser_web/endpoint.ex:1: ParserWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(parser) lib/parser_web/endpoint.ex:1: ParserWeb.Endpoint.plug_builder_call/2
(parser) lib/plug/debugger.ex:102: ParserWeb.Endpoint."call (overridable 3)"/2
(parser) lib/parser_web/endpoint.ex:1: ParserWeb.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:16: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /home/baldor/df/parser/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

Add Firestore support

Right now the firestore isn't supported in the sdk. This PR adds support for it: #60

I think it would be great to merge it and allow support for Firestore in the sdk.

mix google_apis.fetch fails because Google Webstore endpoint 404s

when I run mix google_apis.fetch, I get an error.

 > mix google_apis.fetch
18:16:23.936 [info]  FOUND: https://acceleratedmobilepageurl.googleapis.com/$discovery/rest?version=v1
18:16:24.091 [info]  FOUND: https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.4/rest
18:16:24.279 [info]  FOUND: https://adexchangebuyer.googleapis.com/$discovery/GOOGLE_REST_SIMPLE_URI?version=v2beta1
[clipped]
18:16:45.640 [info]  FOUND: https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest
** (MatchError) no match of right hand side value: {:error, "Error received status: 404 from discovery endpoint"}
    lib/google_apis/discovery.ex:23: GoogleApis.Discovery.fetch/1
    lib/google_apis.ex:54: GoogleApis.fetch/1
    (elixir) lib/enum.ex:675: Enum."-each/2-lists^foreach/1-0-"/2
    (elixir) lib/enum.ex:675: Enum.each/2
    (mix) lib/mix/task.ex:301: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:75: Mix.CLI.run_task/2

I don't think it's calendar, but the webstore api, that's missing. hitting this url confirms: https://www.googleapis.com/discovery/v1/apis/chromewebstore/v1.1/rest

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.