diff --git a/.gitignore b/.gitignore index 8b633e1..e8d2c10 100755 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,7 @@ examples/*.png **/delme* *.json docs/cover/* + +.yath.user.rc +.*.sw? +.perl-version diff --git a/.perltidyrc b/.perltidyrc index d0c1d65..737e532 100644 --- a/.perltidyrc +++ b/.perltidyrc @@ -1,16 +1,17 @@ --pbp -nst # Start with Perl Best Practices - not sure how to drive and cuddles my braces --w # Show all warnings --iob # Ignore old breakpoints --l=180 # 80 characters per line --mbl=2 # No more than 2 blank lines --i=2 # Indentation is 2 columns --ci=2 # Continuation indentation is 2 columns --vt=0 # vertical tightness --pt=0 # parenthesis tightness --bt=0 # brace tightness --sbt=2 # square bracket tightness --wn # Weld nested containers --isbc # Don't indent comments without leading space --sbl # sub-brace on new line --bl # Opening Braces Left --b -bext='/' # operwrite the file and delete backup if no errors +--warning-output +--ignore-old-breakpoints +--maximum-line-length=80 +--maximum-consecutive-blank-lines=2 +--indent-columns=2 +--continuation-indentation=2 +--vertical-tightness=0 +--paren-tightness=2 +--brace-tightness=1 +--square-bracket-tightness=2 +--weld-nested-containers +--indent-spaced-block-comments +--cuddled-else +--trim-qw +--opening-brace-always-on-right +--opening-token-right +-b # overwrite the file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9de084..9ee7946 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,24 @@ +# When hacking on this repo + +There are some live tests in `xt/` which require real user credentials. All they +do is create a file in Google Drive, and then delete it, in order to make sure that +things are ACTUALLY running. + +If you don't trust me, then please don't run those tests. They're part of the +release process, so I'll just run them before releasing. + +If you DO trust me (and I'm flattered), then you need to set the +`GAPI_XT_USER_CREDS` environment variable to a string containing the gapi.json +file, followed by `:` followed by the user to user. Like this: + + /absolute/path/to/gapi.json:your_email@gmail.com + +And also set the `GAPI_XT_SERVICE_CREDS` to the service account file downloaded +from Google. + # Bug Reporting and General Help Requests -- Use the [Github Issues Page](https://github.com/pscott-au/WebService-GoogleAPI-Client/issues) +- Use the [Github Issues Page](https://github.com/rabbiveesh/WebService-GoogleAPI-Client/issues) ## Github Repo Management @@ -10,8 +28,6 @@ # CONTRIBUTING CODE -- Use perlcritic and perltidy if my bracer style is offensive -- This is my first module using dzilla to package a module - I'm not completely sold on it and may be using it incorrectly - advice on improving usage welcome - There remain a few architectural bad smells from the original source code this was based on - don't assume that the class structure is sane - Pull reqeusts preferred but whatever works for you I will try to work with @@ -21,11 +37,11 @@ - refactor to improve test coverage - clean up the test structure - survey other Google Perl modules -- explore handling of batch requests +- implement batch requests - really an interface question more than the + technicalities - API worked examples with help functions - ability to examine CHI cache and introspect on Client instance metrics ( number of HTTP calls, cache size, TTL data sent/received etc ) - comparison with other language Client libraries -- The structure under the AuthStorage is ugly and needs some love Github Repo: [https://github.com/pscott-au/WebService-GoogleAPI-Client] diff --git a/Changes b/Changes new file mode 100644 index 0000000..387f7d3 --- /dev/null +++ b/Changes @@ -0,0 +1,14 @@ +{{$NEXT}} + +ENHANCEMENTS +- add support for service accounts +- rework storage backend to allow custom implementations (here's looking at you, redis) +- allow introspection for credentials on $res returned from an api query + +BREAKING CHANGES +- will immediately on non-existent API endpoints +- rework AuthStorage classes: anything that depended on + ::AuthStorage or ::Credentials in an undocumented way will likely explode. + Please open an issue on github and I'll try and help you migrate +- remove some undocumented options +- the examples/ dir MAY be broken, I didn't check (they need cleaning up anyways) diff --git a/README.md b/README.md index df612c0..5526a79 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ I was unable to get the [Dist::Zilla](https://metacpan.org/pod/Dist::Zilla) pack my $gapi = WebService::GoogleAPI::Client->new(debug => 0); ## This idiom selects the first authorised user from gapi.json - my $aref_token_emails = $gapi->auth_storage->storage->get_token_emails_from_storage; + my $aref_token_emails = $gapi->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; print "Running tests with default user email = $user\n"; $gapi->user($user); @@ -222,7 +222,7 @@ See the examples folder for specific access examples. - API Discovery with local caching using [CHI](https://metacpan.org/pod/CHI) File - OAUTH app credentials (client\_id, client\_secret, users access\_token && refresh\_token) storage stored in local gapi.json file - Automatic access\_token refresh (if user has refresh\_token) and saving refreshed token to storage -- CLI tool ([go_auth](https://metacpan.org/pod/distribution/WebService-GoogleAPI-Client/bin/goauth)) with lightweight HTTP server to simplify config OAuth2 configuration, sccoping, authorization and obtaining access\_ and refresh\_ tokens +- CLI tool ([goauth](https://metacpan.org/pod/distribution/WebService-GoogleAPI-Client/bin/goauth)) with lightweight HTTP server to simplify config OAuth2 configuration, sccoping, authorization and obtaining access\_ and refresh\_ tokens # SEE ALSO diff --git a/README.txt b/README.txt index 81e90ec..177a6cd 100644 --- a/README.txt +++ b/README.txt @@ -4,16 +4,17 @@ NAME VERSION - version 0.21 + version 0.23 SYNOPSIS - Access Google API Services Version 1 using an OAUTH2 User Agent. + Access Google API Services using an OAUTH2 User Agent. - Includes Discovery, validation authentication and API Access. + Includes Discovery, validation, authentication and API Access. - assumes gapi.json configuration in working directory with scoped Google - project redentials and user authorization created by _goauth_ + By default assumes gapi.json configuration in working directory with + scoped Google project credentials and user authorization created by + goauth. use WebService::GoogleAPI::Client; @@ -27,11 +28,13 @@ SYNOPSIS say 'User has Access to GMail Method End-Point gmail.users.settings.sendAs.get'; } - Internal User Agent provided be property - WebService::GoogleAPI::Client::UserAgent dervied from Mojo::UserAgent + Package includes goauth CLI Script to collect initial end-user + authorisation to scoped services. - Package includes go_auth CLI Script to collect initial end-user - authorisation to scoped services + Note to intrepid hackers: Any method that isn't documented is + considered private, and subject to change in breaking ways without + notice. (Although I'm a pretty nice guy, and probably will leave a + warning or something). EXAMPLES @@ -42,18 +45,21 @@ EXAMPLES use MIME::Base64; my $my_email_address = 'peter@shotgundriver.com' + my $raw_email_payload = encode_base64( + Email::Simple->create( + header => [ + To => $my_email_address, + From => $my_email_address, + Subject => "Test email from '$my_email_address' ", + ], + body => "This is the body of email to '$my_email_address'", + )->as_string + ); - my $raw_email_payload = encode_base64( Email::Simple->create( header => [To => $my_email_address, - From => $my_email_address, - Subject =>"Test email from '$my_email_address' ",], - body => "This is the body of email to '$my_email_address'", - )->as_string - ); - - $gapi_client->api_query( - api_endpoint_id => 'gmail.users.messages.send', - options => { raw => $raw_email_payload }, - ); + $gapi_client->api_query( + api_endpoint_id => 'gmail.users.messages.send', + options => { raw => $raw_email_payload }, + ); MANUAL API REQUEST CONSTRUCTION - GET CALENDAR LIST @@ -67,20 +73,70 @@ METHODS new - WebService::GoogleAPI::Client->new( user => 'peter@pscott.com.au', gapi_json => '/fullpath/gapi.json' ); + WebService::GoogleAPI::Client->new( + user => 'peter@pscott.com.au', gapi_json => '/fullpath/gapi.json' ); + + General parameters + + debug + + if truthy then diagnostics are send to STDERR - default false. Crank + it up to 11 for maximal debug output + + chi + + an instance to a CHI persistent storage case object - if none + provided FILE is used + + Login Parameters + + You can use either gapi_json, which is the file you get from using the + bundled goauth tool, or service_account which is the json file you can + download from + https://console.cloud.google.com/iam-admin/serviceaccounts. + + service_account and gapi_json are mutually exclusive, and gapi_json + takes precedence. - PARAMETERS + If nothing is passed, then we check the GOOGLE_APPLICATION_CREDENTIALS + env variable for the location of a service account file. This matches + the functionality of the Google Cloud libraries from other languages + (well, somewhat. I haven't fully implemented ADC yet - see Google's + Docs for some + details. PRs are welcome!) - user :: the email address that identifies key of credentials in the - config file + If that doesn't exist, then we default to gapi.json in the current + directory. - gapi_json :: Location of the configuration credentials - default - gapi.json + Be wary! This default is subject to change as more storage backends are + implemented. A deprecation warning will be emmitted when this is likely + to start happening. - debug :: if '1' then diagnostics are send to STDERR - default false + For more advanced usage, you can supply your own auth storage instance, + which is a consumer of the WebService::GoogleAPI::Client::AuthStorage + role. See the POD for that module for more information. - chi :: an instance to a CHI persistent storage case object - if none - provided FILE is used + user + + the email address that requests will be made for + + gapi_json + + Location of end user credentials + + service_account + + Location of service account credentials + + auth_storage + + An instance of a class consuming + WebService::GoogleAPI::Client::AuthStorage, already set up for + returning access tokens (barring the ua). + + If you're using a service account, user represents the user that you're + impersonating. Make sure you have domain-wide delegation set up, or + else this won't work. api_query @@ -91,9 +147,9 @@ METHODS Required params: method, route - Optional params: api_endpoint_id cb_method_discovery_modify + Optional params: api_endpoint_id cb_method_discovery_modify, options - $self->access_token must be valid + $self->get_access_token must return a valid token $gapi->api_query({ method => 'get', @@ -109,50 +165,112 @@ METHODS ## if provide the Google API Endpoint to inform pre-query validation say $gapi_agent->api_query( api_endpoint_id => 'gmail.users.messages.send', - options => { raw => encode_base64( - Email::Simple->create( header => [To => $user, From => $user, Subject =>"Test email from $user",], - body => "This is the body of email from $user to $user", )->as_string - ), - }, - )->to_string; ## + options => + { raw => encode_base64( Email::Simple->create( + header => [To => $user, From => $user, + Subject =>"Test email from $user",], + body => "This is the body of email from $user to $user", + )->as_string ), + }, + )->to_string; ## print $gapi_agent->api_query( - api_endpoint_id => 'gmail.users.messages.list', ## auto sets method to GET, path to 'https://www.googleapis.com/calendar' + api_endpoint_id => 'gmail.users.messages.list', + ## auto sets method to GET, and the path to + ## 'https://www.googleapis.com/gmail/v1/users/me/messages' )->to_string; - #print pp $r; - - - if the pre-query validation fails then a 418 - I'm a Teapot error response is returned with the - body containing the specific description of the errors ( Tea Leaves ;^) ). + + If the pre-query validation fails then a 418 - I'm a Teapot error + response is returned with the body containing the specific description + of the errors ( Tea Leaves ;^) ). + + Dealing with inconsistencies NB: If you pass a 'path' parameter this takes precendence over the API Discovery Spec. Any parameters defined in the path of the format {VARNAME} will be filled in with values within the options=>{ VARNAME => 'value '} parameter structure. This is the simplest way of addressing issues where the API discovery spec is inaccurate. ( See - dev_sheets_example.pl as at 14/11/18 for illustration ) + dev_sheets_example.pl as at 14/11/18 for illustration ). This + particular issue has been since solved, but you never know where else + there are problems with the discovery spec. + + Sometimes, Google is slightly inconsistent about how to name the + parameters. For example, error messages sent back to the user tend to + have the param names in snake_case, whereas the discovery document + always has them in camelCase. To address this issue, and in the DWIM + spirit of perl, parameters may be passed in camelCase or snake_case. + That means that + + $gapi_agent->api_query( + api_endpoint_id => 'gmail.users.messages.list', + options => { userId => 'foobar' }); + + and + + $gapi_agent->api_query( + api_endpoint_id => 'gmail.users.messages.list', + options => { user_id => 'foobar' }); + + will produce the same result. + + Sometimes a param expects a dynamic part and a static part. The + endpoint jobs.projects.jobs.list, for example, has a param called + 'parent' which has a format '^projects/[^/]+$'. In cases like this, you + can just skip out the constant part, making + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.list', + options => { parent => 'sner' } ); + + and - To allow the user to fix discrepencies in the Discovery Specification - the cb_method_discovery_modify callback can be used which must accept - the method specification as a parameter and must return a (potentially + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.list', + options => { parent => 'projects/sner' } ); + + the same. How's that for DWIM? + + In addition, you can use different names to refer to multi-part + parameters. For example, the endpoint jobs.projects.jobs.delete + officially expects one parameter, 'name'. The description for the param + tells you that you it expects it to contain 'projectsId' and 'jobsId'. + For cases like this, + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.delete', + options => {name => 'projects/sner/jobs/bler'} ); + + and + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.delete', + options => {projectsId => 'sner', jobsId => 'bler'} ); + + will produce the same result. Note that for now, in this case you can't + pass the official param name without the constant parts. That may + change in the future. + + To further fix discrepencies in the Discovery Specification, the + cb_method_discovery_modify callback can be used which must accept the + method specification as a parameter and must return a (potentially modified) method spec. eg. - my $r = $gapi_client->api_query( api_endpoint_id => "sheets:v4.spreadsheets.values.update", - options => { - spreadsheetId => '1111111111111111111', - valueInputOption => 'RAW', - range => 'Sheet1!A1:A2', - 'values' => [[99],[98]] - }, - cb_method_discovery_modify => sub { - my $meth_spec = shift; - $meth_spec->{parameters}{valueInputOption}{location} = 'path'; - $meth_spec->{path} = "v4/spreadsheets/{spreadsheetId}/values/{range}?valueInputOption={valueInputOption}"; - return $meth_spec; - } - ); + my $r = $gapi_client->api_query( + api_endpoint_id => "sheets:v4.spreadsheets.values.update", + options => { + spreadsheetId => '1111111111111111111', + valueInputOption => 'RAW', + range => 'Sheet1!A1:A2', + 'values' => [[99],[98]] + }, + cb_method_discovery_modify => sub { + my $meth_spec = shift; + $meth_spec->{parameters}{valueInputOption}{location} = 'path'; + $meth_spec->{path} .= "?valueInputOption={valueInputOption}"; + return $meth_spec; + } + ); + + Again, this specific issue has been fixed. Returns Mojo::Message::Response object @@ -219,14 +337,14 @@ METHODS DELEGATED TO WebService::GoogleAPI::Client::Discovery } print dump $new_hash->{gmail}; - get_api_discovery_for_api_id + get_api_document returns the cached version if avaiable in CHI otherwise retrieves discovery data via HTTP, stores in CHI cache and returns as a Perl data structure. - my $hashref = $self->get_api_discovery_for_api_id( 'gmail' ); - my $hashref = $self->get_api_discovery_for_api_id( 'gmail:v3' ); + my $hashref = $self->get_api_document( 'gmail' ); + my $hashref = $self->get_api_document( 'gmail:v3' ); returns the api discovery specification structure ( cached by CHI ) for api id ( eg 'gmail ') @@ -242,9 +360,9 @@ METHODS DELEGATED TO WebService::GoogleAPI::Client::Discovery methods_available_for_google_api_id('gmail') - extract_method_discovery_detail_from_api_spec + get_method_details - $my $api_detail = $gapi->discovery->extract_method_discovery_detail_from_api_spec( 'gmail.users.settings' ); + $my $api_detail = $gapi->discovery->get_method_details( 'gmail.users.settings' ); returns a hashref representing the discovery specification for the method identified by $tree in dotted API format such as @@ -252,16 +370,18 @@ METHODS DELEGATED TO WebService::GoogleAPI::Client::Discovery returns an empty hashref if not found - list_of_available_google_api_ids + list_api_ids Returns an array list of all the available API's described in the API Discovery Resource that is either fetched or cached in CHI locally for 30 days. - my $r = $agent->list_of_available_google_api_ids(); + my $r = $agent->list_api_ids(); print "List of API Services ( comma separated): $r\n"; - my @list = $agent->list_of_available_google_api_ids(); + my @list = $agent->list_api_ids(); + + To check for just one service id, use service_exists instead. FEATURES @@ -281,13 +401,15 @@ FEATURES OAuth2 configuration, sccoping, authorization and obtaining access_ and refresh_ tokens from users -AUTHOR +AUTHORS + + * Veesh Goldman - Peter Scott + * Peter Scott COPYRIGHT AND LICENSE - This software is Copyright (c) 2017-2018 by Peter Scott and others. + This software is Copyright (c) 2017-2021 by Peter Scott and others. This is free software, licensed under: diff --git a/TODO b/TODO new file mode 100644 index 0000000..2c0e1f5 --- /dev/null +++ b/TODO @@ -0,0 +1,49 @@ +# vim: ft=markdown + +# Make this more idiomatic + +Allow users to make requests like this + $gapi->api_query('drive.files.list', $options) + +Allow boolean values to be coerced from truthy or falsy values (except for +explicit false) + +#Other Issues + +## Less logic on repeated calls + +We'd like to implement a cache for constructing calls, b/c it +works WAAAY too hard. Constructing 100 calls to +sheets.spreadsheets.values.batchGetByDataFilter made my CPU churn +like a tell, and for way too long, too. + +Maybe even go for dynamic class creation, similar to what OpenAPI +producers use. Although I'm thinking of just moving over to using +gRPC, which does actually have a perl client (seemingly). + +It just hit me that it could be some of the slowness comes from checking that +you're authenticated for the request. + + +## Encapsulate logic better + +I'd like to abstract the interpolation and crud into a seperate +module, so that I could use it to make the inner requests for a +batch request. + +## Use generators instead + +I'd like to implement generators for the main ua, and use that as +an interface for adding the headers and crud. The only reason to +not use the 'start' hook is b/c we don't want our auth stuff on a +request for a token. Unless it doesn't matter... + +We need some live tests that we'll put in the xt directory, so +that we can be sure that when it's live things work. + +## Test suite is filled with garbage + +We must fix all the weird warnings in the test suite, and improve +our coverage and stuff. + +Move everything to Test2. diff --git a/bin/goauth b/bin/goauth index abab602..24101b7 100755 --- a/bin/goauth +++ b/bin/goauth @@ -4,26 +4,23 @@ use strictures; package goauth; +# VERSION + use Carp; use Mojolicious::Lite; -use Path::Class; use Config::JSON; -use Tie::File; use feature 'say'; use Net::EmptyPort qw(empty_port); -use Crypt::JWT qw(decode_jwt); - - - # ABSTRACT: CLI tool with mini http server for negotiating Google OAuth2 Authorisation access tokens that allow offline access to Google API Services on behalf of the user. =pod =head2 SUMMARY -Supports multiple users -OAuth2 for Google. You can find the key (CLIENT ID) and secret (CLIENT SECRET) from the app console here under "APIs & Auth" and "Credentials" in the menu at https://console.developers.google.com/project . +Supports multiple users OAuth2 for Google. You can find the key (CLIENT ID) and +secret (CLIENT SECRET) from the app console here under "APIs & Auth" and +"Credentials" in the menu at https://console.developers.google.com/project. Included as a utility within the CPAN L Bundle. @@ -38,39 +35,68 @@ Optionally you can provide an alternate filename to the default gapi.json as a p goauth my_differently_named_gapi.json -Once installed as part of the WebService::GoogleAPI::Client bundle, this tool can be run from the command line to configure a Google Project to access a Project -configuration that allows authenticated and authorised users to grant permission to access Google API services on their data (Email, Files etc) to the extent -provided by the Access Scopes for the project and the auth tokens. +Once installed as part of the WebService::GoogleAPI::Client bundle, this tool +can be run from the command line to configure a Google Project to access a +Project configuration that allows authenticated and authorised users to grant +permission to access Google API services on their data (Email, Files etc) to the +extent provided by the Access Scopes for the project and the auth tokens. -In order to successfully run _go_auth_ for the first time requires the following Google Project configuration variables: -Client ID -Client Secret -List of Scopes to request access to on behalf of users ( must be a subset of those enabled for the project. ) +In order to successfully run C for the first time requires the following +Google Project configuration variables: -If not already available in the gapi.json file, you will be prompted to supply these as the file is created. +=begin :list -Once this configuration is complete, the go_auth tool will launch a mini HTTP server to provide an interface to request users to authorise your project application. += * Client ID -NB: To run successfully your Google Project must be configured to accept requests from the domain. For initial testing ensure that you include localhost in your allowed domains. += * Client Secret -Once you have succesfully created a gapi.json file and ahve authenticated a user that is represented in this file then use WebServices::Google::Client -to start making Google API Requests. += * List of Scopes to request access to on behalf of users ( must be a subset of those enabled for the project. ) - perldoc WebServices::Google::Client for more detail. +=end :list +You must also add whatever URL you end up accessing C from as a valid +Redirect URI in your Google Cloud Console. You can get there from +L, and then clicking edit on +the OAuth Client ID that you're using for this project. -=head2 gapi.json +You need to add something like + + http://localhost:3001/ + +with the port number set to whichever C ends up picking. (This is +assuming that you typed C in your browser when you opened +it, it won't work if you typed in C<127.0.0.1:3001>). -The ultimate output of this is the gapi.json file that contains both the Google Project Specification as well as the authorised user access tokens. -The file describes a set of scopes that must all be configured as available to the Project through the Google Admin Console. -You may have multiple gapi.json files for the same project containing a different subset of scopes. -The gapi.json file also contains the authorisation tokens granted by users. Multiple users can be described within a single gapi.json file. -If users exist across multiple gapi.json files for the same project then (I believe) only the most recently granted set of scopes will be usable. +If not already available in the gapi.json file, you will be prompted to supply +these as the file is created. + +Once this configuration is complete, the C tool will launch a mini HTTP +server to provide an interface to request users to authorise your project +application. + +Once you have succesfully created a gapi.json file and have authenticated a user +that is represented in this file then you can start making Google API Requests. + +See L for more detail. + + +=head2 gapi.json -The user can revoke permissions granted to a project ( Application ) by visiting https://myaccount.google.com/permissions +The ultimate output of this is the gapi.json file that contains both the Google +Project Specification as well as the authorised user access tokens. The file +describes a set of scopes that must all be configured as available to the +Project through the Google Admin Console. You may have multiple gapi.json files +for the same project containing a different subset of scopes. The gapi.json +file also contains the authorisation tokens granted by users. Multiple users can +be described within a single gapi.json file. If users exist across multiple +gapi.json files for the same project then (I believe) only the most recently +granted set of scopes will be usable. -This file can be used to access Google API Services using the WebService::Google:API:Client Google API Client Library. +The user can revoke permissions granted to a project ( Application ) by visiting +L. +This file can be used to access Google API Services using the +WebService::Google:API:Client Google API Client Library. =head2 References @@ -78,25 +104,20 @@ This file can be used to access Google API Services using the WebService::Google =cut -#use Path::Class; # ::File; ## cros-platform file paths handling # Exports file() by default - - my $filename = $ARGV[0] || 'gapi.json'; my $file = file( $filename ); -if ( $file->stat() ) ## file exists +if ($file->stat()) ## file exists { - say 'File ' , $file->absolute() . ' exists'; - input_if_not_exists( ['gapi/client_id', 'gapi/client_secret', 'gapi/scopes'] ); ## this potentially allows mreging with a json file with data external + say 'File ', $file->absolute() . ' exists'; + input_if_not_exists(['gapi/client_id', 'gapi/client_secret', 'gapi/scopes']); + ## this potentially allows mreging with a json file with data external ## to the app or to augment missing scope from file generated from ## earlier versions of goauth from other libs runserver(); -} -else -{ - +} else { setup(); runserver(); } @@ -136,10 +157,6 @@ sub setup $tokensfile->set( 'gapi/scopes', $oauth->{ scopes } ); say 'OAuth details updated!'; - # Remove comment for Mojolicious::Plugin::JSONConfig compatibility - #tie my @array, 'Tie::File', $file->absolute() or croak $!; - #shift @array; - #untie @array; return 1; } @@ -243,7 +260,6 @@ sub runserver } }; #delete $static->extra->{'favicon.ico'}; ## look into https://mojolicious.org/perldoc/Mojolicious/Static with view to repalcing default favicon - app->secrets( ['putyourownsecretcookieseedhereforsecurity' . time] ); ## NB persistence cookies not required beyond server run app->start( 'daemon', '-l', "http://*:$port" ); return 1; } @@ -265,19 +281,6 @@ sub _stdin } -=head2 TODO: Improve user interface of the HTML templates beneath DATA section - -=over 1 - -=item More Testing and documentation - explore cases where refresh token is not returned because previous token was issued - -=item Describe alternative User Agent approaches to WebServices::Google::Client - -=item Explore service accounts and possible inclusion into gapi.json - -=back - -=cut # data:image/vnd.microsoft.icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAAAAAAAAAAAACMhSAAAAGUBS04uKWNqJXxyeiK+d4Af2XeAINhweCK4YWcmckdJMCEAAP8AGRdQAAAAAAAAAAAAAAAAAERFMwA1NToKY2kmbH6HH9uOmR39lKAc/5WhHP+VoRz/k58c/42YHfx7hCDSX2QoXSgmQQY8PDgAAAAAAERGNwAzMj4KaXAkjIqVHfmWohz/laEc/5WhHP+VoRz/laEc/5WhHP+Wohz/laEc/4eRHvRlayV4HRhMBT8/PQD//wAAZGonboqVHfmWohz/laEc/5WhHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHP+Wohz/h5Ee819kKlmLmAUATlEzLH+IINuWohz/laEc/5WhHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHP96gyHLRkc5G2VrJX+Omh3+lqId/ZaiHviVoRz/laEc/5WhHP+Woh/wlqIf8JWhHfyWoh74laEc/5aiHvmWohz9i5Yd+V5kJ2NzeyHClKAc/5aiH+SbpimjlaEc/5WhHP+YoyLSnagumpynK6+ZpCTVm6YoqJWhHP+ZpSaqlqIf5JKeHP9udSOmeYIf4JWhHP+Woh7enqkxeZikI9SWoh7ynKcrk5umKa6ZpCTOmaQkzZumKZGVoRz+maUllZaiH92UoBz/dHwgxnqDHuGVoRz/lqIe3qGrNW6cpyurnagtjZ2oLpSeqTCen6kxl5umKq6gqjN4mKQj2JqlJ5OWoh/dlKAc/3R9H8h1fSHJlKAc/5aiH92cpiuLlqIe+p2nLYeYpCPJm6Yov5qlJsOXoh/tm6YowpumKb+bpiiPlqIf3ZOfHP9vdyOtZ24kjJCbHP+Woh7nnagufpynK5WbpiihlaEd95WhHP+VoRz/laEc/5WhHP+VoRz/maQkpJejHuKNmB39YWcmb1NWLzeCjB/llqIc/5aiHvWWoh7zlaEd/ZWhHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHfWWohz+focg10xONSUAAIgCaG8mg42ZHf6Wohz/laEc/5WhHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHP+Wohz/ipUd+mNpKGz//wAAS04xAD9BNhJvdyKmjpkd/paiHP+VoRz/laEc/5WhHP+VoRz/laEc/5WhHP+Wohz/i5Yd+2tyI5IzMz0LRUY2AAAAqQBRVCsAQUMzFGpxJYuEjh7skp0c/5WhHP+Wohz/lqIc/5WhHP+RnBz/gowf5mZtJns5OjYNR0kwAAAAAAAAAAAAAAAAADc3OgAnJUMFVVkqRGtzI6N5giDgfoge936IHvZ4gSDcaXAjmVFVLDkdGVIDMzJEAAAAAAAAAAAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIABAADAAwAA4AcAAA== diff --git a/dist.ini b/dist.ini index 3a48936..58b5651 100755 --- a/dist.ini +++ b/dist.ini @@ -1,13 +1,12 @@ name = WebService-GoogleAPI-Client +author = Veesh Goldman author = Peter Scott license = Apache_2_0 copyright_holder = Peter Scott and others -copyright_year = 2017-2018 -version = 0.21 +copyright_year = 2017-2021 +version = 0.23 main_module = lib/WebService/GoogleAPI/Client.pm -;[MinimumPerl] -;Perl 5.14.4 [PruneCruft] [ManifestSkip] @@ -22,16 +21,28 @@ main_module = lib/WebService/GoogleAPI/Client.pm [ConfirmRelease] ;[UploadToCPAN] -[PkgVersion] +[OurPkgVersion] [Prereqs] -; Mojo::Message::Response = 7.12 ## can't do this - no version info available for Mojo::Message::Response -;Moose = 2.2 -perl = 5.14.04 -Mojolicious = 7.12 +perl = 5.16.0 +Moo = 2.00 +Mojolicious = 8.30 Mojolicious::Plugin::OAuth2 = 1.5 List::Util = 1.45 - -[AutoPrereqs] +List::SomeUtils = 0 +IO::Socket::SSL = 2.06 +Mojo::JWT = 0 +Mojo::JWT::Google = 0.15 +Exporter::Shiny = 0 +Net::EmptyPort = 0 +Config::JSON = 0 +Data::Dumper = 0 +Data::Dump = 0 +strictures = 0 +Carp = 0 +CHI = 0 + +[Prereqs / TestRequires ] +Test2::V0 = 0 [CPANFile] @@ -39,9 +50,12 @@ List::Util = 1.45 perltidyrc = .perltidyrc [GatherDir] -; exclude test scripts from build +; exclude dev scripts from build exclude_filename = gapi.json +exclude_filename = service.json exclude_filename = DEV.MD +exclude_filename = sner +exclude_filename = TODO exclude_match = docs/* exclude_match = examples/dev_* exclude_filename = examples/gapi.json @@ -49,15 +63,9 @@ exclude_match = examples/delme/* exclude_match = examples/*.avi exclude_match = examples/*.png exclude_match = examples/openapi/* -;exclude_filename = t/gapi.json [PodWeaver] -;[ReadmeAnyFromPod] -;type = markdown -;filename = README.md -;location = build - [ReadmeAnyFromPod] type = text filename = README.txt @@ -71,30 +79,15 @@ copy = LICENSE [MetaJSON] - ;[GitHub::Meta] - ;issues = 1 - ;user = pscott-au - ;repository = https://github.com/pscott-au/WebService-GoogleAPI-Client - ;require_auth = 1 - ; uncomment when doing a major release - don't want to hit every build - [GitHub::Meta] -repository = https://github.com/pscott-au/WebService-GoogleAPI-Client - -; Configured by setting use_github_issues for the bundle -;bugs = 1 -; Configured by setting use_github_homepage for the bundle -;homepage = 1 +repository = https://github.com/rabbiveesh/WebService-GoogleAPI-Client +issues = 1 -[ChangelogFromGit] -max_age = 14 -tag_regexp = ^v(\d+\.\d+)$ -file_name = CHANGES -wrap_column = 74 -debug = 0 +[NextRelease] +[Git::CommitBuild] [Test::Perl::Critic] -critic_config = .perlcriticrc ; default / relative to project root +critic_config = .perlcriticrc ; i am unable to get dzil test to use my .perlcriticrc or use modern to avoid structure warnings ; FOR Dist::Zilla USERS (FROM 'perldoc Test::Perl::Critic' ) ; If you use Test::Perl::Critic with Dist::Zilla, beware that some DZ @@ -104,4 +97,4 @@ critic_config = .perlcriticrc ; default / relative to project root ; the top of the file, which will violate ; Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict. One ; solution is to use the Dist::Zilla::Plugin::OurPkgVersion which allows -; you to control where the $VERSION declaration appears. \ No newline at end of file +; you to control where the $VERSION declaration appears. diff --git a/docs/myapp.pl b/docs/myapp.pl index a9305d3..03341cd 100755 --- a/docs/myapp.pl +++ b/docs/myapp.pl @@ -24,7 +24,7 @@ my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); ## , -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; #my $user = $aref_token_emails->[0]; ## default to the first user #$gapi_client->user( $user ); diff --git a/examples/cloud_dns.pl b/examples/cloud_dns.pl index ece62c8..b5c09c0 100644 --- a/examples/cloud_dns.pl +++ b/examples/cloud_dns.pl @@ -107,7 +107,7 @@ =head2 GOOGLE API LINKS ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/cloudstorage_bucket_example.pl b/examples/cloudstorage_bucket_example.pl index 1d39eb3..b1a632d 100755 --- a/examples/cloudstorage_bucket_example.pl +++ b/examples/cloudstorage_bucket_example.pl @@ -110,7 +110,7 @@ =head2 GOOGLE API LINKS ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/dev_calendar_example.pl b/examples/dev_calendar_example.pl index 844c173..9ecf707 100644 --- a/examples/dev_calendar_example.pl +++ b/examples/dev_calendar_example.pl @@ -85,7 +85,7 @@ =head2 GOALS else { croak( 'I only work if gapi.json is here' ); } ; ## prolly better to fail on setup ? my $gapi_agent = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => './gapi.json' ); -my $aref_token_emails = $gapi_agent->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_agent->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_agent->user( $user ); diff --git a/examples/dev_generate_full_json_method_tree_struct.pl b/examples/dev_generate_full_json_method_tree_struct.pl index 08776e5..29f31c5 100644 --- a/examples/dev_generate_full_json_method_tree_struct.pl +++ b/examples/dev_generate_full_json_method_tree_struct.pl @@ -25,7 +25,7 @@ ; ## prolly better to fail on setup ? my $gapi_agent = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => './gapi.json' ); -my $aref_token_emails = $gapi_agent->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_agent->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_agent->user( $user ); diff --git a/examples/dev_mybusiness_example.pl b/examples/dev_mybusiness_example.pl index 25d0d89..3cd40f3 100644 --- a/examples/dev_mybusiness_example.pl +++ b/examples/dev_mybusiness_example.pl @@ -102,7 +102,7 @@ =head2 GOALS else { croak( 'I only work if gapi.json is here' ); } ; ## prolly better to fail on setup ? my $gapi_agent = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => './gapi.json' ); -my $aref_token_emails = $gapi_agent->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_agent->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_agent->user( $user ); diff --git a/examples/dev_sheets_example.pl b/examples/dev_sheets_example.pl index 6871643..8b78cf8 100644 --- a/examples/dev_sheets_example.pl +++ b/examples/dev_sheets_example.pl @@ -132,7 +132,7 @@ =head2 LIST ALL SHEETS else { croak( 'I only work if gapi.json is here' ); } ; ## prolly better to fail on setup ? my $gapi_agent = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_agent->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_agent->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_agent->user( $user ); diff --git a/examples/discovery_example.pl b/examples/discovery_example.pl index f02b912..efcf94c 100755 --- a/examples/discovery_example.pl +++ b/examples/discovery_example.pl @@ -182,7 +182,7 @@ =head2 ABSTRACT #print Dumper $foo;exit; ## list all user scopes configured - my $configured_scopes = $gapi_agent->get_scopes_as_array(); ## TODO rename to array_ref + my $configured_scopes = $gapi_agent->scopes; say "Scopes currently configured are: \n * " . join( "\n * ", @$configured_scopes ); ## transform list into a hash so can do instant lookups @@ -365,11 +365,6 @@ =head2 ABSTRACT ###################################### -# my $api_verson_urls = api_version_urls(); ## hash of api discovery urls api->version->url .. bugger deleted this function -#print Dumper $api_verson_urls ; -#my $api = 'appengine'; my $version = 'v1beta5'; -#my $api = 'sheets'; my $version = 'v4'; -#my $api = 'sheets'; my $version = ''; my $api = 'gmail'; my $version = 'v1'; @@ -465,7 +460,6 @@ =head2 ABSTRACT exit; -print WebService::GoogleAPI::Client::Discovery->new->supported_as_text(); exit; diff --git a/examples/drive_example.pl b/examples/drive_example.pl index fe0aee0..fd4f2c8 100644 --- a/examples/drive_example.pl +++ b/examples/drive_example.pl @@ -93,7 +93,7 @@ =head2 GOOGLE API LINKS ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/geocoding_api.pl b/examples/geocoding_api.pl index 9fd6ab2..a10c63d 100755 --- a/examples/geocoding_api.pl +++ b/examples/geocoding_api.pl @@ -74,7 +74,7 @@ =head2 RELEVANT GOOGLE API LINKS ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); say 'x' x 180; diff --git a/examples/gmail_example.pl b/examples/gmail_example.pl index 776df7c..26f8b7b 100755 --- a/examples/gmail_example.pl +++ b/examples/gmail_example.pl @@ -103,7 +103,7 @@ =head2 send else { croak( 'I only work if gapi.json is here' ); } ; ## prolly better to fail on setup ? my $gapi_agent = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => './gapi.json' ); -my $aref_token_emails = $gapi_agent->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_agent->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_agent->user( $user ); diff --git a/examples/people_api.pl b/examples/people_api.pl index 87b381d..3d1e0d1 100755 --- a/examples/people_api.pl +++ b/examples/people_api.pl @@ -81,7 +81,7 @@ =head2 GOOGLE API LINKS ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manually sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => $config->{debug}, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/service_account_example.pl b/examples/service_account_example.pl index 0306006..2f6cde6 100644 --- a/examples/service_account_example.pl +++ b/examples/service_account_example.pl @@ -1,61 +1,33 @@ #!/usr/bin/env perl use strictures; -## use Crypt::JWT qw(encode_jwt); -- couldn't get this to work -use Data::Dump qw/pp/; -use feature 'say'; -use LWP::UserAgent; -use JSON; -use Mojo::File; -use Mojo::JWT; ## there is also Mojo::JWT::Google but the cpan version is broken - pull request submitted but is easy enough to use parent Mojo::JWT +use Data::Printer; +use Mojo::UserAgent; +use Mojo::JWT::Google; my $config = { path => $ARGV[0] // '/Users/peter/Downloads/computerproscomau-b9f59b8ee34a.json', scopes => $ARGV[1] // 'https://www.googleapis.com/auth/plus.business.manage https://www.googleapis.com/auth/compute' }; -my $jwt = mojo_jwt_from_json_or_croak( $config->{path}, $config->{scopes} ); -my $ua = LWP::UserAgent->new(); #WWW::Mechanize->new( autocheck => 1 ); +my $jwt = Mojo::JWT::Google->new( from_json => $config->{path}, scopes => [ split / /, $config->{scopes} ] ); -my $response = $ua->post('https://www.googleapis.com/oauth2/v4/token', { 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', - 'assertion' => $jwt } +my $ua = Mojo::UserAgent->new(); + +my $response = $ua->post('https://www.googleapis.com/oauth2/v4/token', form => { 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', + 'assertion' => $jwt->encode } ); -if ($response->is_success) +if ($response->res) { - print $response->decoded_content; + p $response->res->json; } else { - print STDERR $response->status_line, "\n"; -} -exit; - -####################################################################### -sub mojo_jwt_from_json_or_croak -{ - my ( $path, $scope ) = @_; - croak("No path provided") if not defined $path; - croak("$path no available") if not -f $path; - my $json = decode_json( Mojo::File->new($path)->slurp ); - croak("No Private key in $path") if not defined $json->{private_key}; - croak("Not a service account") if $json->{type} ne 'service_account'; - my $jwt = Mojo::JWT->new(); - $jwt->algorithm('RS256'); - $jwt->secret($json->{private_key}); - - $jwt->claims( { - iss => $json->{client_email}, - scope => $scope, - aud => 'https://www.googleapis.com/oauth2/v4/token', - iat => time(), - exp => time()+3600 - } ); - $jwt->set_iat( 1 ); - return $jwt->encode; + warn $response->res->status, "\n"; } -####################################################################### +exit; =pod diff --git a/examples/text_to_speech.pl b/examples/text_to_speech.pl index ca70c7f..9708cf2 100755 --- a/examples/text_to_speech.pl +++ b/examples/text_to_speech.pl @@ -51,7 +51,7 @@ =head2 TODO ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => 0, gapi_json => 'gapi.json' ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/translation_example.pl b/examples/translation_example.pl index 3d4ba38..8448f95 100755 --- a/examples/translation_example.pl +++ b/examples/translation_example.pl @@ -98,7 +98,7 @@ =head2 TODO ## assumes gapi.json configuration in working directory with scoped project and user authorization ## manunally sets the client user email to be the first in the gapi.json file my $gapi_client = WebService::GoogleAPI::Client->new( debug => 0, gapi_json => 'gapi.json', debug=>0 ); -my $aref_token_emails = $gapi_client->auth_storage->storage->get_token_emails_from_storage; +my $aref_token_emails = $gapi_client->auth_storage->get_token_emails_from_storage; my $user = $aref_token_emails->[0]; ## default to the first user $gapi_client->user( $user ); diff --git a/examples/usage_basic_examples.pl b/examples/usage_basic_examples.pl index 3609807..2c7b90f 100755 --- a/examples/usage_basic_examples.pl +++ b/examples/usage_basic_examples.pl @@ -8,9 +8,17 @@ use File::Which; use feature 'say'; +use Mojo::Util qw/getopt/; + +getopt + 'c|credentials' => \my $creds, + 'u|user' => \my $user; + +$creds //= './gapi.json'; +die "can't do cool things with no username!" unless $user; ## assumes gapi.json configuration in working directory with scoped project and user authorization -my $gapi_client = WebService::GoogleAPI::Client->new( debug => 1, gapi_json => './gapi.json', user => 'peter@shotgundriver.com' ); +my $gapi_client = WebService::GoogleAPI::Client->new(gapi_json => $creds, user => $user); use Email::Simple; ## RFC2822 formatted messages @@ -18,25 +26,20 @@ my $r; ## using to contain result of queries ( Mojo::Message::Response instance ) -my $my_email_address = 'peter@shotgundriver.com'; - - -if ( 0 ) -{ - print "Sending email to self\n"; - $r = $gapi_client->api_query( - api_endpoint_id => 'gmail.users.messages.send', - options => { - raw => encode_base64( - Email::Simple->create( - header => [To => $my_email_address, From => $my_email_address, Subject => "Test email from '$my_email_address' ",], - body => "This is the body of email to '$my_email_address'", - )->as_string - ) - }, - ); -} +print "Sending email to self\n"; +$r = $gapi_client->api_query( + api_endpoint_id => 'gmail.users.messages.send', + options => { + raw => encode_base64( + Email::Simple->create( + header => + [To => $user, From => $user, Subject => "Test email from '$user' ",], + body => "This is the body of email to '$user'", + )->as_string + ) + }, +); if ( 0 ) { @@ -120,18 +123,6 @@ #say my $x = WebService::GoogleAPI::Client::Discovery->new->list_of_available_google_api_ids(); say 'fnarly' if ref( WebService::GoogleAPI::Client::Discovery->new->discover_all() ) eq 'HASH'; -#exit; -if ( WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api() ) -{ - #say Dumper [ WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api() ]; -} -else -{ - #say Dumper WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api(); -} - -say length( WebService::GoogleAPI::Client::Discovery->new->supported_as_text ) > 100; - #say Dumper $x; say WebService::GoogleAPI::Client::Discovery->new->api_verson_urls; @@ -141,6 +132,5 @@ my $dd = $f->get_credentials_for_refresh(); -#say WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api(); #say join(',', WebService::GoogleAPI::Client->new->list_of_available_google_api_ids() ) . ' as list'; #say WebService::GoogleAPI::Client->new->list_of_available_google_api_ids() . ' as scalar'; diff --git a/lib/WebService/GoogleAPI/Client.pm b/lib/WebService/GoogleAPI/Client.pm index 3b2cf7c..9103eac 100755 --- a/lib/WebService/GoogleAPI/Client.pm +++ b/lib/WebService/GoogleAPI/Client.pm @@ -3,14 +3,27 @@ use 5.14.0; package WebService::GoogleAPI::Client; +# VERSION + use Data::Dump qw/pp/; use Moo; use WebService::GoogleAPI::Client::UserAgent; use WebService::GoogleAPI::Client::Discovery; +use WebService::GoogleAPI::Client::AuthStorage::GapiJSON; +use WebService::GoogleAPI::Client::AuthStorage::ServiceAccount; use Carp; use CHI; -use List::MoreUtils qw(uniq); +use Mojo::Util; +#TODO- batch requests. The only thing necessary is to send a +#multipart request as I wrote in that e-mail. +# +#TODO- implement auth for service accounts. +# +#TODO- allow using promises instead of just calling. Also allow +# for full access to the tx instead of assuming it's always +# returning the res. Perhaps mix in something that delegates the +# json method to the res? # ABSTRACT: Google API Discovery and SDK @@ -24,12 +37,12 @@ use List::MoreUtils qw(uniq); =head1 SYNOPSIS -Access Google API Services Version 1 using an OAUTH2 User Agent. +Access Google API Services using an OAUTH2 User Agent. -Includes Discovery, validation authentication and API Access. +Includes Discovery, validation, authentication and API Access. -assumes gapi.json configuration in working directory with scoped Google project -redentials and user authorization created by _goauth_ +By default assumes gapi.json configuration in working directory with scoped Google project +credentials and user authorization created by L. use WebService::GoogleAPI::Client; @@ -44,9 +57,12 @@ redentials and user authorization created by _goauth_ } -Internal User Agent provided be property WebService::GoogleAPI::Client::UserAgent dervied from Mojo::UserAgent +Package includes L CLI Script to collect initial end-user authorisation +to scoped services. -Package includes I CLI Script to collect initial end-user authorisation to scoped services +Note to intrepid hackers: Any method that isn't documented is considered +private, and subject to change in breaking ways without notice. (Although I'm a +pretty nice guy, and probably will leave a warning or something). =head1 EXAMPLES @@ -57,18 +73,21 @@ Package includes I CLI Script to collect initial end-user authorisation use MIME::Base64; my $my_email_address = 'peter@shotgundriver.com' + my $raw_email_payload = encode_base64( + Email::Simple->create( + header => [ + To => $my_email_address, + From => $my_email_address, + Subject => "Test email from '$my_email_address' ", + ], + body => "This is the body of email to '$my_email_address'", + )->as_string + ); - my $raw_email_payload = encode_base64( Email::Simple->create( header => [To => $my_email_address, - From => $my_email_address, - Subject =>"Test email from '$my_email_address' ",], - body => "This is the body of email to '$my_email_address'", - )->as_string - ); - - $gapi_client->api_query( - api_endpoint_id => 'gmail.users.messages.send', - options => { raw => $raw_email_payload }, - ); + $gapi_client->api_query( + api_endpoint_id => 'gmail.users.messages.send', + options => { raw => $raw_email_payload }, + ); =head2 MANUAL API REQUEST CONSTRUCTION - GET CALENDAR LIST @@ -82,23 +101,53 @@ Package includes I CLI Script to collect initial end-user authorisation =cut -has 'debug' => ( is => 'rw', default => 0, lazy => 1 ); ## NB - when udpated change doesn't propogate ! -has 'ua' => ( - handles => [qw/access_token auth_storage do_autorefresh get_scopes_as_array user /], - is => 'ro', - default => sub { WebService::GoogleAPI::Client::UserAgent->new( debug => shift->debug ) }, - lazy => 1, +has 'debug' => ( + is => 'rw', + default => 0, + lazy => 1 +); +has 'ua' => ( + handles => + [qw/do_autorefresh auth_storage get_access_token scopes user/], + is => 'ro', + default => + sub { WebService::GoogleAPI::Client::UserAgent->new(debug => shift->debug) } + , + lazy => 1, +); + +sub get_scopes_as_array { + carp 'get_scopes_as_array has deprecated in favor of the shorter "scopes"'; + return $_[0]->scopes +} + +has 'chi' => ( + is => 'rw', + default => sub { + CHI->new( + driver => 'File', + max_key_length => 512, + namespace => __PACKAGE__ + ); + }, + lazy => 1 ); -has 'chi' => ( is => 'rw', default => sub { CHI->new( driver => 'File', max_key_length => 512, namespace => __PACKAGE__ ) }, lazy => 1 ); + has 'discovery' => ( handles => [ - qw/ discover_all extract_method_discovery_detail_from_api_spec get_api_discovery_for_api_id - methods_available_for_google_api_id list_of_available_google_api_ids / ## get_method_meta + qw/ discover_all + get_method_details + get_api_document service_exists + methods_available_for_google_api_id list_api_ids / ], is => 'ro', default => sub { my $self = shift; - return WebService::GoogleAPI::Client::Discovery->new( debug => $self->debug, ua => $self->ua, chi => $self->chi ); + return WebService::GoogleAPI::Client::Discovery->new( + debug => $self->debug, + ua => $self->ua, + chi => $self->chi + ); }, lazy => 1, ); @@ -110,31 +159,98 @@ has 'discovery' => ( =head2 C - WebService::GoogleAPI::Client->new( user => 'peter@pscott.com.au', gapi_json => '/fullpath/gapi.json' ); + WebService::GoogleAPI::Client->new( + user => 'peter@pscott.com.au', gapi_json => '/fullpath/gapi.json' ); -=head3 PARAMETERS +=head3 B -=head4 user :: the email address that identifies key of credentials in the config file +=over 4 -=head4 gapi_json :: Location of the configuration credentials - default gapi.json +=item debug -=head4 debug :: if '1' then diagnostics are send to STDERR - default false +if truthy then diagnostics are send to STDERR - default false. Crank it up to 11 +for maximal debug output -=head4 chi :: an instance to a CHI persistent storage case object - if none provided FILE is used +=item chi +an instance to a CHI persistent storage case object - if none provided FILE is used -=cut +=back -sub BUILD -{ - my ( $self, $params ) = @_; +=head3 B + +You can use either gapi_json, which is the file you get from using the bundled +goauth tool, or service_account which is the json file you can download from +https://console.cloud.google.com/iam-admin/serviceaccounts. + +service_account and gapi_json are mutually exclusive, and gapi_json takes precedence. - $self->auth_storage->setup( { type => 'jsonfile', path => $params->{ gapi_json } } ) if ( defined $params->{ gapi_json } ); - $self->user( $params->{ user } ) if ( defined $params->{ user } ); +If nothing is passed, then we check the GOOGLE_APPLICATION_CREDENTIALS env +variable for the location of a service account file. This matches the +functionality of the Google Cloud libraries from other languages (well, +somewhat. I haven't fully implemented ADC yet - see +L for some details. PRs +are welcome!) - ## how to handle chi as a parameter - $self->discovery->chi( $self->chi ); ## is this redundant? set in default? - ## TODO - think about consequences of user not providing auth storage or user on instantiaton +If that doesn't exist, then we default to F in the current directory. + +B This default is subject to change as more storage backends are implemented. +A deprecation warning will be emmitted when this is likely to start happening. + +For more advanced usage, you can supply your own auth storage instance, which is +a consumer of the L role. See the +POD for that module for more information. + +=begin :list + += user + +the email address that requests will be made for + += gapi_json + +Location of end user credentials + += service_account + +Location of service account credentials + += auth_storage + +An instance of a class consuming L, already +set up for returning access tokens (barring the ua). + +=end :list + +If you're using a service account, user represents the user that you're +impersonating. Make sure you have domain-wide delegation set up, or else this +won't work. + +=cut + +#NOTE- in terms of implementing google's ADC +# (see https://cloud.google.com/docs/authentication/production and also +# https://github.com/googleapis/python-cloud-core/blob/master/google/cloud/client.py) +# I looked into it and based on that, it seems that every environment has different reqs, +# so it's a maintenance liability +sub BUILD { + my ($self, $params) = @_; + + my ($storage, $file); + if ($params->{auth_storage}) { + $storage = $params->{auth_storage}; + } elsif ($file = $params->{gapi_json}) { + $storage = WebService::GoogleAPI::Client::AuthStorage::GapiJSON->new(path => $file); + } elsif ($file = $params->{service_account}) { + $storage = WebService::GoogleAPI::Client::AuthStorage::ServiceAccount->new( + path => $file, scopes => $params->{scopes}); + } elsif ($file = $ENV{GOOGLE_APPLICATION_CREDENTIALS}) { + $storage = WebService::GoogleAPI::Client::AuthStorage::ServiceAccount->new( + path => $file, scopes => $params->{scopes}); + } + $self->auth_storage($storage) if $storage; + + $self->user($params->{user}) if (defined $params->{user}); } =head2 C @@ -145,9 +261,9 @@ handles user auth token inclusion in request headers and refreshes token if requ Required params: method, route -Optional params: api_endpoint_id cb_method_discovery_modify +Optional params: api_endpoint_id cb_method_discovery_modify, options -$self->access_token must be valid +$self->get_access_token must return a valid token $gapi->api_query({ @@ -164,45 +280,112 @@ $self->access_token must be valid ## if provide the Google API Endpoint to inform pre-query validation say $gapi_agent->api_query( api_endpoint_id => 'gmail.users.messages.send', - options => { raw => encode_base64( - Email::Simple->create( header => [To => $user, From => $user, Subject =>"Test email from $user",], - body => "This is the body of email from $user to $user", )->as_string - ), - }, - )->to_string; ## + options => + { raw => encode_base64( Email::Simple->create( + header => [To => $user, From => $user, + Subject =>"Test email from $user",], + body => "This is the body of email from $user to $user", + )->as_string ), + }, + )->to_string; ## print $gapi_agent->api_query( - api_endpoint_id => 'gmail.users.messages.list', ## auto sets method to GET, path to 'https://www.googleapis.com/calendar' + api_endpoint_id => 'gmail.users.messages.list', + ## auto sets method to GET, and the path to + ## 'https://www.googleapis.com/gmail/v1/users/me/messages' )->to_string; - #print pp $r; +If the pre-query validation fails then a 418 - I'm a Teapot error response is +returned with the body containing the specific description of the +errors ( Tea Leaves ;^) ). + +=head3 B + + + +NB: If you pass a 'path' parameter this takes precendence over the +API Discovery Spec. Any parameters defined in the path of the +format {VARNAME} will be filled in with values within the +options=>{ VARNAME => 'value '} parameter structure. This is the +simplest way of addressing issues where the API discovery spec is +inaccurate. ( See dev_sheets_example.pl as at 14/11/18 for +illustration ). This particular issue has been since solved, but +you never know where else there are problems with the discovery spec. + +Sometimes, Google is slightly inconsistent about how to name the parameters. For example, +error messages sent back to the user tend to have the param names in snake_case, whereas +the discovery document always has them in camelCase. To address this issue, and in +the DWIM spirit of perl, parameters may be passed in camelCase or snake_case. That +means that + + $gapi_agent->api_query( + api_endpoint_id => 'gmail.users.messages.list', + options => { userId => 'foobar' }); - if the pre-query validation fails then a 418 - I'm a Teapot error response is returned with the - body containing the specific description of the errors ( Tea Leaves ;^) ). +and -NB: If you pass a 'path' parameter this takes precendence over the API Discovery Spec. Any parameters defined in the path of the format {VARNAME} will be - filled in with values within the options=>{ VARNAME => 'value '} parameter structure. This is the simplest way of addressing issues where the API - discovery spec is inaccurate. ( See dev_sheets_example.pl as at 14/11/18 for illustration ) + $gapi_agent->api_query( + api_endpoint_id => 'gmail.users.messages.list', + options => { user_id => 'foobar' }); -To allow the user to fix discrepencies in the Discovery Specification the cb_method_discovery_modify callback can be used which must accept the -method specification as a parameter and must return a (potentially modified) method spec. +will produce the same result. + +Sometimes a param expects a dynamic part and a static part. The endpoint +jobs.projects.jobs.list, for example, has a param called 'parent' which has a +format '^projects/[^/]+$'. In cases like this, you can just skip out the constant +part, making + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.list', + options => { parent => 'sner' } ); + +and + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.list', + options => { parent => 'projects/sner' } ); + +the same. How's that for DWIM? + +In addition, you can use different names to refer to multi-part +parameters. For example, the endpoint jobs.projects.jobs.delete officially +expects one parameter, 'name'. The description for the param tells you +that you it expects it to contain 'projectsId' and 'jobsId'. For cases like this, + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.delete', + options => {name => 'projects/sner/jobs/bler'} ); + +and + + $gapi_agent->api_query( api_endpoint_id => 'jobs.projects.jobs.delete', + options => {projectsId => 'sner', jobsId => 'bler'} ); + +will produce the same result. Note that for now, in this case you can't pass +the official param name without the constant parts. That may change in the +future. + +To further fix discrepencies in the Discovery Specification, the +cb_method_discovery_modify callback can be used which must accept +the method specification as a parameter and must return a +(potentially modified) method spec. eg. - my $r = $gapi_client->api_query( api_endpoint_id => "sheets:v4.spreadsheets.values.update", - options => { - spreadsheetId => '1111111111111111111', - valueInputOption => 'RAW', - range => 'Sheet1!A1:A2', - 'values' => [[99],[98]] - }, - cb_method_discovery_modify => sub { - my $meth_spec = shift; - $meth_spec->{parameters}{valueInputOption}{location} = 'path'; - $meth_spec->{path} = "v4/spreadsheets/{spreadsheetId}/values/{range}?valueInputOption={valueInputOption}"; - return $meth_spec; - } - ); + my $r = $gapi_client->api_query( + api_endpoint_id => "sheets:v4.spreadsheets.values.update", + options => { + spreadsheetId => '1111111111111111111', + valueInputOption => 'RAW', + range => 'Sheet1!A1:A2', + 'values' => [[99],[98]] + }, + cb_method_discovery_modify => sub { + my $meth_spec = shift; + $meth_spec->{parameters}{valueInputOption}{location} = 'path'; + $meth_spec->{path} .= "?valueInputOption={valueInputOption}"; + return $meth_spec; + } + ); + +Again, this specific issue has been fixed. Returns L object @@ -224,161 +407,237 @@ Returns L object ## NB - uses the ua api_query to execute the server request ################################################## -sub api_query -{ - my ( $self, @params_array ) = @_; +sub api_query { + my ($self, @params_array) = @_; ## TODO - find a more elgant idiom to do this - pulled this off top of head for quick imeplementation my $params = {}; - if ( scalar( @params_array ) == 1 && ref( $params_array[0] ) eq 'HASH' ) - { + if (scalar(@params_array) == 1 && ref($params_array[0]) eq 'HASH') { $params = $params_array[0]; + } else { + $params = {@params_array}; ## what happens if not even count } - else - { - $params = { @params_array }; ## what happens if not even count - } - carp( pp $params) if $self->debug > 10; - + carp(pp $params) if $self->debug > 10; - my @teapot_errors = (); ## used to collect pre-query validation errors - if set we return a response with 418 I'm a teapot - @teapot_errors = $self->_process_params_for_api_endpoint_and_return_errors( $params ) if ( defined $params->{ api_endpoint_id } ); ## ## pre-query validation if api_id parameter is included + croak "Missing neccessary scopes to access $params->{api_endpoint_id}" + unless $self->has_scope_to_access_api_endpoint($params->{api_endpoint_id}); - - if ( not defined $params->{ path } ) ## either as param or from discovery - { + ## used to collect pre-query validation errors - if set we return a response + # with 418 I'm a teapot + my @teapot_errors = (); + ## pre-query validation if api_id parameter is included + @teapot_errors = $self->_process_params($params) + if (defined $params->{api_endpoint_id}); + + ## either as param or from discovery + if (not defined $params->{path}) { push @teapot_errors, 'path is a required parameter'; $params->{path} = ''; } - push @teapot_errors, "Path '$params->{path}' includes unfilled variable after processing" if ( $params->{ path } =~ /\{.+\}/xms ) ; - - if ( @teapot_errors > 0 ) ## carp and include in 418 TEAPOT ERROR - response body with @teapot errors - { - carp( join( "\n", @teapot_errors ) ) if $self->debug; + push @teapot_errors, "Path '$params->{path}' includes unfilled variable after processing" + if ($params->{path} =~ /\{.+\}/xms); + ## carp and include in 418 TEAPOT ERROR - response body with @teapot errors + if (@teapot_errors > 0) { + carp(join("\n", @teapot_errors)) if $self->debug; return Mojo::Message::Response->new( content_type => 'text/plain', code => 418, - message => 'Teapot Error - Reqeust blocked before submitting to server with pre-query validation errors', - body => join( "\n", @teapot_errors ) + message => +'Teapot Error - Reqeust blocked before submitting to server with pre-query validation errors', + body => join("\n", @teapot_errors) ); - } - else ## query looks good - send to user agent to execute - { - #print pp $params; - return $self->ua->validated_api_query( $params ); + } else { + ## query looks good - send to user agent to execute + return $self->ua->validated_api_query($params); } } ################################################## ################################################## ## _ensure_api_spec_has_defined_fields is really only used to allow carping without undef warnings if needed -sub _ensure_api_spec_has_defined_fields -{ - my ( $self, $api_discovery_struct ) = @_; +sub _ensure_api_spec_has_defined_fields { + my ($self, $api_discovery_struct) = @_; ## Ensure API Discovery has expected fields defined - foreach my $expected_key ( qw/path title ownerName version id discoveryVersion revision description documentationLink rest/ ) - { - $api_discovery_struct->{ $expected_key } = '' unless defined $api_discovery_struct->{ $expected_key }; + foreach my $expected_key (qw/path title ownerName version id discoveryVersion + revision description documentationLink rest/) { + $api_discovery_struct->{$expected_key} = '' + unless defined $api_discovery_struct->{$expected_key}; } - $api_discovery_struct->{ canonicalName } = $api_discovery_struct->{ title } unless defined $api_discovery_struct->{ canonicalName }; + $api_discovery_struct->{canonicalName} = $api_discovery_struct->{title} + unless defined $api_discovery_struct->{canonicalName}; return $api_discovery_struct; } ################################################## ################################################## -sub _process_params_for_api_endpoint_and_return_errors -{ - my ( $self, $params) = @_; ## nb - api_endpoint is a param - param key values are modified through this sub +sub _process_params_for_api_endpoint_and_return_errors { + warn '_process_params_for_api_endpoint_and_return_errors has been deprecated. Please use _process_params'; + _process_params(@_); +} - croak('this should never happen - this method is internal only!') unless defined $params->{ api_endpoint_id }; - - my $api_discovery_struct = $self->_ensure_api_spec_has_defined_fields( $self->discovery->get_api_discovery_for_api_id( $params->{ api_endpoint_id } ) ); ## $api_discovery_struct requried for service base URL - $api_discovery_struct->{ baseUrl } =~ s/\/$//sxmg; ## remove trailing '/' from baseUrl - - my $method_discovery_struct = $self->extract_method_discovery_detail_from_api_spec( $params->{ api_endpoint_id } ); ## if can get discovery data for google api endpoint then continue to perform detailed checks +sub _process_params { + ## nb - api_endpoint is a param - param key values are modified through this sub + my ($self, $params) = @_; - ## allow optional user callback pre-processing of method_discovery_struct - $method_discovery_struct = &{$params->{cb_method_discovery_modify}}($method_discovery_struct) if ( defined $params->{cb_method_discovery_modify} && ref( $params->{cb_method_discovery_modify} ) eq 'CODE' ); + croak('this should never happen - this method is internal only!') + unless defined $params->{api_endpoint_id}; - return ("Checking discovery of $params->{api_endpoint_id} method data failed - is this a valid end point") unless ( keys %{ $method_discovery_struct } > 0 ); - ## assertion: method discovery struct ok - or at least has keys - carp( "API Endpoint $params->{api_endpoint_id} discovered specification didn't include expected 'parameters' keyed HASH structure" ) unless ref( $method_discovery_struct->{ parameters } ) eq 'HASH'; + ## $api_discovery_struct requried for service base URL + my $api_discovery_struct = $self->_ensure_api_spec_has_defined_fields( + $self->discovery->get_api_document($params->{api_endpoint_id})); + ## remove trailing '/' from baseUrl + $api_discovery_struct->{baseUrl} =~ s/\/$//sxmg; - my @teapot_errors = (); ## errors are pushed into this as encountered - $params->{ method } = $method_discovery_struct->{ httpMethod } || 'GET' if ( not defined $params->{ method } ); - push( @teapot_errors, "method mismatch - you requested a $params->{method} which conflicts with discovery spec requirement for $method_discovery_struct->{httpMethod}" ) if ( $params->{ method } !~ /^$method_discovery_struct->{httpMethod}$/sxim ); - push( @teapot_errors, "Client Credentials do not include required scope to access $params->{api_endpoint_id}" ) unless $self->has_scope_to_access_api_endpoint( $params->{ api_endpoint_id } ); ## ensure user has required scope access - $params->{ path } = $method_discovery_struct->{ path } unless $params->{ path }; ## Set default path iff not set by user - NB - will prepend baseUrl later - push @teapot_errors, 'path is a required parameter' unless $params->{ path }; - - push @teapot_errors, $self->_interpolate_path_parameters_append_query_params_and_return_errors( $params, $method_discovery_struct ); + ## if can get discovery data for google api endpoint then continue to perform + # detailed checks + my $method_discovery_struct = $self->get_method_details($params->{api_endpoint_id}); + + #save away original path so we can know if it's fiddled with + #later + $method_discovery_struct->{origPath} = $method_discovery_struct->{path}; + + ## allow optional user callback pre-processing of method_discovery_struct + $method_discovery_struct = + &{ $params->{cb_method_discovery_modify} }($method_discovery_struct) + if (defined $params->{cb_method_discovery_modify} + && ref($params->{cb_method_discovery_modify}) eq 'CODE'); + + my @teapot_errors = (); ## errors are pushed into this as encountered + $params->{method} = $method_discovery_struct->{httpMethod} || 'GET' + if (not defined $params->{method}); + push(@teapot_errors, +"method mismatch - you requested a $params->{method} which conflicts with discovery spec requirement for $method_discovery_struct->{httpMethod}" + ) if ($params->{method} !~ /^$method_discovery_struct->{httpMethod}$/sxim); - $params->{ path } =~ s/^\///sxmg; ## remove leading '/' from path - $params->{ path } = "$api_discovery_struct->{baseUrl}/$params->{path}" unless $params->{ path } =~ /^$api_discovery_struct->{baseUrl}/ixsmg; ## prepend baseUrl if required + ## Set default path iff not set by user - NB - will prepend baseUrl later + $params->{path} = $method_discovery_struct->{path} unless $params->{path}; + push @teapot_errors, 'path is a required parameter' unless $params->{path}; + + push @teapot_errors, + $self->_interpolate_path_parameters_append_query_params_and_return_errors( + $params, $method_discovery_struct); + + $params->{path} =~ s/^\///sxmg; ## remove leading '/' from path + $params->{path} = "$api_discovery_struct->{baseUrl}/$params->{path}" + unless $params->{path} =~ + /^$api_discovery_struct->{baseUrl}/ixsmg; ## prepend baseUrl if required ## if errors - add detail available in the discovery struct for the method and service to aid debugging - push (@teapot_errors, qq{ $api_discovery_struct->{title} $api_discovery_struct->{rest} API into $api_discovery_struct->{ownerName} $api_discovery_struct->{canonicalName} $api_discovery_struct->{version} with id $method_discovery_struct->{id} as described by discovery document version $method_discovery_struct->{discoveryVersion} revision $method_discovery_struct->{revision} with documentation at $api_discovery_struct->{documentationLink} \nDescription $api_discovery_struct->{description}\n} ) if ( @teapot_errors ); + push @teapot_errors, +qq{ $api_discovery_struct->{title} $api_discovery_struct->{rest} API into $api_discovery_struct->{ownerName} $api_discovery_struct->{canonicalName} $api_discovery_struct->{version} with id $method_discovery_struct->{id} as described by discovery document version $api_discovery_struct->{discoveryVersion} revision $api_discovery_struct->{revision} with documentation at $api_discovery_struct->{documentationLink} \nDescription: $method_discovery_struct->{description}\n} + if @teapot_errors; return @teapot_errors; } ################################################## +#small subs to convert between these_types to theseTypes of params +#TODO- should probs move this into a Util module +sub camel { shift if @_ > 1; $_[0] =~ s/ _(\w) /\u$1/grx }; +sub snake { shift if @_ > 1; $_[0] =~ s/([[:upper:]])/_\l$1/grx }; ################################################## sub _interpolate_path_parameters_append_query_params_and_return_errors { - my ( $self, $params, $method_discovery_struct ) = @_; + my ( $self, $params, $discovery_struct ) = @_; my @teapot_errors = (); my @get_query_params = (); - my %path_params = map { $_ => 1 } ($params->{path} =~ /\{\+*([^\}]+)\}/xg); ## the params embedded in the path as indexes of hash - foreach my $meth_param_spec ( uniq(keys %path_params ,keys %{ $method_discovery_struct->{ parameters } } ) ) - { - if ( (defined $path_params{ $meth_param_spec } ) && (defined $params->{ options }{ $meth_param_spec } ) ) ## if param option is in the path then interpolate and forget - { - $params->{ path } =~ s/\{\+*$meth_param_spec\}/$params->{options}{$meth_param_spec}/xsmg; - delete $params->{ options }{ $meth_param_spec }; ## if a GET param should not also be a BODY param + #create a hash of whatever the expected params may be + my %path_params; my $param_regex = qr/\{ \+? ([^\}]+) \}/x; + if ($params->{path} ne $discovery_struct->{origPath}) { + #check if the path was given as a custom path. If it is, just + #interpolate things directly, and assume the user is responsible + %path_params = map { $_ => 'custom' } ($params->{path} =~ /$param_regex/xg); + } else { + #label which param names are from the normal path and from the + #flat path + %path_params = map { $_ => 'plain' } ($discovery_struct->{path} =~ /$param_regex/xg); + if ($discovery_struct->{flatPath}) { + %path_params = (%path_params, + map { $_ => 'flat' } ($discovery_struct->{flatPath} =~ /$param_regex/xg) ) } - elsif ( $method_discovery_struct->{ parameters }{ $meth_param_spec }{ 'location' } eq 'path' ) ## this is a path variable - { - ## interpolate variables into URI if available and not filled - if ( $params->{ path } =~ /\{.+\}/xms ) ## there are un-interpolated variables in the path - try to fill them for this param if reqd - { - #carp( "$params->{path} includes un-filled variables " ) if $self->debug > 10; - ## requires interpolations into the URI -- consider && into containing if - if ( $params->{ path } =~ /\{\+*$meth_param_spec\}/xg ) ## eg match {jobId} or {+jobId} in 'v1/jobs/{jobId}/reports/{reportId}' - { - ## if provided as an option - if ( defined $params->{ options }{ $meth_param_spec } ) - { - carp( "DEBUG: $meth_param_spec is defined in param->{options}" ) if $self->{debug} > 10; - $params->{ path } =~ s/\{\+*$meth_param_spec\}/$params->{options}{$meth_param_spec}/xsmg; - delete $params->{ options }{ $meth_param_spec }; ## if a GET param should not also be a BODY param - } - elsif ( defined $method_discovery_struct->{ parameters }{ $meth_param_spec }{ default } ) ## not provided as an option but a default value is provided in the spec - should be assumed by server so could probbaly remove this - { - $params->{ path } =~ s/\{\+*$meth_param_spec\}/$method_discovery_struct->{parameters}{$meth_param_spec}{default}/xsmg; - } - else ## otherwise flag as an error - unable to interpolate - { - push( @teapot_errors, "$params->{path} requires interpolation value for $meth_param_spec but none provided as option and no default value provided by specification" ); - } - } + } + + + + #switch the path we're dealing with to the flat path if any of + #the parameters match the flat path + $params->{path} = $discovery_struct->{flatPath} + if grep { $_ eq 'flat' } map {$path_params{camel $_} || ()} keys %{ $params->{options} }; + + + #loop through params given, placing them in the path or query, + #or leaving them for the request body + for my $param_name ( keys %{ $params->{options} } ) { + + #first check if it needs to be interpolated into the path + if ($path_params{$param_name} || $path_params{camel $param_name}) { + #pull out the value from the hash, and remove the key + my $param_value = delete $params->{options}{$param_name}; + + #Camelize the param name if not passed in customly, allowing + #the user to pass in camelCase or snake_case param names. + #This implictly allows for a non camelCased param to be left + #alone in a custom param. + $param_name = camel $param_name if $path_params{camel $param_name}; + + #first deal with any param that doesn't have a plus, b/c + #those just get interpolated + $params->{path} =~ s/\{$param_name\}/$param_value/; + + #if there's a plus in the path spec, we need more work + if ($params->{path} =~ /\{ \+ $param_name \}/x) { + my $pattern = $discovery_struct->{parameters}{$param_name}{pattern}; + #if the given param matches google's pattern for the + #param, just interpolate it straight + if ($param_value =~ /$pattern/) { + $params->{path} =~ s/\{\+$param_name\}/$param_value/; + } else { + #N.B. perhaps support passing an arrayref or csv for those + #params such as jobs.projects.jobs.delete which have two + #dynamic parts. But for now, unnecessary + + #remove the regexy parts of the pattern to interpolate it + #into the path, assuming the user has provided just the + #dynamic portion of the param. + $pattern =~ s/^\^ | \$$//gx; my $placeholder = qr/ \[ \^ \/ \] \+ /x; + $params->{path} =~ s/\{\+$param_name\}/$pattern/x; + $params->{path} =~ s/$placeholder/$param_value/x; + push @teapot_errors, "Not enough parameters given for {+$param_name}." + if $params->{path} =~ /$placeholder/; + } } + #skip to the next run, so I don't need an else clause later + next; #I don't like nested if-elses } - elsif ( ( defined $params->{ options }{ $meth_param_spec } ) && ( $method_discovery_struct->{ parameters }{ $meth_param_spec }{ 'location' } eq 'query' )) ## check post form variables .. assume not get? - { - $params->{ options }{ $meth_param_spec } = $method_discovery_struct->{ parameters }{ $meth_param_spec }{ default } if ( defined $method_discovery_struct->{ parameters }{ $meth_param_spec }{ default } ); - push( @get_query_params, "$meth_param_spec=$params->{options}{$meth_param_spec}" ) if defined $params->{ options }{ $meth_param_spec }; - delete $params->{ options }{ $meth_param_spec }; - } + #if it's not in the list of params, then it goes in the + #request body, and our work here is done + next unless $discovery_struct->{parameters}{$param_name}; + + #it must be a GET type query param, so push the name and value + #on our param stack and take it off of the options list + push @get_query_params, $param_name, delete $params->{options}{$param_name}; } - if ( scalar(@get_query_params)>0 ) - { - #$params->{path} .= '/' unless $params->{path} =~ /\/$/mx; - $params->{path} .= '?' . join('&', @get_query_params ); + + #if there are any query params... + if ( @get_query_params ) { + #interpolate and escape the get query params built up in our + #former for loop + $params->{path} .= ($params->{path} =~ /\?/) ? '&' : '?'; + $params->{path} .= Mojo::Parameters->new(@get_query_params); + } + + #interpolate default value for path params if not given. Needed + #for things like the gmail API, where userID is 'me' by default + for my $param_name ( $params->{path} =~ /$param_regex/g ) { + my $param_value = $discovery_struct->{parameters}{$param_name}{default}; + $params->{path} =~ s/\{$param_name\}/$param_value/ if $param_value; } + push @teapot_errors, "Missing a parameter for {$_}." + for $params->{path} =~ /$param_regex/g; + #print pp $params; #exit; return @teapot_errors; @@ -398,39 +657,32 @@ warns and returns 0 on error ( eg user or config not specified etc ) =cut -######################################################## -sub has_scope_to_access_api_endpoint -{ - my ( $self, $api_ep ) = @_; - return 0 unless defined $api_ep; - return 0 if $api_ep eq ''; - my $method_spec = $self->extract_method_discovery_detail_from_api_spec( $api_ep ); - - if ( keys( %$method_spec ) > 0 ) ## empty hash indicates failure - { - my $configured_scopes = $self->ua->get_scopes_as_array(); ## get user scopes arrayref +sub has_scope_to_access_api_endpoint { + my ($self, $api_ep) = @_; + my $method_spec = $self->get_method_details($api_ep); + + if (keys %$method_spec) { + my $configured_scopes = $self->scopes; ## get user scopes arrayref ## create a hashindex to facilitate quick lookups - my %configured_scopes_hash = map { s/\/$//xr, 1 } @$configured_scopes; ## NB r switch as per https://www.perlmonks.org/?node_id=613280 to filter out any trailing '/' - my $granted = 0; ## assume permission not granted until we find a matching scope - my $required_scope_count = 0 - ; ## if the final count of scope constraints = 0 then we will assume permission is granted - this has proven necessary for the experimental Google My Business because scopes are not defined in the current discovery data as at 14/10/18 - foreach my $method_scope ( map {s/\/$//xr} @{ $method_spec->{ scopes } } ) - { + my %configured_scopes_hash = map { (s/\/$//xr, 1) } @$configured_scopes; + ## NB r switch as per https://www.perlmonks.org/?node_id=613280 to filter + #out any trailing '/' + my $granted = 0; + ## assume permission not granted until we find a matching scope + my $required_scope_count = 0; + ## if the final count of scope constraints = 0 then we will assume permission is granted - this has proven necessary for the experimental Google My Business because scopes are not defined in the current discovery data as at 14/10/18 + for my $method_scope (map { s/\/$//xr } @{ $method_spec->{scopes} }) { $required_scope_count++; - $granted = 1 if defined $configured_scopes_hash{ $method_scope }; - last if $granted; + $granted = 1 if defined $configured_scopes_hash{$method_scope}; + last if $granted; } - $granted = 1 if ( $required_scope_count == 0 ); + $granted = 1 if $required_scope_count == 0; return $granted; - } - else - { - return 0; ## cannot get method spec - warnings should have already been issued - returning - to indicate access denied + } else { + return 0; } } -######################################################## - #TODO: Consider rename to return_fetched_google_v1_apis_discovery_structure @@ -495,13 +747,13 @@ sub has_scope_to_access_api_endpoint -=head2 C +=head2 C returns the cached version if avaiable in CHI otherwise retrieves discovery data via HTTP, stores in CHI cache and returns as a Perl data structure. - my $hashref = $self->get_api_discovery_for_api_id( 'gmail' ); - my $hashref = $self->get_api_discovery_for_api_id( 'gmail:v3' ); + my $hashref = $self->get_api_document( 'gmail' ); + my $hashref = $self->get_api_document( 'gmail:v3' ); returns the api discovery specification structure ( cached by CHI ) for api id ( eg 'gmail ') @@ -517,25 +769,26 @@ discovery specification for that method ( API Endpoint ). methods_available_for_google_api_id('gmail') -=head2 C +=head2 C - $my $api_detail = $gapi->discovery->extract_method_discovery_detail_from_api_spec( 'gmail.users.settings' ); + $my $api_detail = $gapi->discovery->get_method_details( 'gmail.users.settings' ); returns a hashref representing the discovery specification for the method identified by $tree in dotted API format such as texttospeech.text.synthesize returns an empty hashref if not found -=head2 C +=head2 C Returns an array list of all the available API's described in the API Discovery Resource that is either fetched or cached in CHI locally for 30 days. - my $r = $agent->list_of_available_google_api_ids(); + my $r = $agent->list_api_ids(); print "List of API Services ( comma separated): $r\n"; - my @list = $agent->list_of_available_google_api_ids(); + my @list = $agent->list_api_ids(); +To check for just one service id, use C instead. =head1 FEATURES diff --git a/lib/WebService/GoogleAPI/Client/AccessToken.pm b/lib/WebService/GoogleAPI/Client/AccessToken.pm new file mode 100644 index 0000000..40522aa --- /dev/null +++ b/lib/WebService/GoogleAPI/Client/AccessToken.pm @@ -0,0 +1,40 @@ +package WebService::GoogleAPI::Client::AccessToken; +use strictures; + +# VERSION + +# ABSTRACT: A small class for bundling user and scopes with a token +use Moo; + +use overload '""' => sub { shift->token }; + +has [ qw/token user scopes/ ] => + is => 'ro', + required => 1; + +=head1 SYNOPSIS + + my $token = $gapi->get_access_token # returns this class + # { + # token => '...', + # user => 'the-user-that-it's-for', + # scopes => [ 'the', 'scopes', 'that', 'its', 'for' ] + # } + # + my $res = ... # any api call here + $res->{_token} # the token the call was made with + +This is a simple class which contains the data related to a Google Cloud access token +that bundles the related user and scopes. + +It overloads stringification so that interpolating it in, say an auth header, +will return just the token. + +This is for introspection purposes, so if something goes wrong, you can check +the response from your request and check the C<_token> hash key on that object. +Note that this is subject to change in future versions (there's probably a saner +way to do this). + +=cut + +9008 diff --git a/lib/WebService/GoogleAPI/Client/AuthStorage.pm b/lib/WebService/GoogleAPI/Client/AuthStorage.pm index 0aa30ff..f09d20d 100755 --- a/lib/WebService/GoogleAPI/Client/AuthStorage.pm +++ b/lib/WebService/GoogleAPI/Client/AuthStorage.pm @@ -1,86 +1,169 @@ use strictures; - package WebService::GoogleAPI::Client::AuthStorage; -# ABSTRACT: JSON File Persistence for Google OAUTH Project and User Access Tokens - -## is client->auth_storage -## or is Client->ua->auth_storage delegated as auth_storage to client +# ABSTRACT: Role for classes which store your auth credentials -## or is UserAgent->credentials +# VERSION -use Moo; +use Moo::Role; use Carp; -use WebService::GoogleAPI::Client::AuthStorage::ConfigJSON; +use WebService::GoogleAPI::Client::AccessToken; +=head1 SYNOPSIS -has 'storage' => ( is => 'rw', default => sub { WebService::GoogleAPI::Client::AuthStorage::ConfigJSON->new } ); # by default -has 'is_set' => ( is => 'rw', default => 0 ); + package My::Cool::AuthStorage::Class; + use Moo; + with 'WebService::GoogleAPI::Client::AuthStorage'; + ... # implement the necessary functions -=method setup + package main; + use WebService::GoogleAPI::Client; + use My::Cool::AuthStorage::Class; + my $gapi = WebService::GoogleAPI::Client->new( + auth_storage => My::Cool::AuthStorage::Class->new + ); + ... # and now your class manages the access_tokens -Set appropriate storage +WebService::GoogleAPI::Client::AuthStorage is a Moo::Role for auth storage backends. +This dist comes with two consumers, L +and L. See those for more info +on how you can use them with L. - my $auth_storage = WebService::GoogleAPI::Client::AuthStorage->new; - $auth_storage->setup; # by default will be config.json - $auth_storage->setup({type => 'jsonfile', path => '/abs_path' }); +This is a role which defines the interface that L +will use when making requests. +=cut +has user => is => 'rw'; +=attr user + +The user that an access token should be returned for. Is read/write. May be +falsy, depending on the backend. =cut -sub setup -{ - my ( $self, $params ) = @_; - if ( $params->{ type } eq 'jsonfile' ) - { - $self->storage->pathToTokensFile( $params->{ path } ); - $self->storage->setup; - $self->is_set( 1 ); - } - else - { - croak "Unknown storage type."; - } - return $self; -} +# this is managed by the BUILD in ::Client::UserAgent, +# and by the BUILD in ::Client +has ua => is => 'rw', weak_ref => 1; +=attr ua + +An weak reference to the WebService::GoogleAPI::Client::UserAgent that this is +attached to, so that access tokens can be refreshed. The UserAgent object manages this. + +=cut -### Below are list of methods that each Storage subclass must provide -=method get_credentials_for_refresh +=head1 REQUIRES -Return all parameters that is needed for Mojo::Google::AutoTokenRefresh::refresh_access_token() function: client_id, client_secret and refresh_token +It requires the consuming class to implement functions with the following names: -$c->get_credentials_for_refresh('examplemail@gmail.com') +=begin :list -This method must have all subclasses of WebService::GoogleAPI::Client::AuthStorage += scopes +A list of scopes that you expect the access token to be valid for. This could be +read/write, but it's not necessary. Some backends may have different credentials +for different sets of scopes (though as an author, you probably want to just +have the whole set you need upfront). + += refresh_access_token + +A method which will refresh the access token if it has been determined to have +expired. Take a look at the two consumers which come with this dist for +examples of how to renew user credentials and service account credentials. + += get_access_token + +A method which will return the access token for the current user and scopes. +This method is wrapped to augment whatever has been returned with user and +scopes data for introspection by making a +WebService::GoogleAPI::Client::AccessToken instance. If you choose to return such an instance yourself, then it will be left alone. + +=end :list =cut +requires qw/ + scopes + refresh_access_token + get_access_token +/; -sub get_credentials_for_refresh -{ - my ( $self, $user ) = @_; - return $self->storage->get_credentials_for_refresh( $user ); -} +around get_access_token => sub { + my ($orig, $self) = @_; + my $user = $self->user; + my $scopes = $self->scopes; -sub get_access_token_from_storage -{ - my ( $self, $user ) = @_; - return $self->storage->get_access_token_from_storage( $user ); -} + my $token = $self->$orig; + my $class = 'WebService::GoogleAPI::Client::AccessToken'; + return $token if ref $token eq $class; + return WebService::GoogleAPI::Client::AccessToken->new( + user => $user, token => $token, scopes => $scopes ); +}; -sub set_access_token_to_storage -{ - my ( $self, $user, $access_token ) = @_; - return $self->storage->set_access_token_to_storage( $user, $access_token ); -} +=method refresh_user_token + +Makes the call to Google's OAuth API to refresh a token for a user. +Requires one parameter, a hashref with the keys: +=begin :list -sub get_scopes_from_storage_as_array -{ - my ( $self ) = @_; - return $self->storage->get_scopes_from_storage_as_array(); += client_id Your OAuth Client ID + += client_secret Your OAuth Client Secret + += refresh_token The refresh token for the user + +=end :list + +Will return the token from the API, for the backend to store (wherever it pleases). + +Will die with the error message from Google if the refresh fails. + +=cut + +sub refresh_user_token { + my ($self, $params) = @_; + my $tx = $self->ua->post('https://www.googleapis.com/oauth2/v4/token' => + form => { %$params, grant_type => 'refresh_token' } + ); + my $new_token = $tx->res->json('/access_token'); + unless ($new_token) { + croak "Failed to refresh access token: ", + join ' - ', map $tx->res->json("/$_"), qw/error error_description/ + if $tx->res->json; + # if the error doesn't come from google + croak "Unknown error refreshing access token"; + } + + return $new_token } +=method refresh_service_account_token + +Makes the call to Google's OAuth API to refresh a token for a service account. +Requires one parameter, a L object already set with the user +and scopes requested. + +Will return the token from the API, for the backend to store (wherever it pleases). + +Will die with the error message from Google if the refresh fails. + +=cut + +sub refresh_service_account_token { + my ($self, $jwt) = @_; + my $tx = $self->ua->post('https://www.googleapis.com/oauth2/v4/token' => form => + $jwt->as_form_data + ); + my $new_token = $tx->res->json('/access_token'); + unless ($new_token) { + croak "Failed to get access token: ", + join ' - ', map $tx->res->json("/$_"), qw/error error_description/ + if $tx->res->json; + # if the error doesn't come from google + croak "Unknown error getting access token"; + } + return $new_token +} + 1; diff --git a/lib/WebService/GoogleAPI/Client/AuthStorage/ConfigJSON.pm b/lib/WebService/GoogleAPI/Client/AuthStorage/ConfigJSON.pm deleted file mode 100755 index 7c647b3..0000000 --- a/lib/WebService/GoogleAPI/Client/AuthStorage/ConfigJSON.pm +++ /dev/null @@ -1,84 +0,0 @@ -use strictures; - -package WebService::GoogleAPI::Client::AuthStorage::ConfigJSON; - -# ABSTRACT: Specific methods to fetch tokens from JSON data sources - -use Moo; -use Config::JSON; -use Carp; - -has 'pathToTokensFile' => ( is => 'rw', default => 'gapi.json' ); # default is gapi.json - -# has 'tokensfile'; # Config::JSON object pointer -my $tokensfile; -has 'debug' => ( is => 'rw', default => 0 ); - -## cringe .. getters and setters, tokenfile?, global $tokensfile? .. *sigh* - -sub setup -{ - my ( $self ) = @_; - $tokensfile = Config::JSON->new( $self->pathToTokensFile ); - return $self; -} - -sub get_credentials_for_refresh -{ - my ( $self, $user ) = @_; - return { - client_id => $self->get_client_id_from_storage(), - client_secret => $self->get_client_secret_from_storage(), - refresh_token => $self->get_refresh_token_from_storage( $user ) - }; -} - -sub get_token_emails_from_storage -{ - my $tokens = $tokensfile->get( 'gapi/tokens' ); - return [keys %$tokens]; -} - - -sub get_client_id_from_storage -{ - return $tokensfile->get( 'gapi/client_id' ); -} - -sub get_client_secret_from_storage -{ - return $tokensfile->get( 'gapi/client_secret' ); -} - -sub get_refresh_token_from_storage -{ - my ( $self, $user ) = @_; - carp "get_refresh_token_from_storage(" . $user . ")" if $self->debug; - return $tokensfile->get( 'gapi/tokens/' . $user . '/refresh_token' ); -} - -sub get_access_token_from_storage -{ - my ( $self, $user ) = @_; - return $tokensfile->get( 'gapi/tokens/' . $user . '/access_token' ); -} - -sub set_access_token_to_storage -{ - my ( $self, $user, $token ) = @_; - return $tokensfile->set( 'gapi/tokens/' . $user . '/access_token', $token ); -} - -sub get_scopes_from_storage -{ - my ( $self ) = @_; - return $tokensfile->get( 'gapi/scopes' ); ## NB - returns an array - is stored as space sep list -} - -sub get_scopes_from_storage_as_array -{ - my ( $self ) = @_; - return [split( ' ', $tokensfile->get( 'gapi/scopes' ) )]; ## NB - returns an array - is stored as space sep list -} - -1; diff --git a/lib/WebService/GoogleAPI/Client/AuthStorage/GapiJSON.pm b/lib/WebService/GoogleAPI/Client/AuthStorage/GapiJSON.pm new file mode 100644 index 0000000..3e9c9b6 --- /dev/null +++ b/lib/WebService/GoogleAPI/Client/AuthStorage/GapiJSON.pm @@ -0,0 +1,139 @@ +use strictures; + +package WebService::GoogleAPI::Client::AuthStorage::GapiJSON; + +# VERSION +# ABSTRACT: Auth Storage Backend based on gapi.json + +use Moo; +use Config::JSON; +use Carp; + +with 'WebService::GoogleAPI::Client::AuthStorage'; + +=head1 SYNOPSIS + +This class provides an auth backend for gapi.json files produced with the provided L +script. This is used for user credentials. For service accounts, please see L. + +In future versions, I hope to provide the functionality of L as a +L, so you can provide this flow in your app rather than having to run it offline. + +This class mixes in L, and provides +all attributes and methods from that role. As noted there, the C is usually managed by +the L object this is set on. + +=attr path + +The location of the gapi.json file. Default to gapi.json in the current directory. + +=cut +has 'path' => ( is => 'rw', default => './gapi.json' ); # default is gapi.json + +=attr tokensfile + +A Config::JSON object that contains the parsed gapi.json file. Authomatically set +at object instantiation. + +=cut +has 'tokensfile' => ( is => 'rw' ); # Config::JSON object pointer + +# NOTE- this type of class has getters and setters b/c the implementation of +# getting and setting depends on what's storing + +sub BUILD { + my ($self) = @_; + $self->tokensfile(Config::JSON->new($self->path)); + my $missing = grep !$_, map $self->get_from_storage($_), qw/client_id client_secret/; + croak <get_from_storage('access_token'); + return $value +} + +=method refresh_access_token + +This will refresh the access token for the currently set C. Will write the +new token back into the gapi.json file. + +If you don't have a refresh token for that user, it will die with the following message: + +If your credentials are missing the refresh_token - consider removing the auth at +https://myaccount.google.com/permissions as The oauth2 server will only ever mint one refresh +token at a time, and if you request another access token via the flow it will operate as if +you only asked for an access token. + +=cut +sub refresh_access_token { + my ($self) = @_; + my %p = map { ( $_ => $self->get_from_storage($_) ) } + qw/client_id client_secret refresh_token/; + + croak <user; + + my $new_token = $self->refresh_user_token(\%p); + + $self->tokensfile->set("gapi/tokens/$user/access_token", $new_token); + return $new_token; +} + +sub get_token_emails_from_storage { + my ($self) = @_; + my $tokens = $self->get_from_storage('tokens'); + return [keys %$tokens]; +} + +=method get_from_storage + +A method to get stored fields from the gapi.json file. Will retrieve tokens for +the current user, and other fields from the global config. + +=cut +sub get_from_storage { + my ($self, $key) = @_; + if ($key =~ /_token/) { + return $self->tokensfile->get("gapi/tokens/${\$self->user}/$key") + } else { + return $self->tokensfile->get("gapi/$key") + } +} + +sub get_scopes_from_storage_as_array { + carp 'get_scopes_from_storage_as_array is being deprecated, please use the more succint scopes accessor'; + return $_[0]->scopes +} + +# NOTE - the scopes are stored as a space seperated list, and this method +# returns an arrayref +# +=method scopes + +Read-only accessor returning the list of scopes configured in the gapi.json file. +=cut + +sub scopes { + my ($self) = @_; + return [split / /, $self->tokensfile->get('gapi/scopes')]; +} + +9011; diff --git a/lib/WebService/GoogleAPI/Client/AuthStorage/ServiceAccount.pm b/lib/WebService/GoogleAPI/Client/AuthStorage/ServiceAccount.pm new file mode 100644 index 0000000..0e1b35b --- /dev/null +++ b/lib/WebService/GoogleAPI/Client/AuthStorage/ServiceAccount.pm @@ -0,0 +1,146 @@ +use strictures; +package WebService::GoogleAPI::Client::AuthStorage::ServiceAccount; + +# VERSION + +# ABSTRACT: Manage access tokens from a service account file + +=head1 SYNOPSIS + +This class provides an auth backend for service account files downloaded from +your google cloud console. For user accounts, please see +L. + +This backend is only for explicitly passing a service account JSON file. It will +not attempt to find one by itself, or to do the Application Default Credentials, +at least yet. + +This backend will cache tokens in memory for any set of scopes requested, and +for any user you ask to impersonate (more on that later). + +This class mixes in L, and provides +all attributes and methods from that role. As noted there, the C is usually managed by +the L object this is set on. + +=cut + +use Moo; +use Carp; +use Mojo::JWT::Google; + +=attr scopes + +A read/write attribute containing the scopes the service account is asking access to. +Will coerce a space seperated list of scopes into the required arrayref of scopes. + +=cut +has scopes => + is => 'rw', + coerce => sub { + my $arg = shift; + return [ split / /, $arg ] unless ref $arg eq 'ARRAY'; + return $arg + }, + default => sub { [] }; + +=attr user + +The user you want to impersonate. Defaults to the empty string, which signifies +no user. In order to impersonate a user, you need to have domain-wide delegation +set up for the service account. + +=cut +has user => + is => 'rw', + coerce => sub { $_[0] || '' }, + default => ''; + +with 'WebService::GoogleAPI::Client::AuthStorage'; + +=attr path + +The location of the file containing the service account credentials. This is +downloaded from your google cloud console's service account page. + +=cut +has path => + is => 'rw', + required => 1, + trigger => 1; + +sub _trigger_path { + my ($self) = @_; + $self->jwt( + Mojo::JWT::Google->new(from_json => $self->path) + ); +} + + +=attr jwt + +An instance of Mojo::JWT::Google used for retrieving the access tokens. This is +built whenever the C attribute is set. + +=cut +has jwt => + is => 'rw'; + +=attr tokens + +A hash for caching the tokens that have been retrieved by this object. It caches on +scopes (via the C method) and then user. + +=cut +has tokens => + is => 'ro', + default => sub { {} }; + +=method get_access_token + +Return an access token for the current user (if any) and scopes from the cache if exists, +otherwise retrieve a new token with C. + +=cut +sub get_access_token { + my ($self) = @_; + my $token = $self->tokens->{$self->scopes_string}{$self->user}; + return $self->refresh_access_token unless $token; + return $token +} + +=method refresh_access_token + +Retrieve an access token for the current user (if any) and scopes from Google's auth API, +using a JWT. + +=cut +sub refresh_access_token { + my ($self) = @_; + croak "Can't get a token without a set of scopes" unless @{$self->scopes}; + + $self->jwt->scopes($self->scopes); + if ($self->user) { + $self->jwt->user_as($self->user) + } else { + $self->jwt->user_as(undef) + } + + my $new_token = $self->refresh_service_account_token($self->jwt); + + $self->tokens->{$self->scopes_string}{$self->user} = $new_token; + return $new_token +} + +=method scopes_string + +Return the list of scopes as a space seperated string. + +=cut + +sub scopes_string { + my ($self) = @_; + return join ' ', @{$self->scopes} +} + + +9001 diff --git a/lib/WebService/GoogleAPI/Client/Credentials.pm b/lib/WebService/GoogleAPI/Client/Credentials.pm deleted file mode 100644 index 69ff33f..0000000 --- a/lib/WebService/GoogleAPI/Client/Credentials.pm +++ /dev/null @@ -1,52 +0,0 @@ -use strictures; - -package WebService::GoogleAPI::Client::Credentials; - -# ABSTRACT: Credentials for particular Client instance. You can use this module as singleton also if you need to share -# credentials between two or more modules - - -use Carp; -use Moo; -with 'MooX::Singleton'; - - -has 'access_token' => ( is => 'rw' ); -has 'user' => ( is => 'rw', trigger => \&get_access_token_for_user ); # full gmail, like peter@shotgundriver.com -has 'auth_storage' => ( is => 'rw', default => sub { WebService::GoogleAPI::Client::AuthStorage->new } ); # dont delete to able to configure - -=method get_access_token_for_user - -Automatically get access_token for current user if auth_storage is set - -=cut - -sub get_access_token_for_user -{ - my ( $self ) = @_; - if ( $self->auth_storage->is_set ) - { # chech that auth_storage initialized fine - $self->access_token( $self->auth_storage->get_access_token_from_storage( $self->user ) ); - } - else - { - croak q/Can get access token for specified user because storage isn't set/; - } - return $self; ## ?? is self the access token for user? -} - -sub get_scopes_as_array -{ - my ( $self ) = @_; - if ( $self->auth_storage->is_set ) - { # chech that auth_storage initialized fine - return $self->access_token( $self->auth_storage->get_scopes_from_storage_as_array() ); - } - else - { - croak q/Can get access token for specified user because storage isn't set/; - } - -} - -1; diff --git a/lib/WebService/GoogleAPI/Client/Discovery.pm b/lib/WebService/GoogleAPI/Client/Discovery.pm index 553dffb..350f215 100644 --- a/lib/WebService/GoogleAPI/Client/Discovery.pm +++ b/lib/WebService/GoogleAPI/Client/Discovery.pm @@ -2,6 +2,8 @@ use strictures; package WebService::GoogleAPI::Client::Discovery; +# VERSION + # ABSTRACT: Google API discovery service =head2 MORE INFORMATION @@ -13,531 +15,455 @@ L Not using Swagger but it is interesting - L for Swagger Specs. -L - contains code for parsing discovery structures +L - contains code for parsing discovery structures includes a chi property that is an instance of CHI using File Driver to cache discovery resources for 30 days say $client-dicovery->chi->root_dir(); ## provides full file path to temp storage location used for caching -=head2 TODO - -=over 2 - -=item * handle 403 ( Daily Limit for Unauthenticated Use Exceeded.) errors when reqeusting a discovrey resource for a service but do we have access to authenticated reqeusts? - -=back - =cut use Moo; use Carp; use WebService::GoogleAPI::Client::UserAgent; -use List::Util qw/uniq/; ## are these util dependencies necessary? -use Hash::Slice qw/slice/; +use List::Util qw/uniq reduce/; +use List::SomeUtils qw/pairwise/; use Data::Dump qw/pp/; -use CHI; # Caching .. NB Consider reviewing https://metacpan.org/pod/Mojo::UserAgent::Role::Cache -# use feature - -## NB - I am not familiar with this moosey approach to OO so there may be obvious errors - keep an eye on this. - -has 'ua' => ( is => 'rw', default => sub { WebService::GoogleAPI::Client::UserAgent->new }, lazy => 1 ); ## typically shared with parent instance of Client which sets on new -has 'debug' => ( is => 'rw', default => 0, lazy => 1 ); -has 'chi' => ( is => 'rw', default => sub { CHI->new( driver => 'File', namespace => __PACKAGE__ ) }, lazy => 1 ); ## i believe that this gives priority to param if provided ? - - -my $stats = { - network => { - # last request timestamp - # last request response_code - # last request response_code_count - # total bytes sent - # total bytes received - }, - cache => { - get => 0, - # last request timestamp - # last request response_code - # last request response_code_count - # total bytes sent - # total bytes received - } -}; -=head1 METHODS - - -=head2 get_api_discovery_for_api_id +use CHI; + +has ua => ( + is => 'rw', + default => sub { WebService::GoogleAPI::Client::UserAgent->new } +); +has debug => (is => 'rw', default => 0); +has 'chi' => ( + is => 'rw', + default => sub { CHI->new(driver => 'File', namespace => __PACKAGE__) }, + lazy => 1 +); ## i believe that this gives priority to param if provided ? +has 'stats' => is => 'rw', + default => sub { { network => { get => 0 }, cache => { get => 0 } } }; -returns the cached version if avaiable in CHI otherwise retrieves discovery data via HTTP, stores in CHI cache and returns as -a Perl data structure. +=head1 METHODS - my $hashref = $self->get_api_discovery_for_api_id( 'gmail' ); - my $hashref = $self->get_api_discovery_for_api_id( 'gmail:v3' ); - my $hashref = $self->get_api_discovery_for_api_id( 'gmail:v3.users.list' ); - my $hashref = $self->get_api_discovery_for_api_id( { api=> 'gmail', version => 'v3' } ); ## nb enclosing bracer - must be hashref +=head2 get_with_cache -NB: if deeper structure than the api_id is provided then only the head is used + my $hashref = $disco->get_with_cache($url, $force, $authenticate) -so get_api_discovery_for_api_id( 'gmail' ) is the same as get_api_discovery_for_api_id( 'gmail.some.child.method' ) +Retrieves the given API URL, retrieving and caching the returned +JSON. If it gets a 403 Unauthenticated error, then it will try +again using the credentials that are save on this instances 'ua'. -returns the api discovery specification structure ( cached by CHI ) for api id ( eg 'gmail ') - -returns the discovery data as a hashref, an empty hashref on certain failing conditions or croaks on critical errors. +If passed a truthy value for $force, then will not use the cache. +If passed a truthy value for $authenticate, then will make the +request with credentials. =cut -sub get_api_discovery_for_api_id -{ - my ( $self, $params ) = @_; - ## TODO: warn if user doesn't have the necessary scope .. no should stil be able to examine - ## TODO: consolidate the http method calls to a single function - ie - discover_all - simplistic quick fix - assume that if no param then endpoint is as per discover_all - - $params = { api => $params } if ref( $params ) eq ''; ## scalar parameter not hashref - so assume is intended to be $params->{api} - - ## trim any resource, method or version details in api id - if ( $params->{ api } =~ /([^:]+):(v[^\.]+)/ixsm ) - { - $params->{ api } = $1; - $params->{ version } = $2; - } - if ( $params->{ api } =~ /^(.*?)\./xsm ) ## we only want the api and not the children so trime them out here - { - $params->{ api } = $1; - - } - - - croak( "get_api_discovery_for_api_id called with api param undefined" . pp $params) unless defined $params->{ api }; - $params->{ version } = $self->latest_stable_version( $params->{ api } ) unless defined $params->{ version }; +sub get_with_cache { + my ($self, $key, $force, $authorized) = @_; - croak( "get_api_discovery_for_api_id called with empty api param defined" . pp $params) if $params->{ api } eq ''; - croak( "get_api_discovery_for_api_id called with empty version param defined" . pp $params) if $params->{ version } eq ''; + my $expiration = $self->chi->get_expires_at($key) // 0; - my $aapis = $self->available_APIs(); - - - my $api_verson_urls = {}; - for my $api ( @{ $aapis } ) - { - for ( my $i = 0; $i < scalar @{ $api->{ versions } }; $i++ ) - { - $api_verson_urls->{ $api->{ name } }{ $api->{ versions }[$i] } = $api->{ discoveryRestUrl }[$i]; - } - } - croak( "Unable to determine discovery URI for any version of $params->{api}" ) unless defined $api_verson_urls->{ $params->{ api } }; - croak( "Unable to determine discovery URI for $params->{api} $params->{version}" ) unless defined $api_verson_urls->{ $params->{ api } }{ $params->{ version } }; - my $api_discovery_uri = $api_verson_urls->{ $params->{ api } }{ $params->{ version } }; - - #carp "get_api_discovery_for_api_id requires data from $api_discovery_uri" if $self->debug; - if ( my $dat = $self->chi->get( $api_discovery_uri ) ) ## clobbers some of the attempted thinking further on .. just return it for now if it's there - { - #carp pp $dat; - $self->{stats}{cache}{get}++; - return $dat; - } - - if ( my $expires_at = $self->chi->get_expires_at( $api_discovery_uri ) ) ## maybe this isn't th ebest way to check if get available. - { - carp "CHI '$api_discovery_uri' cached data with root = " . $self->chi->root_dir . "expires in ", scalar( $expires_at ) - time(), " seconds\n" if $self->debug; - - #carp "Value = " . pp $self->chi->get( $api_discovery_uri ) if $self->debug ; - return $self->chi->get( $api_discovery_uri ); - - } - else - { - carp "'$api_discovery_uri' not in cache - fetching it" if $self->debug; - ## TODO: better handle failed response - if 403 then consider adding in the auth headers and trying again. - #croak("Huh $api_discovery_uri"); - my $ret = $self->ua->validated_api_query( $api_discovery_uri ); # || croak("Failed to retrieve $api_discovery_uri");; - if ( $ret->is_success ) - { - my $dat = $ret->json || croak( "failed to convert $api_discovery_uri return data in json" ); - - #carp("dat1 = " . pp $dat); - $self->chi->set( $api_discovery_uri, $dat, '30 days' ); - $self->{stats}{network}{get}++; - return $dat; - - #my $ret_data = $self->chi->get( $api_discovery_uri ); - #carp ("ret_data = " . pp $ret_data) unless ref($ret_data) eq 'HASH'; - #return $ret_data;# if ref($ret_data) eq 'HASH'; - #croak(); - #$self->chi->remove( $api_discovery_uri ) unless eval '${^TAINT}'; ## if not hashref then assume is corrupt so delete it + my $will_expire = $expiration - time(); + if ($will_expire > 0 && not $force) { + carp "discovery_data cached data expires in $will_expire seconds" + if $self->debug > 2; + my $ret = $self->chi->get($key); + croak 'was expecting a HASHREF!' unless ref $ret eq 'HASH'; + $self->stats->{cache}{get}++; + return $ret; + } else { + my $ret; + if ($authorized) { + $ret = $self->ua->validated_api_query($key); + $self->stats->{network}{authorized}++; + } else { + $ret = $self->ua->get($key)->res; } - else - { - ## TODO - why is this failing for certain resources ?? because the urls contain a '$' ? because they are now authenticated? - carp( "Fetching resource failed - $ret->message" ); ## was croaking - carp( pp $ret ); - return {}; #$ret; + if ($ret->is_success) { + my $all = $ret->json; + $self->stats->{network}{get}++; + $self->chi->set($key, $all, '30d'); + return $all; + } else { + if ($ret->code == 403 && !$authorized) { + return $self->get_with_cache($key, $force, 1); + } + croak $ret->message; } } - croak( "something went wrong in get_api_discovery_for_api_id key = '$api_discovery_uri' - try again to see if data corruption has been flushed for " . pp $params); - - #return $self->chi->get( $api_discovery_uri ); - #croak('never gets here'); + return {}; } - =head2 C -TODO: Consider rename to return_fetched_google_v1_apis_discovery_structure + my $hashref = $disco->discover_all($force, $authenticate) -TODO - handle auth required error and resubmit request with OAUTH headers if response indicates - access requires auth ( when exceed free access limits ) +Return details about all Available Google APIs as provided by Google or in CHI Cache. +Does the fetching with C, and arguments are as above. - Return details about all Available Google APIs as provided by Google or in CHI Cache +On Success: Returns HASHREF with keys discoveryVersion,items,kind +On Failure: dies a horrible death. You probably don't want to continue in that case. - On Success: Returns HASHREF with keys discoveryVersion,items,kind - On Failure: Warns and returns empty hashref +SEE ALSO: available_APIs, list_of_available_google_api_ids - my $d = WebService::GoogleAPI::Client::Discovery->new; - print Dumper $d; +=cut - WebService::GoogleAPI::Client::Discovery->discover_all(); +sub discover_key {'https://www.googleapis.com/discovery/v1/apis'} - $client->discover_all(); - $client->discover_all(1); ## NB if include a parameter that evaluates to true such as '1' then the cache is flushed with a new version +sub discover_all { + my $self = shift; + $self->get_with_cache($self->discover_key, @_); +} +#TODO- double triple check that we didn't break anything with the +#hashref change +=head2 C -SEE ALSO: available_APIs, list_of_available_google_api_ids +Return hashref keyed on api name, with arrays of versions, links to +documentation, and links to the url for that version's API document. -=cut + { + youtube => { + version => [ 'v3', ... ] + documentationLink => [ ..., ... ] , + discoveryRestUrl => [ ..., ... ] , + }, + gmail => { + ... + } + } -sub discover_all -{ +Used internally to pull relevant discovery documents. - my ( $self, $force ) = @_; +=cut - if ( my $expires_at = $self->chi->get_expires_at( 'https://www.googleapis.com/discovery/v1/apis' ) && not $force ) - { - carp "discovery_data cached data expires in ", scalar( $expires_at ) - time(), " seconds\n" if ( $self->debug > 2 ); - my $ret = $self->chi->get( 'https://www.googleapis.com/discovery/v1/apis' ); - croak( 'CHI Discovery should be a hash - got something other' ) unless ref( $ret ) eq 'HASH'; - $self->{stats}{cache}{get}++; - return $ret; - } - else ## - { - #return $self->chi->get('https://www.googleapis.com/discovery/v1/apis') if ($self->chi->get('https://www.googleapis.com/discovery/v1/apis')); - my $ret = $self->ua->validated_api_query( 'https://www.googleapis.com/discovery/v1/apis' ); +#TODO- maybe cache this on disk too? +my $available; +sub _invalidate_available { + $available = undef; +} - # if ( $ret->is_status_class(200) ) ## older versions of Mojo::Message::Response don't support is_success .. Require V > 7.12 - if ( $ret->is_success ) - { - my $all = $ret->json; - $self->{stats}{network}{get}++; - $self->chi->set( 'https://www.googleapis.com/discovery/v1/apis', $all, '30d' ); - return $self->chi->get( 'https://www.googleapis.com/discovery/v1/apis' ); +sub available_APIs { + #cache this crunch + return $available if $available; + + my ($self) = @_; + my $d_all = $self->discover_all; + croak 'no items in discovery data' unless defined $d_all->{items}; + + #grab only entries with the four keys we want + #and strip other keys + my @keys = qw/name version documentationLink discoveryRestUrl/; + my @relevant; + for my $i (@{ $d_all->{items} }) { + next unless @keys == grep { exists $i->{$_} } @keys; + push @relevant, { %{$i}{@keys} }; + }; + + my $reduced = reduce { + for my $key (qw/version documentationLink discoveryRestUrl/) { + $a->{$b->{name}}->{$key} //= []; + push @{$a->{$b->{name}}->{$key}}, $b->{$key}; } - else - { + $a; + } {}, @relevant; - carp( "$ret->message" ); ## should probably croak - return {}; - } - } - return {}; + #store it away globally + $available = $reduced; } -=head2 C +=head2 C Allows you to augment the cached stored version of the discovery structure - augment_discover_all_with_unlisted_experimental_api( - { - 'version' => 'v4', - 'preferred' => 1, - 'title' => 'Google My Business API', - 'description' => 'The Google My Business API provides an interface for managing business location information on Google.', - 'id' => 'mybusiness:v4', - 'kind' => 'discovery#directoryItem', - 'documentationLink' => "https://developers.google.com/my-business/", - 'icons' => { - "x16"=> "http://www.google.com/images/icons/product/search-16.gif", - "x32"=> "http://www.google.com/images/icons/product/search-32.gif" - }, - 'discoveryRestUrl' => - 'https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p2.json', - 'name' => 'mybusiness' - } ); - -if there is a conflict with the existing then warn and return the existing data without modification - -on success just returns the augmented structure - -NB - does not interpolate schema object '$ref' values. + $augmented_document = $disco->augment_with({ + 'version' => 'v4', + 'preferred' => 1, + 'title' => 'Google My Business API', + 'description' => 'The Google My Business API provides an interface for managing business location information on Google.', + 'id' => 'mybusiness:v4', + 'kind' => 'discovery#directoryItem', + 'documentationLink' => "https://developers.google.com/my-business/", + 'icons' => { + "x16" => "http://www.google.com/images/icons/product/search-16.gif", + "x32" => "http://www.google.com/images/icons/product/search-32.gif" + }, + 'discoveryRestUrl' => 'https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p2.json', + 'name' => 'mybusiness' + }); + +This can also be used to overwrite the cached structure. + +Can also be called as C, which is +being deprecated for being plain old too long. =cut +sub augment_discover_all_with_unlisted_experimental_api { + my ($self, $api_spec) = @_; + carp <augment_with($api_spec); +} -sub augment_discover_all_with_unlisted_experimental_api -{ - my ( $self, $api_spec ) = @_; +sub augment_with { + my ($self, $api_spec) = @_; my $all = $self->discover_all(); - #warn pp $all; ## fail if any of the expected fields are not provided - foreach my $field ( qw/version title description id kind documentationLink discoveryRestUrl name/ ) ## icons preferred - { - if ( not defined $api_spec->{ $field } ) - { - carp( "required $field in provided experimental api spec in not defined - returning without augmentation" ); - return $all; + for my $field ( + qw/version title description id kind documentationLink + discoveryRestUrl name/ + ) { + if (not defined $api_spec->{$field}) { + carp("required $field in provided api spec missing"); } - } + push @{ $all->{items} }, $api_spec; + $self->chi->set($self->discover_key, $all, '30d'); + $self->_invalidate_available; + return $all +} - ## warn and return existing data if entry appears to already exist - foreach my $i ( @{ $all->{ items } } ) - { - $i->{ id } = '' unless defined $i->{ id }; - if ( ( $i->{ name } eq $api_spec->{ name } ) && ( $i->{ version } eq $api_spec->{ version } ) ) - { - carp( "There is already an entry with name = $i->{name} and version = $i->{version} - no modifications saved" ); - return $all; - } - if ( $i->{ id } eq $api_spec->{id} ) - { - carp( "There is already an entry with id = $i->{id} - no modifications saved" ); - return $all; - } - } - push @{ $all->{ items } }, $api_spec; - $self->chi->set( 'https://www.googleapis.com/discovery/v1/apis', $all, '30d' ); - return $self->chi->get( 'https://www.googleapis.com/discovery/v1/apis' ); -} +=head2 C +Return 1 if Google Service API ID is described by Google API discovery. +Otherwise return 0 -=head2 C + print $disco->service_exists('calendar'); # 1 + print $disco->service_exists('someapi'); # 0 -Return arrayref of all available API's (services) +Note that most Google APIs are fully lowercase, but some are camelCase. Please +check the documentation from Google for reference. - { - 'name' => 'youtube', - 'versions' => [ 'v3' ] - documentationLink => , - discoveryRestUrl => , - }, +=cut -Originally for printing list of supported API's in documentation .. - +sub service_exists { + my ($self, $api) = @_; + return unless $api; + return $self->available_APIs->{$api} +} -SEE ALSO: -may be better/more flexible to use client->list_of_available_google_api_ids -client->discover_all which is delegated to Client::Discovery->discover_all +=head2 C -=cut + Show available versions of particular API described by api id passed as parameter such as 'gmail' -sub available_APIs -{ - my ( $self ) = @_; - my $d_all = $self->discover_all(); ## - warn( 'no items in discovery data' ) unless defined $d_all->{ items }; - return [] unless defined $d_all->{ items }; - my $all = $d_all->{ items }; - - #print pp $all; - for my $i ( @$all ) - { - $i = { map { $_ => $i->{ $_ } } grep { exists $i->{ $_ } } qw/name version documentationLink discoveryRestUrl/ }; - } - my @subset = uniq map { $_->{ name } } @$all; ## unique names - # carp scalar @$all; - # carp scalar @subset; - # carp dump \@subset; - # my @a = map { $_->{name} } @$all; - - my @arr; - for my $s ( @subset ) - { - #print pp $s; - my @v = map { $_->{ version } } grep { $_->{ name } eq $s } @$all; - my @doclinks = uniq map { $_->{ documentationLink } } grep { $_->{ name } eq $s } @$all; - my @discovery_links = map { $_->{ discoveryRestUrl } } grep { $_->{ name } eq $s } @$all; - - push @arr, { name => $s, versions => \@v, doclinks => \@doclinks, discoveryRestUrl => \@discovery_links }; - } + $disco->available_versions('calendar'); # ['v3'] + $disco->available_versions('youtubeAnalytics'); # ['v1','v1beta1'] + + Returns arrayref - return \@arr; +=cut + +sub available_versions { + my ($self, $api) = @_; + return [] unless $api; + return $self->available_APIs->{$api}->{version} // [] } -=head2 C +=head2 C - Return 1 if Google Service API ID is described by Google API discovery. - Otherwise return 0 +return latest stable verion of API - print $d->service_exists('calendar'); # 1 - print $d->service_exists('someapi'); # 0 + $d->available_versions('calendar'); # ['v3'] + $d->latest_stable_version('calendar'); # 'v3' -NB - Is case sensitive - all lower is required so $d->service_exists('Calendar') returns 0 + $d->available_versions('tagmanager'); # ['v1','v2'] + $d->latest_stable_version('tagmanager'); # ['v2'] + + $d->available_versions('storage'); # ['v1','v1beta1', 'v1beta2'] + $d->latest_stable_version('storage'); # ['v1'] =cut -sub service_exists -{ - my ( $self, $api ) = @_; - return 0 unless $api; - my $apis_all = $self->available_APIs(); - return grep { $_->{ name } eq $api } @$apis_all; ## 1 iff an equality is found with keyed name +sub latest_stable_version { + my ($self, $api) = @_; + return '' unless $api; + my $versions = $self->available_versions($api); + return '' unless $versions; + return '' unless @{ $versions } > 0; + #remove alpha or beta versions + my @stable = grep { !/beta|alpha/ } @$versions; + return $stable[-1] || ''; } -=head2 C +=head2 C - No params. - Returns list of supported APIs as string in human-readible format ( name, versions and doclinks ) - + my $hashref = $disco->process_api_version('gmail') + # { api => 'gmail', version => 'v1' } + my $hashref = $disco->process_api_version({ api => 'gmail' }) + # { api => 'gmail', version => 'v1' } + my $hashref = $disco->process_api_version('gmail:v2') + # { api => 'gmail', version 'v2' } + +Takes a version string and breaks it into a hashref. If no version is +given, then default to the latest stable version in the discover document. =cut -sub supported_as_text -{ - my ( $self ) = @_; - my $ret = ''; - for my $api ( @{ $self->available_APIs() } ) - { - croak( 'doclinks key defined but is not the expected arrayref' ) unless ref $api->{ doclinks } eq 'ARRAY'; - croak( 'array of apis provided by available_APIs includes one without a defined name' ) unless defined $api->{ name }; +sub process_api_version { + my ($self, $params) = @_; + # scalar parameter not hashref - so assume is intended to be $params->{api} + $params = { api => $params } if ref $params eq ''; - my @clean_doclinks = grep { defined $_ } @{ $api->{ doclinks } }; ## was seeing undef in doclinks array - eg 'surveys'causing warnings in join + croak "'api' must be defined" unless $params->{api}; - ## unique doclinks using idiom from https://www.oreilly.com/library/view/perl-cookbook/1565922433/ch04s07.html - my %seen = (); - my $doclinks = join( ',', ( grep { !$seen{ $_ }++ } @clean_doclinks ) ) || ''; ## unique doclinks as string + ## trim any resource, method or version details in api id + if ($params->{api} =~ /([^:]+):(v[^\.]+)/ixsm) { + $params->{api} = $1; + $params->{version} = $2; + } + if ($params->{api} =~ /^(.*?)\./xsm) { + $params->{api} = $1; + } - $ret .= $api->{ name } . ' : ' . join( ',', @{ $api->{ versions } } ) . ' : ' . $doclinks . "\n"; + unless ($self->service_exists($params->{api})) { + croak "$params->{api} does not seem to be a valid Google API"; } - return $ret; + + $params->{version} //= $self->latest_stable_version($params->{api}); + return $params } -=head2 C - Show available versions of particular API described by api id passed as parameter such as 'gmail' +=head2 get_api_document - $d->available_versions('calendar'); # ['v3'] - $d->available_versions('youtubeAnalytics'); # ['v1','v1beta1'] +returns the cached version if avaiable in CHI otherwise retrieves discovery data via HTTP, stores in CHI cache and returns as +a Perl data structure. - Returns arrayref + my $hashref = $self->get_api_document( 'gmail' ); + my $hashref = $self->get_api_document( 'gmail:v3' ); + my $hashref = $self->get_api_document( 'gmail:v3.users.list' ); + my $hashref = $self->get_api_document( { api=> 'gmail', version => 'v3' } ); + +NB: if deeper structure than the api_id is provided then only the head is used +so get_api_document( 'gmail' ) is the same as get_api_document( 'gmail.some.child.method' ) +returns the api discovery specification structure ( cached by CHI ) for api id (eg 'gmail') +returns the discovery data as a hashref, an empty hashref on certain failing conditions or croaks on critical errors. + +Also available as get_api_discovery_for_api_id, which is being deprecated. =cut -sub available_versions -{ - my ( $self, $api ) = @_; - return [] unless $api; - my @api_target = grep { $_->{ name } eq $api } @{ $self->available_APIs() }; - return [] if scalar( @api_target ) == 0; - return $api_target[0]->{ versions }; +sub get_api_discovery_for_api_id { + carp <get_api_document(@_) } -=head2 C - -return latest stable verion of API +sub get_api_document { + my ($self, $arg) = @_; - $d->available_versions('calendar'); # ['v3'] - $d->latest_stable_version('calendar'); # 'v3' + my $params = $self->process_api_version($arg); + my $apis = $self->available_APIs(); - $d->available_versions('tagmanager'); # ['v1','v2'] - $d->latest_stable_version('tagmanager'); # ['v2'] + my $api = $apis->{$params->{api}}; + croak "No versions found for $params->{api}" unless $api->{version}; - $d->available_versions('storage'); # ['v1','v1beta1', 'v1beta2'] - $d->latest_stable_version('storage'); # ['v1'] + my @versions = @{$api->{version}}; + my @urls = @{$api->{discoveryRestUrl}}; + my ($url) = pairwise { $a eq $params->{version} ? $b : () } @versions, @urls; -=cut + croak "Couldn't find correct url for $params->{api} $params->{version}" + unless $url; -sub latest_stable_version -{ - my ( $self, $api ) = @_; - return '' unless $api; - return '' unless $self->available_versions( $api ); - return '' unless @{ $self->available_versions( $api ) } > 0; - my $versions = $self->available_versions( $api ); # arrayref - if ( $versions->[-1] =~ /beta/ ) - { - return $versions->[0]; - } - else - { - return $versions->[-1]; - } + $self->get_with_cache($url); } +#TODO- HERE - we are here in refactoring +sub _extract_resource_methods_from_api_spec { + my ($self, $tree, $api_spec, $ret) = @_; + $ret = {} unless defined $ret; + croak("ret not a hash - $tree, $api_spec, $ret") unless ref($ret) eq 'HASH'; -######################################################## -sub api_version_urls -{ - my ( $self ) = @_; - ## transform structure to be keyed on api->versionRestUrl - my $aapis = $self->available_APIs(); - my $api_verson_urls = {}; - for my $api ( @{ $aapis } ) - { - for ( my $i = 0; $i < scalar @{ $api->{ versions } }; $i++ ) - { - $api_verson_urls->{ $api->{ name } }{ $api->{ versions }[$i] } = $api->{ discoveryRestUrl }[$i]; + if (defined $api_spec->{methods} && ref($api_spec->{methods}) eq 'HASH') { + foreach my $method (keys %{ $api_spec->{methods} }) { + $ret->{"$tree.$method"} = $api_spec->{methods}{$method} + if ref($api_spec->{methods}{$method}) eq 'HASH'; } } - return $api_verson_urls; + if (defined $api_spec->{resources}) { + foreach my $resource (keys %{ $api_spec->{resources} }) { + ## NB - recursive traversal down tree of api_spec resources + $self->_extract_resource_methods_from_api_spec("$tree.$resource", + $api_spec->{resources}{$resource}, $ret); + } + } + return $ret; } -######################################################## -=head2 C +=head2 C - $agent->extract_method_discovery_detail_from_api_spec( $tree, $api_version ) + $disco->get_method_details($tree, $api_version) -returns a hashref representing the discovery specification for the method identified by $tree in dotted API format such as texttospeech.text.synthesize +returns a hashref representing the discovery specification for the +method identified by $tree in dotted API format such as +texttospeech.text.synthesize -returns an empty hashref if not found +Dies a horrible death if not found. +Also available as C, but the long name is being +deprecated in favor of the more compact one. =cut -######################################################## -sub extract_method_discovery_detail_from_api_spec -{ - my ( $self, $tree, $api_version ) = @_; +sub extract_method_discovery_detail_from_api_spec { + carp <get_method_details(@_) +} + +sub get_method_details { + my ($self, $tree, $api_version) = @_; ## where tree is the method in format from _extract_resource_methods_from_api_spec() like projects.models.versions.get ## the root is the api id - further '.' sep levels represent resources until the tailing label that represents the method - return {} unless defined $tree; + croak 'You must ask for a method!' unless defined $tree; my @nodes = split /\./smx, $tree; - croak( "tree structure '$tree' must contain at least 2 nodes including api id, [list of hierarchical resources ] and method - not " . scalar( @nodes ) ) - unless scalar( @nodes ) > 1; + croak( + "tree structure '$tree' must contain at least 2 nodes including api id, [list of hierarchical resources ] and method - not " + . scalar(@nodes)) + unless @nodes > 1; - my $api_id = shift( @nodes ); ## api was head - my $method = pop( @nodes ); ## method was tail + my $api_id = shift(@nodes); ## api was head + my $method = pop(@nodes); ## method was tail ## split out version if is defined as part of $tree ## trim any resource, method or version details in api id - if ( $api_id =~ /([^:]+):([^\.]+)$/ixsm ) ## we have already isolated head from api tree children - { - $api_id = $1; - $api_version = $2; + ## we have already isolated head from api tree children + if ($api_id =~ /([^:]+):([^\.]+)$/ixsm) { + $api_id = $1; + $api_version = $2; } ## handle incorrect api_id - if ( $self->service_exists( $api_id ) == 0 ) - { - carp( "unable to confirm that '$api_id' is a valid Google API service id" ); - return {}; + if ($self->service_exists($api_id) == 0) { + croak("unable to confirm that '$api_id' is a valid Google API service id"); } - $api_version = $self->latest_stable_version( $api_id ) unless $api_version; + $api_version = $self->latest_stable_version($api_id) unless $api_version; ## TODO: confirm that spec available for api version - my $api_spec = $self->get_api_discovery_for_api_id( { api => $api_id, version => $api_version } ); + my $api_spec = $self->get_api_document( + { api => $api_id, version => $api_version }); - - ## we use the schames to substitute into '$ref' keyed placeholders + ## we use the schemas to substitute into '$ref' keyed placeholders my $schemas = {}; - foreach my $schema_key (sort keys %{$api_spec->{schemas}}) - { - $schemas->{$schema_key} = $api_spec->{'schemas'}{$schema_key}; + foreach my $schema_key (sort keys %{ $api_spec->{schemas} }) { + $schemas->{$schema_key} = $api_spec->{'schemas'}{$schema_key}; } ## recursive walk through the structure in _fix_ref @@ -545,51 +471,37 @@ sub extract_method_discovery_detail_from_api_spec ## '$ref' values within the schema structures themselves ## including within the schema spec structures (NB assumes no cyclic structures ) ## otherwise would could recursive chaos - my $api_spec_fix = $self->_fix_ref( $api_spec, $schemas ); ## first level ( '$ref' in the method params and return values etc ) - $api_spec = $self->_fix_ref($api_spec_fix, $schemas ); ## second level ( '$ref' in the interpolated schemas from first level ) + my $api_spec_fix = $self->_fix_ref($api_spec, $schemas) + ; ## first level ( '$ref' in the method params and return values etc ) + $api_spec = $self->_fix_ref($api_spec_fix, $schemas) + ; ## second level ( '$ref' in the interpolated schemas from first level ) ## now extract all the methods (recursive ) - my $all_api_methods = $self->_extract_resource_methods_from_api_spec( "$api_id:$api_version", $api_spec ); - #print dump $all_api_methods;exit; - if ( defined $all_api_methods->{ $tree } ) - { - return $all_api_methods->{ $tree }; - } - else - { - #return $all_api_methods->{ "$api_id:$api_version" } if ( defined $all_api_methods->{ "$api_id:$api_version" } ); - return $all_api_methods->{ $tree } if ( $all_api_methods = $self->_extract_resource_methods_from_api_spec( "$api_id", $api_spec ) ); + my $all_api_methods + = $self->_extract_resource_methods_from_api_spec("$api_id:$api_version", + $api_spec); - carp( "Unable to find method detail for '$tree' within Google Discovery Spec for $api_id version $api_version" ) if $self->debug; - return {}; + unless (defined $all_api_methods->{$tree}) { + $all_api_methods + = $self->_extract_resource_methods_from_api_spec($api_id, $api_spec); } + if ($all_api_methods->{$tree}) { + + #add in the global parameters to the endpoint, + #stored in the top level of the api_spec + # TODO - why are we mutating the main hash? + $all_api_methods->{$tree}{parameters} = { + %{ $all_api_methods->{$tree}{parameters} }, + %{ $api_spec->{parameters} } + }; + return $all_api_methods->{$tree}; + } + + croak("Unable to find method detail for '$tree' within Google Discovery Spec for $api_id version $api_version") } ######################################################## ######################################################## -sub _extract_resource_methods_from_api_spec -{ - my ( $self, $tree, $api_spec, $ret ) = @_; - $ret = {} unless defined $ret; - croak( "ret not a hash - $tree, $api_spec, $ret" ) unless ref( $ret ) eq 'HASH'; - - if ( defined $api_spec->{ methods } && ref( $api_spec->{ methods } ) eq 'HASH' ) - { - foreach my $method ( keys %{ $api_spec->{ methods } } ) - { - $ret->{ "$tree.$method" } = $api_spec->{ methods }{ $method } if ref( $api_spec->{ methods }{ $method } ) eq 'HASH'; - } - } - if ( defined $api_spec->{ resources } ) - { - foreach my $resource ( keys %{ $api_spec->{ resources } } ) - { - ## NB - recursive traversal down tree of api_spec resources - $self->_extract_resource_methods_from_api_spec( "$tree.$resource", $api_spec->{ resources }{ $resource }, $ret ); - } - } - return $ret; -} ######################################################## #=head2 C @@ -597,52 +509,45 @@ sub _extract_resource_methods_from_api_spec #This sub walks through the structure and replaces any hashes keyed with '$ref' with #the value defined in $schemas->{ } # -#eg -# ->{'response'}{'$ref'}{'Buckets'} -# is replaced with +#eg +# ->{'response'}{'$ref'}{'Buckets'} +# is replaced with # ->{response}{ $schemas->{Buckets} } # # It assumes that the schemas have been extracted from the original discover for the API -# and is typically applued to the method ( api endpoint ) to provide a fully descriptive +# and is typically applied to the method ( api endpoint ) to provide a fully descriptive # structure without external references. # #=cut ######################################################## -sub _fix_ref -{ - my ( $self, $node, $schemas ) = @_; - my $ret = undef; - my $r = ref($node); - - - if ( $r eq 'ARRAY' ) { - $ret = []; - foreach my $el ( @$node ) - { - push @$ret, $self->_fix_ref( $el, $schemas ); - } +sub _fix_ref { + my ($self, $node, $schemas) = @_; + my $ret = undef; + my $r = ref($node); + + + if ($r eq 'ARRAY') { + $ret = []; + foreach my $el (@$node) { + push @$ret, $self->_fix_ref($el, $schemas); } - elsif ( $r eq 'HASH') - { - $ret = {}; - foreach my $key ( keys %$node ) - { - if ( $key eq '$ref' ) - { - #say $node->{'$ref'}; - $ret = $schemas->{ $node->{'$ref'} }; - } - else - { - $ret->{$key} = $self->_fix_ref( $node->{$key}, $schemas ); - } - } + } elsif ($r eq 'HASH') { + $ret = {}; + foreach my $key (keys %$node) { + if ($key eq '$ref') { + + #say $node->{'$ref'}; + $ret = $schemas->{ $node->{'$ref'} }; + } else { + $ret->{$key} = $self->_fix_ref($node->{$key}, $schemas); + } } - else - { $ret = $node; } - - return $ret; + } else { + $ret = $node; + } + + return $ret; } ######################################################## @@ -660,59 +565,63 @@ representing the corresponding discovery specification for that method ( API End =cut -#TODO: consider ? refactor to allow parameters either as a single api id such as 'gmail' +#TODO: consider ? refactor to allow parameters either as a single api id such as 'gmail' # as well as the currently accepted hash keyed on the api and version # -#SEE ALSO: +#SEE ALSO: # The following methods are delegated through to Client::Discovery - see perldoc WebService::Client::Discovery for detils # -# get_method_meta -# discover_all -# extract_method_discovery_detail_from_api_spec +# get_method_meta +# discover_all +# extract_method_discovery_detail_from_api_spec # get_api_discovery_for_api_id ######################################################## -## TODO: consider renaming ? -sub methods_available_for_google_api_id -{ - my ( $self, $api_id, $version ) = @_; +#TODO- give short name and deprecate +sub methods_available_for_google_api_id { + my ($self, $api_id, $version) = @_; - $version = $self->latest_stable_version( $api_id ) unless $version; + $version = $self->latest_stable_version($api_id) unless $version; ## TODO: confirm that spec available for api version - my $api_spec = $self->get_api_discovery_for_api_id( { api => $api_id, version => $version } ); - my $methods = $self->_extract_resource_methods_from_api_spec( $api_id, $api_spec ); + my $api_spec = $self->get_api_discovery_for_api_id( + { api => $api_id, version => $version }); + my $methods + = $self->_extract_resource_methods_from_api_spec($api_id, $api_spec); return $methods; } ######################################################## -=head2 C +=head2 C Returns an array list of all the available API's described in the API Discovery Resource that is either fetched or cached in CHI locally for 30 days. - my $r = $agent->list_of_available_google_api_ids(); + my $r = $agent->list_api_ids(); print "List of API Services ( comma separated): $r\n"; - my @list = $agent->list_of_available_google_api_ids(); + my @list = $agent->list_api_ids(); + +Formerly was list_of_available_google_api_ids, which will now give a deprecation warning +to switch to list_api_ids. =cut -######################################################## +sub list_of_available_google_api_ids { + carp <list_api_ids +} ## returns a list of all available API Services -sub list_of_available_google_api_ids -{ - my ( $self ) = @_; - my $aapis = $self->available_APIs(); ## array of hashes - my @api_list = map { $_->{ name } } @$aapis; - return wantarray ? @api_list : join( ',', @api_list ); ## allows to be called in either list or scalar context - #return @api_list; - +sub list_api_ids { + my ($self) = @_; + my @api_list = keys %{$self->available_APIs}; + return wantarray ? @api_list + : join(',', @api_list); } -######################################################## 1; - -## TODO - CODE REVIEW -## get_expires_at .. deos this do what is expected ? - what if has expired and so get fails - will this still return a value? \ No newline at end of file diff --git a/lib/WebService/GoogleAPI/Client/UserAgent.pm b/lib/WebService/GoogleAPI/Client/UserAgent.pm index f8fe3c0..e73be26 100644 --- a/lib/WebService/GoogleAPI/Client/UserAgent.pm +++ b/lib/WebService/GoogleAPI/Client/UserAgent.pm @@ -2,39 +2,57 @@ use strictures; package WebService::GoogleAPI::Client::UserAgent; +# VERSION # ABSTRACT: User Agent wrapper for working with Google APIs use Moo; extends 'Mojo::UserAgent'; #extends 'Mojo::UserAgent::Mockable'; -use WebService::GoogleAPI::Client::Credentials; -use WebService::GoogleAPI::Client::AuthStorage; +use WebService::GoogleAPI::Client::AuthStorage::GapiJSON; use Mojo::UserAgent; use Data::Dump qw/pp/; # for dev debug use Carp qw/croak carp cluck/; -has 'do_autorefresh' => ( is => 'rw', default => 1 ); # if 1 storage must be configured -has 'auto_update_tokens_in_storage' => ( is => 'rw', default => 1 ); +has 'do_autorefresh' => ( is => 'rw', default => 1 ); has 'debug' => ( is => 'rw', default => 0 ); -has 'credentials' => - ( is => 'rw', default => sub { WebService::GoogleAPI::Client::Credentials->instance }, handles => [qw/access_token auth_storage get_scopes_as_array user /], lazy => 1 ); +has 'auth_storage' => ( + is => 'rw', + default => sub { + WebService::GoogleAPI::Client::AuthStorage::GapiJSON->new + }, + handles => [qw/get_access_token scopes user/], + trigger => 1, + isa => sub { + my $role = 'WebService::GoogleAPI::Client::AuthStorage'; + die "auth_storage must implement the $role role to work!" unless $_[0]->does($role) + }, + lazy => 1 +); + +sub _trigger_auth_storage { + my ($self) = @_; + # give the auth_storage a ua + # TODO - this seems like code smell to me. Should these storage things be + # roles that get applied to this ua? + $self->auth_storage->ua($self) +} -## NB - could cache using https://metacpan.org/pod/Mojo::UserAgent::Cached TODO: Review source of this for ideas +## NB - could cache using https://metacpan.org/pod/Mojo::UserAgent::Cached +# TODO: Review source of this for ideas ## NB - used by both Client and Discovery # Keep access_token in headers always actual -sub BUILD -{ - my ( $self ) = @_; - ## performance tip as per https://developers.google.com/calendar/performance and similar links - ## NB - to work with Google APIs also assumes that Accept-Encoding: gzip is set in HTTP headers - $self->transactor->name( __PACKAGE__ . ' (gzip enabled)' ); - ## MAX SIZE ETC _ WHAT OTHER CONFIGURABLE PARAMS ARE AVAILABLE +## performance tip as per https://developers.google.com/calendar/performance and similar links +## NB - to work with Google APIs also assumes that Accept-Encoding: gzip is set in HTTP headers +sub BUILD { + my ($self) = @_; + $self->transactor->name(__PACKAGE__ . ' (gzip enabled)'); + ## MAX SIZE ETC _ WHAT OTHER CONFIGURABLE PARAMS ARE AVAILABLE } @@ -44,24 +62,19 @@ sub BUILD =cut -## TODO: this should probably nbe handled ->on('start' => sub {}) as per https://metacpan.org/pod/Mojolicious::Guides::Cookbook#Decorating-follow-up-requests - -sub header_with_bearer_auth_token -{ - my ( $self, $headers ) = @_; +sub header_with_bearer_auth_token { + my ($self, $headers) = @_; $headers = {} unless defined $headers; - $headers->{ 'Accept-Encoding' } = 'gzip'; + $headers->{'Accept-Encoding'} = 'gzip'; - # cluck "header_with_bearer_auth_token: ".$self->access_token; - if ( $self->access_token ) - { - $headers->{ 'Authorization' } = 'Bearer ' . $self->access_token; - } - else - { - cluck 'No access_token, can\'t build Auth header'; + if (my $token = $self->get_access_token) { + $headers->{Authorization} = "Bearer $token"; + } else { + # TODO - why is this not fatal? + carp +"Can't build Auth header, couldn't get an access token. Is your AuthStorage set up correctly?"; } return $headers; } @@ -78,51 +91,55 @@ sub header_with_bearer_auth_token =cut -sub build_http_transaction -{ - my ( $self, $params ) = @_; +sub build_http_transaction { + my ($self, $params) = @_; ## hack to allow method option as alias for httpMethod - $params->{ httpMethod } = $params->{ method } if defined $params->{ method }; - $params->{ httpMethod } = '' unless defined $params->{ httpMethod }; + $params->{httpMethod} = $params->{method} if defined $params->{method}; + $params->{httpMethod} = '' unless defined $params->{httpMethod}; - my $http_method = uc( $params->{ httpMethod } ) || 'GET'; # uppercase ? - my $optional_data = $params->{ options } || ''; - my $path = $params->{ path } || cluck( 'path parameter required for build_http_transaction' ); - my $no_auth = $params->{ no_auth } || 0; ## default to including auth header - ie not setting no_auth - my $headers = $params->{ headers} || {}; + my $http_method = uc($params->{httpMethod}) || 'GET'; # uppercase ? + my $optional_data = $params->{options} || ''; + my $path = $params->{path} + || cluck('path parameter required for build_http_transaction'); + my $no_auth = $params->{no_auth} + || 0; ## default to including auth header - ie not setting no_auth + my $headers = $params->{headers} || {}; - cluck 'Attention! You are using POST, but no payload specified' if ( ( $http_method eq 'POST' ) && !defined $optional_data ); + cluck 'Attention! You are using POST, but no payload specified' + if (($http_method eq 'POST') && !defined $optional_data); cluck "build_http_transaction:: $http_method $path " if ($self->debug > 11); - cluck "$http_method Not a SUPPORTED HTTP method parameter specified to build_http_transaction" . pp $params unless $http_method =~ /^GET|PATH|PUT|POST|PATCH|DELETE$/ixm; - - ## NB - headers not passed if no_auth - $headers = $self->header_with_bearer_auth_token( $headers ) unless $no_auth; - if ( $http_method =~ /^POST|PATH|PUT|PATCH$/ixg ) - { + cluck +"$http_method Not a SUPPORTED HTTP method parameter specified to build_http_transaction" + . pp $params + unless $http_method =~ /^GET|PATH|PUT|POST|PATCH|DELETE$/ixm; + + ## NB - headers not passed if no_auth + $headers = $self->header_with_bearer_auth_token($headers) unless $no_auth; + if ($http_method =~ /^POST|PATH|PUT|PATCH$/ixg) { ## ternary conditional on whether optional_data is set ## return $optional_data eq '' ? $self->build_tx( $http_method => $path => $headers ) : $self->build_tx( $http_method => $path => $headers => json => $optional_data ); - if ( $optional_data eq '' ) - { - return $self->build_tx( $http_method => $path => $headers ); - } - else - { - if ( ref($optional_data) eq 'HASH' ) - { - return $self->build_tx( $http_method => $path => $headers => json => $optional_data ); - } - elsif ( ref($optional_data) eq '') ## am assuming is a post with options containing a binary payload + if ($optional_data eq '') { + return $self->build_tx($http_method => $path => $headers); + } else { + if (ref($optional_data) eq 'HASH') { + return $self->build_tx( + $http_method => $path => $headers => json => $optional_data); + } elsif ( + ref($optional_data) eq + '') ## am assuming is a post with options containing a binary payload { - return $self->build_tx( $http_method => $path => $headers => $optional_data ); + return $self->build_tx( + $http_method => $path => $headers => $optional_data); } - + } - } - else ## DELETE or GET - { - return $self->build_tx( $http_method => $path => $headers => form => $optional_data ) if ( $http_method eq 'GET' ); - return $self->build_tx( $http_method => $path => $headers ) if ( $http_method eq 'DELETE' ); + } else { ## DELETE or GET + return $self->build_tx( + $http_method => $path => $headers => form => $optional_data) + if ($http_method eq 'GET'); + return $self->build_tx($http_method => $path => $headers) + if ($http_method eq 'DELETE'); } #return undef; ## assert: should never get here @@ -142,7 +159,7 @@ NB - handles auth headers injection and token refresh if required and possible Required params: method, route -$self->access_token must be valid +$self->get_access_token must return a valid token Examples of usage: @@ -164,102 +181,50 @@ Returns L object =cut -sub validated_api_query -{ - my ( $self, $params ) = @_; - ## NB validated means that assumes checking against discovery specs has already been done. - - if ( ref( $params ) eq '' ) ## assume is a GET for the URI at $params +# NOTE validated means that we assume checking against discovery specs has already been done. +sub validated_api_query { + my ($self, $params) = @_; + + ## assume is a GET for the URI at $params + if (ref($params) eq '') { - cluck( "transcribing $params to a hashref for validated_api_query" ) if $self->debug; + cluck("transcribing $params to a hashref for validated_api_query") + if $self->debug; my $val = $params; $params = { path => $val, method => 'get', options => {}, }; } - my $tx = $self->build_http_transaction( $params ); - - cluck("$params->{method} $params->{path}") if $self->debug; - my $res = $self->start( $tx )->res; - - ## TODO: HANDLE TIMEOUTS AND OTHER ERRORS IF THEY WEREN'T HANDLED BY build_http_transaction - - ## TODO: -# return Mojo::Message::Response->new unless ref( $res ) eq 'Mojo::Message::Response'; + my $tx = $self->build_http_transaction($params); - if ( ( $res->code == 401 ) && $self->do_autorefresh ) - { - if ( $res->code == 401 ) ## redundant - was there something else in mind ? - { - croak "No user specified, so cant find refresh token and update access_token" unless $self->user; - cluck "401 response - access_token was expired. Attemptimg to update it automatically ..." if ($self->debug > 11); + cluck("$params->{method} $params->{path}") if $self->debug; - # cluck "Seems like access_token was expired. Attemptimg update it automatically ..." if $self->debug; + #TODO- figure out how we can alter this to use promises + # at this point, i think we'd have to make a different method entirely to + # do this promise-wise + my $res = $self->start($tx)->res; + $res->{_token} = $self->get_access_token; - my $cred = $self->auth_storage->get_credentials_for_refresh( $self->user ); # get client_id, client_secret and refresh_token - my $new_token = $self->refresh_access_token( $cred )->{ access_token }; # here also {id_token} etc - cluck "validated_api_query() Got a new token: " . $new_token if ($self->debug > 11); - $self->access_token( $new_token ); + if (($res->code == 401) && $self->do_autorefresh) { + cluck "Your access token was expired. Attemptimg to update it automatically..." + if ($self->debug > 11); - if ( $self->auto_update_tokens_in_storage ) - { - $self->auth_storage->set_access_token_to_storage( $self->user, $self->access_token ); - } + $self->auth_storage->refresh_access_token($self); - #$tx = $self->build_http_transaction( $params ); - - $res = $self->start( $self->build_http_transaction( $params ) )->res; # Mojo::Message::Response - } - } - elsif ( $res->code == 403 ) - { - cluck( 'Unexpected permission denied 403 error ' ); + return $self->validated_api_query($params); + } elsif ($res->code == 403) { + cluck('Unexpected permission denied 403 error'); return $res; + } elsif ($res->code == 429) { + cluck('HTTP 429 - you hit a rate limit. Try again later'); + return $res } return $res if $res->code == 200; - return $res if $res->code == 204; ## NO CONTENT - INDICATES OK FOR DELETE ETC - return $res if $res->code == 400; ## general failure - cluck( "unhandled validated_api_query response code " . $res->code ); + return $res if $res->code == 204; ## NO CONTENT - INDICATES OK FOR DELETE ETC + return $res if $res->code == 400; ## general failure + cluck("unhandled validated_api_query response code " . $res->code); return $res; } -=head2 C - -Get new access token for user from Google API server - - $self->refresh_access_token({ - client_id => '', - client_secret => '', - refresh_token => '' - }) - - Q: under what conditions could we not have a refresh token? - what scopes are required? ensure that included in defaults if they are req'd - -=cut - -sub refresh_access_token -{ - my ( $self, $credentials ) = @_; - - if ( - ( !defined $credentials->{ client_id } ) ## could this be caught somewhere earlier than here? - || ( !defined $credentials->{ client_secret } ) ## unless credentials include an access token only ? - || ( !defined $credentials->{ refresh_token } ) - ) - { - croak 'If you credentials are missing the refresh_token - consider removing the auth at ' - . 'https://myaccount.google.com/permissions as The oauth2 server will only ever mint one refresh ' - . 'token at a time, and if you request another access token via the flow it will operate as if ' - . 'you only asked for an access token.' - if !defined $credentials->{ refresh_token }; - - croak "Not enough credentials to refresh access_token. Check that you provided client_id, client_secret and refresh_token"; - } - - cluck "refresh_access_token:: Attempt to refresh access_token " if ($self->debug > 11); - $credentials->{ grant_type } = 'refresh_token'; - return $self->post( 'https://www.googleapis.com/oauth2/v4/token' => form => $credentials )->res->json || croak( 'refresh_access_token failed' ); # tokens -} - 1; diff --git a/t/00-load.t b/t/00-load.t deleted file mode 100755 index 97be0ba..0000000 --- a/t/00-load.t +++ /dev/null @@ -1,57 +0,0 @@ -#!perl -T - -=head2 USAGE - -To run manually in the local directory assuming gapi.json present in source root and in xt/author/calendar directory - C - -NB: is also run as part of dzil test - -=cut - -use 5.006; -use strict; -use warnings; -use Test::More; - -use Cwd; -my $dir = getcwd; - -# plan tests => 1; ## or at end done_test(); -my $DEBUG = 0; - -#BEGIN { - -use_ok( 'WebService::GoogleAPI::Client' ) || print "Bail out!\n"; - -my $default_file = $ENV{ 'GOOGLE_TOKENSFILE' } || "$dir/../../gapi.json"; ## assumes running in a sub of the build dir by dzil -my $user = $ENV{ 'GMAIL_FOR_TESTING' } || ''; ## will be populated by first available if set to '' and default_file exists - - -subtest 'Test with User Configuration' => sub { - plan( skip_all => 'No user configuration - set $ENV{GOOGLE_TOKENSFILE} or create gapi.json in dzil source root directory' ) unless -e $default_file; - - ok( 1 == 1, 'Configured WebService::GoogleAPI::Client User' ); - my $gapi = WebService::GoogleAPI::Client->new( debug => $DEBUG ); - - $gapi->auth_storage->setup( { type => 'jsonfile', path => $default_file } ) || croak( $! ); - my $aref_token_emails = $gapi->auth_storage->storage->get_token_emails_from_storage; - $user = $aref_token_emails->[0] unless $user; ## default to the first user if none defined yet - - #note("ENV CONFIG SETS $ENV{'GMAIL_FOR_TESTING'} WITHIN $ENV{'GOOGLE_TOKENSFILE'} "); - - if ( -e $default_file && $user ) - { - note( "Running tests with user '$user' using '$default_file' credentials" ); - $gapi->auth_storage->setup( { type => 'jsonfile', path => $default_file } ); - $gapi->user( $user ); - - #p($gapi); - - } -}; ## END 'Test with User Configuration' SUBTEST - - -#note("Testing WebService::GoogleAPI::Client $WebService::GoogleAPI::Client::VERSION, Perl $], $^X"); - -done_testing(); diff --git a/t/03-pre-warmed-cache-discovery.t b/t/03-pre-warmed-cache-discovery.t deleted file mode 100644 index 1d09315..0000000 --- a/t/03-pre-warmed-cache-discovery.t +++ /dev/null @@ -1,7130 +0,0 @@ -#!perl -T - -=head2 USAGE - -To run manually in the local directory assuming gapi.json present in source root and in xt/author/calendar directory - C - -NB: is also run as part of dzil test - -=cut - -use 5.006; -use strict; -use warnings; -use Test::More; -use Data::Dumper; ## remove this when finish tweaking -use Cwd; -use CHI; -use WebService::GoogleAPI::Client; -use Sub::Override; -#use WebService::GoogleAPI::Client::Discovery; -use JSON; -#use lib './lib'; ## provides pre-populated values -#use CHI::Driver::TEST_MOCKED; - -my $dir = getcwd; -my $DEBUG = 1; ## to see noise of class debugging -my $warm_hash = {}; -#$warm_hash->{'https://www.googleapis.com/discovery/v1/apis'} = 'foo'; -#print Dumper $hash; - - -my $chi = CHI->new(driver => 'RawMemory', datastore => $warm_hash ); - -#$chi->set('https://www.googleapis.com/discovery/v1/apis' => from_json( pre_get_all_apis_json()) ); -#$chi->set('https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest' => from_json(pre_get_gmail_spec_json()) ); -use_ok( 'WebService::GoogleAPI::Client::Discovery' ); - -#my $disc = WebService::GoogleAPI::Client::Discovery->new( ); - -ok( my $disc = WebService::GoogleAPI::Client::Discovery->new( chi=>$chi, debug=>$DEBUG ) ,'Create a new discovery instance to use mocked agent responses'); - - ## INJECT HTTP RESPONSE FOR API DISCOVERY REQUEST - my $override = Sub::Override->new('Mojo::Transaction::res', sub { - my $res = Mojo::Message::Response->new ; - $res->code( 200 ); - $res->body( pre_get_all_apis_json() ); - return $res; - }); - - ok( my $all = $disc->discover_all(), 'discover_all()' ); - - ## INJECT HTTP RESPONSE FOR GAMIL V1 API SPECIFICATION - my $override2 = Sub::Override->new('Mojo::Transaction::res', - sub { - my $res2 = Mojo::Message::Response->new ; - $res2->code( 200 ); - $res2->body( pre_get_gmail_spec_json() ); - return $res2; - }); - - - ok( my $gmail_api_spec = $disc->methods_available_for_google_api_id('gmail', 'v1'), 'Get available methods for Gmail V1'); - - - - my $override3 = Sub::Override->new('Mojo::Transaction::res', - sub { - my $res2 = Mojo::Message::Response->new ; - $res2->code( 200 ); - $res2->body( "TESTED FINE" ); - return $res2; - }); - - - #my $gapi_client = WebService::GoogleAPI::Client->new( debug => 0, gapi_json => 'gapi.json', chi => $chi ); - #ok( my $cl = $gapi_client->api_query( api_endpoint_id => 'gmail.users.messages.list' ), 'api_query - "gmail.users.messages.list"'); - - - - - -ok ( $disc->augment_discover_all_with_unlisted_experimental_api( - { - 'version' => 'v4', - 'preferred' => 1, - 'title' => 'Google My Business API', - 'description' => 'The Google My Business API - provides an interface for managing business location information on - Google.', - 'id' => 'mybusiness:v4', - 'kind' => 'discovery#directoryItem', - 'documentationLink' => - "https://developers.google.com/my-business/", - 'icons' => { - "x16"=> - "http://www.google.com/images/icons/product/search-16.gif", - "x32"=> - "http://www.google.com/images/icons/product/search-32.gif" - }, - 'discoveryRestUrl' => - 'https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p2.json', - 'name' => 'mybusiness' - } ), 'Augment discovery all with experimental specification' ); - - - - -ok ( $disc->available_APIs(), 'Get available APIs'); -ok ( $disc->supported_as_text(), 'Supported as text'); -ok ( $disc->available_versions('gmail'), 'Available versions for Gmail'); -ok ( $disc->latest_stable_version('gmail'), 'Latest stable version for Gmail'); -ok( $disc->api_version_urls(), 'api version urls'); -ok( $disc->methods_available_for_google_api_id('gmail'), 'Get end points available for gmail'); -ok( $disc->list_of_available_google_api_ids(), 'All available Google API IDs'); - -note( ' CHI TYPE + ' . ref( $disc->chi() ) ); -#note( my$y = $x->get('https://www.googleapis.com/discovery/v1/apis')); -#print Dumper $x; - -#use_ok( 'WebService::GoogleAPI::Client' ); # || print "Bail out!\n"; - - -#ok( ref( WebService::GoogleAPI::Client::Discovery->new->( chi => $chi )->discover_all() ) eq 'HASH', 'WebService::GoogleAPI::Client::Discovery->new->discover_all() return HASREF' ); - - - -done_testing(); - - -sub pre_get_all_apis_json -{ - return <<'_END' -{ - "kind": "discovery#directoryList", - "discoveryVersion": "v1", - "items": [ - { - "kind": "discovery#directoryItem", - "id": "abusiveexperiencereport:v1", - "name": "abusiveexperiencereport", - "version": "v1", - "title": "Abusive Experience Report API", - "description": "Views Abusive Experience Report data, and gets a list of sites that have a significant number of abusive experiences.", - "discoveryRestUrl": "https://abusiveexperiencereport.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/abusive-experience-report/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "acceleratedmobilepageurl:v1", - "name": "acceleratedmobilepageurl", - "version": "v1", - "title": "Accelerated Mobile Pages (AMP) URL API", - "description": "This API contains a single method, batchGet. Call this method to retrieve the AMP URL (and equivalent AMP Cache URL) for given public URL(s).", - "discoveryRestUrl": "https://acceleratedmobilepageurl.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/amp/cache/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "accesscontextmanager:v1beta", - "name": "accesscontextmanager", - "version": "v1beta", - "title": "Access Context Manager API", - "description": "An API for setting attribute based access control to requests to GCP services.", - "discoveryRestUrl": "https://accesscontextmanager.googleapis.com/$discovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/access-context-manager/docs/reference/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.2", - "name": "adexchangebuyer", - "version": "v1.2", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.2/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.3", - "name": "adexchangebuyer", - "version": "v1.3", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.3/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.4", - "name": "adexchangebuyer", - "version": "v1.4", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.4/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer2:v2beta1", - "name": "adexchangebuyer2", - "version": "v2beta1", - "title": "Ad Exchange Buyer API II", - "description": "Accesses the latest features for managing Ad Exchange accounts, Real-Time Bidding configurations and auction metrics, and Marketplace programmatic deals.", - "discoveryRestUrl": "https://adexchangebuyer.googleapis.com/$discovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest/reference/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexperiencereport:v1", - "name": "adexperiencereport", - "version": "v1", - "title": "Ad Experience Report API", - "description": "Views Ad Experience Report data, and gets a list of sites that have a significant number of annoying ads.", - "discoveryRestUrl": "https://adexperiencereport.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/ad-experience-report/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "admin:datatransfer_v1", - "name": "admin", - "version": "datatransfer_v1", - "title": "Admin Data Transfer API", - "description": "Transfers user data from one user to another.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/datatransfer_v1/rest", - "discoveryLink": "./apis/admin/datatransfer_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/data-transfer/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "admin:directory_v1", - "name": "admin", - "version": "directory_v1", - "title": "Admin Directory API", - "description": "Manages enterprise resources such as users and groups, administrative notifications, security features, and more.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/directory_v1/rest", - "discoveryLink": "./apis/admin/directory_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/directory/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "admin:reports_v1", - "name": "admin", - "version": "reports_v1", - "title": "Admin Reports API", - "description": "Fetches reports for the administrators of G Suite customers about the usage, collaboration, security, and risk for their users.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/reports_v1/rest", - "discoveryLink": "./apis/admin/reports_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/reports/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adsense:v1.4", - "name": "adsense", - "version": "v1.4", - "title": "AdSense Management API", - "description": "Accesses AdSense publishers' inventory and generates performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsense/v1.4/rest", - "discoveryLink": "./apis/adsense/v1.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/adsense-16.png", - "x32": "https://www.google.com/images/icons/product/adsense-32.png" - }, - "documentationLink": "https://developers.google.com/adsense/management/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adsensehost:v4.1", - "name": "adsensehost", - "version": "v4.1", - "title": "AdSense Host API", - "description": "Generates performance reports, generates ad codes, and provides publisher management capabilities for AdSense Hosts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsensehost/v4.1/rest", - "discoveryLink": "./apis/adsensehost/v4.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/adsense-16.png", - "x32": "https://www.google.com/images/icons/product/adsense-32.png" - }, - "documentationLink": "https://developers.google.com/adsense/host/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "alertcenter:v1beta1", - "name": "alertcenter", - "version": "v1beta1", - "title": "G Suite Alert Center API", - "description": "G Suite Alert Center API to view and manage alerts on issues affecting your domain.", - "discoveryRestUrl": "https://alertcenter.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/alertcenter/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "analytics:v2.4", - "name": "analytics", - "version": "v2.4", - "title": "Google Analytics API", - "description": "Views and manages your Google Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v2.4/rest", - "discoveryLink": "./apis/analytics/v2.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/analytics-16.png", - "x32": "https://www.google.com/images/icons/product/analytics-32.png" - }, - "documentationLink": "https://developers.google.com/analytics/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "analytics:v3", - "name": "analytics", - "version": "v3", - "title": "Google Analytics API", - "description": "Views and manages your Google Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v3/rest", - "discoveryLink": "./apis/analytics/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/analytics-16.png", - "x32": "https://www.google.com/images/icons/product/analytics-32.png" - }, - "documentationLink": "https://developers.google.com/analytics/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "analyticsreporting:v4", - "name": "analyticsreporting", - "version": "v4", - "title": "Google Analytics Reporting API", - "description": "Accesses Analytics report data.", - "discoveryRestUrl": "https://analyticsreporting.googleapis.com/$discovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/analytics/devguides/reporting/core/v4/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androiddeviceprovisioning:v1", - "name": "androiddeviceprovisioning", - "version": "v1", - "title": "Android Device Provisioning Partner API", - "description": "Automates Android zero-touch enrollment for device resellers, customers, and EMMs.", - "discoveryRestUrl": "https://androiddeviceprovisioning.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/zero-touch/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidenterprise:v1", - "name": "androidenterprise", - "version": "v1", - "title": "Google Play EMM API", - "description": "Manages the deployment of apps to Android for Work users.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidenterprise/v1/rest", - "discoveryLink": "./apis/androidenterprise/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android/work/play/emm-api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidmanagement:v1", - "name": "androidmanagement", - "version": "v1", - "title": "Android Management API", - "description": "The Android Management API provides remote enterprise management of Android devices and apps.", - "discoveryRestUrl": "https://androidmanagement.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/android/management", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v1", - "name": "androidpublisher", - "version": "v1", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1/rest", - "discoveryLink": "./apis/androidpublisher/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v1.1", - "name": "androidpublisher", - "version": "v1.1", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1.1/rest", - "discoveryLink": "./apis/androidpublisher/v1.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v2", - "name": "androidpublisher", - "version": "v2", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v2/rest", - "discoveryLink": "./apis/androidpublisher/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v3", - "name": "androidpublisher", - "version": "v3", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v3/rest", - "discoveryLink": "./apis/androidpublisher/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1alpha", - "name": "appengine", - "version": "v1alpha", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta", - "name": "appengine", - "version": "v1beta", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1", - "name": "appengine", - "version": "v1", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta4", - "name": "appengine", - "version": "v1beta4", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta5", - "name": "appengine", - "version": "v1beta5", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta5", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appsactivity:v1", - "name": "appsactivity", - "version": "v1", - "title": "Drive Activity API", - "description": "Provides a historical view of activity.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appsactivity/v1/rest", - "discoveryLink": "./apis/appsactivity/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/activity/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appstate:v1", - "name": "appstate", - "version": "v1", - "title": "Google App State API", - "description": "The Google App State API.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appstate/v1/rest", - "discoveryLink": "./apis/appstate/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services/web/api/states", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "bigquery:v2", - "name": "bigquery", - "version": "v2", - "title": "BigQuery API", - "description": "A data platform for customers to create, manage, share and query data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest", - "discoveryLink": "./apis/bigquery/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/search-16.gif", - "x32": "https://www.google.com/images/icons/product/search-32.gif" - }, - "documentationLink": "https://cloud.google.com/bigquery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "bigquerydatatransfer:v1", - "name": "bigquerydatatransfer", - "version": "v1", - "title": "BigQuery Data Transfer API", - "description": "Transfers data from partner SaaS applications to Google BigQuery on a scheduled, managed basis.", - "discoveryRestUrl": "https://bigquerydatatransfer.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/bigquery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "binaryauthorization:v1beta1", - "name": "binaryauthorization", - "version": "v1beta1", - "title": "Binary Authorization API", - "description": "The management interface for Binary Authorization, a system providing policy control for images deployed to Kubernetes Engine clusters.", - "discoveryRestUrl": "https://binaryauthorization.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/binary-authorization/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "blogger:v2", - "name": "blogger", - "version": "v2", - "title": "Blogger API", - "description": "API for access to the data within Blogger.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v2/rest", - "discoveryLink": "./apis/blogger/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/blogger-16.png", - "x32": "https://www.google.com/images/icons/product/blogger-32.png" - }, - "documentationLink": "https://developers.google.com/blogger/docs/2.0/json/getting_started", - "labels": [ - "limited_availability" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "blogger:v3", - "name": "blogger", - "version": "v3", - "title": "Blogger API", - "description": "API for access to the data within Blogger.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest", - "discoveryLink": "./apis/blogger/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/blogger-16.png", - "x32": "https://www.google.com/images/icons/product/blogger-32.png" - }, - "documentationLink": "https://developers.google.com/blogger/docs/3.0/getting_started", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "books:v1", - "name": "books", - "version": "v1", - "title": "Books API", - "description": "Searches for books and manages your Google Books library.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/books/v1/rest", - "discoveryLink": "./apis/books/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/ebooks-16.png", - "x32": "https://www.google.com/images/icons/product/ebooks-32.png" - }, - "documentationLink": "https://developers.google.com/books/docs/v1/getting_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "calendar:v3", - "name": "calendar", - "version": "v3", - "title": "Calendar API", - "description": "Manipulates events and other calendar data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest", - "discoveryLink": "./apis/calendar/v3/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/calendar-16.png", - "x32": "http://www.google.com/images/icons/product/calendar-32.png" - }, - "documentationLink": "https://developers.google.com/google-apps/calendar/firstapp", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "chat:v1", - "name": "chat", - "version": "v1", - "title": "Hangouts Chat API", - "description": "Create bots and extend the new Hangouts Chat.", - "discoveryRestUrl": "https://chat.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/hangouts/chat", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "civicinfo:v2", - "name": "civicinfo", - "version": "v2", - "title": "Google Civic Information API", - "description": "Provides polling places, early vote locations, contest data, election officials, and government representatives for U.S. residential addresses.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/civicinfo/v2/rest", - "discoveryLink": "./apis/civicinfo/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/civic-information", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "classroom:v1", - "name": "classroom", - "version": "v1", - "title": "Google Classroom API", - "description": "Manages classes, rosters, and invitations in Google Classroom.", - "discoveryRestUrl": "https://classroom.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/classroom", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudasset:v1beta1", - "name": "cloudasset", - "version": "v1beta1", - "title": "Cloud Asset API", - "description": "The cloud asset API manages the history and inventory of cloud resources.", - "discoveryRestUrl": "https://cloudasset.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://console.cloud.google.com/apis/api/cloudasset.googleapis.com/overview", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbilling:v1", - "name": "cloudbilling", - "version": "v1", - "title": "Cloud Billing API", - "description": "Allows developers to manage billing for their Google Cloud Platform projects programmatically.", - "discoveryRestUrl": "https://cloudbilling.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/billing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbuild:v1alpha1", - "name": "cloudbuild", - "version": "v1alpha1", - "title": "Cloud Build API", - "description": "Creates and manages builds on Google Cloud Platform.", - "discoveryRestUrl": "https://cloudbuild.googleapis.com/$discovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/cloud-build/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbuild:v1", - "name": "cloudbuild", - "version": "v1", - "title": "Cloud Build API", - "description": "Creates and manages builds on Google Cloud Platform.", - "discoveryRestUrl": "https://cloudbuild.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/cloud-build/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "clouddebugger:v2", - "name": "clouddebugger", - "version": "v2", - "title": "Stackdriver Debugger API", - "description": "Examines the call stack and variables of a running application without stopping or slowing it down.", - "discoveryRestUrl": "https://clouddebugger.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/debugger", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "clouderrorreporting:v1beta1", - "name": "clouderrorreporting", - "version": "v1beta1", - "title": "Stackdriver Error Reporting API", - "description": "Groups and counts similar errors from cloud services and applications, reports new errors, and provides access to error groups and their associated errors.", - "discoveryRestUrl": "https://clouderrorreporting.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/error-reporting/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudfunctions:v1", - "name": "cloudfunctions", - "version": "v1", - "title": "Cloud Functions API", - "description": "Manages lightweight user-provided functions executed in response to events.", - "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/functions", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudfunctions:v1beta2", - "name": "cloudfunctions", - "version": "v1beta2", - "title": "Cloud Functions API", - "description": "Manages lightweight user-provided functions executed in response to events.", - "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/functions", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudiot:v1", - "name": "cloudiot", - "version": "v1", - "title": "Cloud IoT API", - "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", - "discoveryRestUrl": "https://cloudiot.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iot", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudiot:v1beta1", - "name": "cloudiot", - "version": "v1beta1", - "title": "Cloud IoT API", - "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", - "discoveryRestUrl": "https://cloudiot.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iot", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudkms:v1", - "name": "cloudkms", - "version": "v1", - "title": "Cloud Key Management Service (KMS) API", - "description": "Manages keys and performs cryptographic operations in a central cloud service, for direct use by other cloud resources and applications.", - "discoveryRestUrl": "https://cloudkms.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kms/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudprofiler:v2", - "name": "cloudprofiler", - "version": "v2", - "title": "Stackdriver Profiler API", - "description": "Manages continuous profiling information.", - "discoveryRestUrl": "https://cloudprofiler.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/profiler/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v1", - "name": "cloudresourcemanager", - "version": "v1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v1beta1", - "name": "cloudresourcemanager", - "version": "v1beta1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v2", - "name": "cloudresourcemanager", - "version": "v2", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v2beta1", - "name": "cloudresourcemanager", - "version": "v2beta1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudshell:v1alpha1", - "name": "cloudshell", - "version": "v1alpha1", - "title": "Cloud Shell API", - "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", - "discoveryRestUrl": "https://cloudshell.googleapis.com/$discovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/shell/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudshell:v1", - "name": "cloudshell", - "version": "v1", - "title": "Cloud Shell API", - "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", - "discoveryRestUrl": "https://cloudshell.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/shell/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtasks:v2beta2", - "name": "cloudtasks", - "version": "v2beta2", - "title": "Cloud Tasks API", - "description": "Manages the execution of large numbers of distributed requests.", - "discoveryRestUrl": "https://cloudtasks.googleapis.com/$discovery/rest?version=v2beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tasks/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtasks:v2beta3", - "name": "cloudtasks", - "version": "v2beta3", - "title": "Cloud Tasks API", - "description": "Manages the execution of large numbers of distributed requests.", - "discoveryRestUrl": "https://cloudtasks.googleapis.com/$discovery/rest?version=v2beta3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tasks/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v2alpha1", - "name": "cloudtrace", - "version": "v2alpha1", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$discovery/rest?version=v2alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v1", - "name": "cloudtrace", - "version": "v1", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v2", - "name": "cloudtrace", - "version": "v2", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "composer:v1", - "name": "composer", - "version": "v1", - "title": "Cloud Composer API", - "description": "Manages Apache Airflow environments on Google Cloud Platform.", - "discoveryRestUrl": "https://composer.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/composer/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "composer:v1beta1", - "name": "composer", - "version": "v1beta1", - "title": "Cloud Composer API", - "description": "Manages Apache Airflow environments on Google Cloud Platform.", - "discoveryRestUrl": "https://composer.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/composer/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:alpha", - "name": "compute", - "version": "alpha", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/alpha/rest", - "discoveryLink": "./apis/compute/alpha/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:beta", - "name": "compute", - "version": "beta", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/beta/rest", - "discoveryLink": "./apis/compute/beta/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:v1", - "name": "compute", - "version": "v1", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest", - "discoveryLink": "./apis/compute/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "container:v1", - "name": "container", - "version": "v1", - "title": "Kubernetes Engine API", - "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", - "discoveryRestUrl": "https://container.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/container-engine/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "container:v1beta1", - "name": "container", - "version": "v1beta1", - "title": "Kubernetes Engine API", - "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", - "discoveryRestUrl": "https://container.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/container-engine/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "content:v2", - "name": "content", - "version": "v2", - "title": "Content API for Shopping", - "description": "Manages product items, inventory, and Merchant Center accounts for Google Shopping.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/content/v2/rest", - "discoveryLink": "./apis/content/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/shopping-content", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "customsearch:v1", - "name": "customsearch", - "version": "v1", - "title": "CustomSearch API", - "description": "Searches over a website or collection of websites", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/customsearch/v1/rest", - "discoveryLink": "./apis/customsearch/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/custom-search/v1/using_rest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataflow:v1b3", - "name": "dataflow", - "version": "v1b3", - "title": "Dataflow API", - "description": "Manages Google Cloud Dataflow projects on Google Cloud Platform.", - "discoveryRestUrl": "https://dataflow.googleapis.com/$discovery/rest?version=v1b3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataflow", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataproc:v1", - "name": "dataproc", - "version": "v1", - "title": "Cloud Dataproc API", - "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", - "discoveryRestUrl": "https://dataproc.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataproc/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataproc:v1beta2", - "name": "dataproc", - "version": "v1beta2", - "title": "Cloud Dataproc API", - "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", - "discoveryRestUrl": "https://dataproc.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataproc/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1", - "name": "datastore", - "version": "v1", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1beta1", - "name": "datastore", - "version": "v1beta1", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1beta3", - "name": "datastore", - "version": "v1beta3", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1beta3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:alpha", - "name": "deploymentmanager", - "version": "alpha", - "title": "Google Cloud Deployment Manager Alpha API", - "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/alpha/rest", - "discoveryLink": "./apis/deploymentmanager/alpha/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:v2beta", - "name": "deploymentmanager", - "version": "v2beta", - "title": "Google Cloud Deployment Manager API V2Beta Methods", - "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2beta/rest", - "discoveryLink": "./apis/deploymentmanager/v2beta/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/deployment-manager/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:v2", - "name": "deploymentmanager", - "version": "v2", - "title": "Google Cloud Deployment Manager API", - "description": "Declares, configures, and deploys complex solutions on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2/rest", - "discoveryLink": "./apis/deploymentmanager/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v2.8", - "name": "dfareporting", - "version": "v2.8", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v2.8/rest", - "discoveryLink": "./apis/dfareporting/v2.8/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.0", - "name": "dfareporting", - "version": "v3.0", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.0/rest", - "discoveryLink": "./apis/dfareporting/v3.0/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.1", - "name": "dfareporting", - "version": "v3.1", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.1/rest", - "discoveryLink": "./apis/dfareporting/v3.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.2", - "name": "dfareporting", - "version": "v3.2", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.2/rest", - "discoveryLink": "./apis/dfareporting/v3.2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dialogflow:v2", - "name": "dialogflow", - "version": "v2", - "title": "Dialogflow API", - "description": "Builds conversational interfaces (for example, chatbots, and voice-powered apps and devices).", - "discoveryRestUrl": "https://dialogflow.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dialogflow:v2beta1", - "name": "dialogflow", - "version": "v2beta1", - "title": "Dialogflow API", - "description": "Builds conversational interfaces (for example, chatbots, and voice-powered apps and devices).", - "discoveryRestUrl": "https://dialogflow.googleapis.com/$discovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "digitalassetlinks:v1", - "name": "digitalassetlinks", - "version": "v1", - "title": "Digital Asset Links API", - "description": "Discovers relationships between online assets such as websites or mobile apps.", - "discoveryRestUrl": "https://digitalassetlinks.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/digital-asset-links/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "discovery:v1", - "name": "discovery", - "version": "v1", - "title": "APIs Discovery Service", - "description": "Provides information about other Google APIs, such as what APIs are available, the resource, and method details for each API.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/discovery/v1/rest", - "discoveryLink": "./apis/discovery/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/feature/filing_cabinet_search-g16.png", - "x32": "http://www.google.com/images/icons/feature/filing_cabinet_search-g32.png" - }, - "documentationLink": "https://developers.google.com/discovery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dlp:v2", - "name": "dlp", - "version": "v2", - "title": "Cloud Data Loss Prevention (DLP) API", - "description": "Provides methods for detection, risk analysis, and de-identification of privacy-sensitive fragments in text, images, and Google Cloud Platform storage repositories.", - "discoveryRestUrl": "https://dlp.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dlp/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v1", - "name": "dns", - "version": "v1", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1/rest", - "discoveryLink": "./apis/dns/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v1beta2", - "name": "dns", - "version": "v1beta2", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1beta2/rest", - "discoveryLink": "./apis/dns/v1beta2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v2beta1", - "name": "dns", - "version": "v2beta1", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v2beta1/rest", - "discoveryLink": "./apis/dns/v2beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "doubleclickbidmanager:v1", - "name": "doubleclickbidmanager", - "version": "v1", - "title": "DoubleClick Bid Manager API", - "description": "API for viewing and managing your reports in DoubleClick Bid Manager.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclickbidmanager/v1/rest", - "discoveryLink": "./apis/doubleclickbidmanager/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/bid-manager/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "doubleclicksearch:v2", - "name": "doubleclicksearch", - "version": "v2", - "title": "DoubleClick Search API", - "description": "Reports and modifies your advertising data in DoubleClick Search (for example, campaigns, ad groups, keywords, and conversions).", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclicksearch/v2/rest", - "discoveryLink": "./apis/doubleclicksearch/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/doubleclick-search/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "drive:v2", - "name": "drive", - "version": "v2", - "title": "Drive API", - "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v2/rest", - "discoveryLink": "./apis/drive/v2/rest", - "icons": { - "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", - "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" - }, - "documentationLink": "https://developers.google.com/drive/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "drive:v3", - "name": "drive", - "version": "v3", - "title": "Drive API", - "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", - "discoveryLink": "./apis/drive/v3/rest", - "icons": { - "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", - "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" - }, - "documentationLink": "https://developers.google.com/drive/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "file:v1beta1", - "name": "file", - "version": "v1beta1", - "title": "Cloud Filestore API", - "description": "The Cloud Filestore API is used for creating and managing cloud file servers.", - "discoveryRestUrl": "https://file.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/filestore/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebasedynamiclinks:v1", - "name": "firebasedynamiclinks", - "version": "v1", - "title": "Firebase Dynamic Links API", - "description": "Programmatically creates and manages Firebase Dynamic Links.", - "discoveryRestUrl": "https://firebasedynamiclinks.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/dynamic-links/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebasehosting:v1beta1", - "name": "firebasehosting", - "version": "v1beta1", - "title": "Firebase Hosting API", - "description": "", - "discoveryRestUrl": "https://firebasehosting.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/hosting/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebaserules:v1", - "name": "firebaserules", - "version": "v1", - "title": "Firebase Rules API", - "description": "Creates and manages rules that determine when a Firebase Rules-enabled service should permit a request.", - "discoveryRestUrl": "https://firebaserules.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/storage/security", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1", - "name": "firestore", - "version": "v1", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1beta1", - "name": "firestore", - "version": "v1beta1", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1beta2", - "name": "firestore", - "version": "v1beta2", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "fitness:v1", - "name": "fitness", - "version": "v1", - "title": "Fitness", - "description": "Stores and accesses user data in the fitness store from apps on any platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fitness/v1/rest", - "discoveryLink": "./apis/fitness/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fit/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "fusiontables:v1", - "name": "fusiontables", - "version": "v1", - "title": "Fusion Tables API", - "description": "API for working with Fusion Tables data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v1/rest", - "discoveryLink": "./apis/fusiontables/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fusiontables", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "fusiontables:v2", - "name": "fusiontables", - "version": "v2", - "title": "Fusion Tables API", - "description": "API for working with Fusion Tables data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v2/rest", - "discoveryLink": "./apis/fusiontables/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fusiontables", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "games:v1", - "name": "games", - "version": "v1", - "title": "Google Play Game Services API", - "description": "The API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/games/v1/rest", - "discoveryLink": "./apis/games/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gamesConfiguration:v1configuration", - "name": "gamesConfiguration", - "version": "v1configuration", - "title": "Google Play Game Services Publishing API", - "description": "The Publishing API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesConfiguration/v1configuration/rest", - "discoveryLink": "./apis/gamesConfiguration/v1configuration/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gamesManagement:v1management", - "name": "gamesManagement", - "version": "v1management", - "title": "Google Play Game Services Management API", - "description": "The Management API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesManagement/v1management/rest", - "discoveryLink": "./apis/gamesManagement/v1management/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v1alpha2", - "name": "genomics", - "version": "v1alpha2", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v1alpha2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v2alpha1", - "name": "genomics", - "version": "v2alpha1", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v2alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v1", - "name": "genomics", - "version": "v1", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gmail:v1", - "name": "gmail", - "version": "v1", - "title": "Gmail API", - "description": "Access Gmail mailboxes including sending user email.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest", - "discoveryLink": "./apis/gmail/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/googlemail-16.png", - "x32": "https://www.google.com/images/icons/product/googlemail-32.png" - }, - "documentationLink": "https://developers.google.com/gmail/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "groupsmigration:v1", - "name": "groupsmigration", - "version": "v1", - "title": "Groups Migration API", - "description": "Groups Migration Api.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupsmigration/v1/rest", - "discoveryLink": "./apis/groupsmigration/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/discussions-16.gif", - "x32": "https://www.google.com/images/icons/product/discussions-32.gif" - }, - "documentationLink": "https://developers.google.com/google-apps/groups-migration/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "groupssettings:v1", - "name": "groupssettings", - "version": "v1", - "title": "Groups Settings API", - "description": "Lets you manage permission levels and related settings of a group.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupssettings/v1/rest", - "discoveryLink": "./apis/groupssettings/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/groups-settings/get_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iam:v1", - "name": "iam", - "version": "v1", - "title": "Identity and Access Management (IAM) API", - "description": "Manages identity and access control for Google Cloud Platform resources, including the creation of service accounts, which you can use to authenticate to Google and make API calls.", - "discoveryRestUrl": "https://iam.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iam/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iamcredentials:v1", - "name": "iamcredentials", - "version": "v1", - "title": "IAM Service Account Credentials API", - "description": "Creates short-lived, limited-privilege credentials for IAM service accounts.", - "discoveryRestUrl": "https://iamcredentials.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iap:v1beta1", - "name": "iap", - "version": "v1beta1", - "title": "Cloud Identity-Aware Proxy API", - "description": "Controls access to cloud applications running on Google Cloud Platform.", - "discoveryRestUrl": "https://iap.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iap", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "identitytoolkit:v3", - "name": "identitytoolkit", - "version": "v3", - "title": "Google Identity Toolkit API", - "description": "Help the third party sites to implement federated login.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/identitytoolkit/v3/rest", - "discoveryLink": "./apis/identitytoolkit/v3/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/identity-toolkit/v3/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "indexing:v3", - "name": "indexing", - "version": "v3", - "title": "Indexing API", - "description": "Notifies Google when your web pages change.", - "discoveryRestUrl": "https://indexing.googleapis.com/$discovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/search/apis/indexing-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v3p1beta1", - "name": "jobs", - "version": "v3p1beta1", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$discovery/rest?version=v3p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v2", - "name": "jobs", - "version": "v2", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v3", - "name": "jobs", - "version": "v3", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$discovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "kgsearch:v1", - "name": "kgsearch", - "version": "v1", - "title": "Knowledge Graph Search API", - "description": "Searches the Google Knowledge Graph for entities.", - "discoveryRestUrl": "https://kgsearch.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/knowledge-graph/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1", - "name": "language", - "version": "v1", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1beta1", - "name": "language", - "version": "v1beta1", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1beta2", - "name": "language", - "version": "v1beta2", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "licensing:v1", - "name": "licensing", - "version": "v1", - "title": "Enterprise License Manager API", - "description": "Views and manages licenses for your domain.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/licensing/v1/rest", - "discoveryLink": "./apis/licensing/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/licensing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "logging:v2", - "name": "logging", - "version": "v2", - "title": "Stackdriver Logging API", - "description": "Writes log entries and manages your Logging configuration.", - "discoveryRestUrl": "https://logging.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/logging/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "logging:v2beta1", - "name": "logging", - "version": "v2beta1", - "title": "Stackdriver Logging API", - "description": "Writes log entries and manages your Logging configuration.", - "discoveryRestUrl": "https://logging.googleapis.com/$discovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/logging/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "manufacturers:v1", - "name": "manufacturers", - "version": "v1", - "title": "Manufacturer Center API", - "description": "Public API for managing Manufacturer Center related data.", - "discoveryRestUrl": "https://manufacturers.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/manufacturers/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "mirror:v1", - "name": "mirror", - "version": "v1", - "title": "Google Mirror API", - "description": "Interacts with Glass users via the timeline.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/mirror/v1/rest", - "discoveryLink": "./apis/mirror/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/glass", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "ml:v1", - "name": "ml", - "version": "v1", - "title": "Cloud Machine Learning Engine", - "description": "An API to enable creating and using machine learning models.", - "discoveryRestUrl": "https://ml.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/ml/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "monitoring:v3", - "name": "monitoring", - "version": "v3", - "title": "Stackdriver Monitoring API", - "description": "Manages your Stackdriver Monitoring data and configurations. Most projects must be associated with a Stackdriver account, with a few exceptions as noted on the individual method pages.", - "discoveryRestUrl": "https://monitoring.googleapis.com/$discovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/monitoring/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "oauth2:v1", - "name": "oauth2", - "version": "v1", - "title": "Google OAuth2 API", - "description": "Obtains end-user authorization grants for use with other Google APIs.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v1/rest", - "discoveryLink": "./apis/oauth2/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oauth2:v2", - "name": "oauth2", - "version": "v2", - "title": "Google OAuth2 API", - "description": "Obtains end-user authorization grants for use with other Google APIs.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v2/rest", - "discoveryLink": "./apis/oauth2/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1alpha", - "name": "oslogin", - "version": "v1alpha", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1beta", - "name": "oslogin", - "version": "v1beta", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1", - "name": "oslogin", - "version": "v1", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v1", - "name": "pagespeedonline", - "version": "v1", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v1/rest", - "discoveryLink": "./apis/pagespeedonline/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v1/getting_started", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v2", - "name": "pagespeedonline", - "version": "v2", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v2/rest", - "discoveryLink": "./apis/pagespeedonline/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v2/getting-started", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v4", - "name": "pagespeedonline", - "version": "v4", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v4/rest", - "discoveryLink": "./apis/pagespeedonline/v4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v4/getting-started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "partners:v2", - "name": "partners", - "version": "v2", - "title": "Google Partners API", - "description": "Searches certified companies and creates contact leads with them, and also audits the usage of clients.", - "discoveryRestUrl": "https://partners.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/partners/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "people:v1", - "name": "people", - "version": "v1", - "title": "People API", - "description": "Provides access to information about profiles and contacts.", - "discoveryRestUrl": "https://people.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/people/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "playcustomapp:v1", - "name": "playcustomapp", - "version": "v1", - "title": "Google Play Custom App Publishing API", - "description": "An API to publish custom Android apps.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/playcustomapp/v1/rest", - "discoveryLink": "./apis/playcustomapp/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/android/work/play/custom-app-api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "plus:v1", - "name": "plus", - "version": "v1", - "title": "Google+ API", - "description": "Builds on top of the Google+ platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plus/v1/rest", - "discoveryLink": "./apis/plus/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/gplus-16.png", - "x32": "http://www.google.com/images/icons/product/gplus-32.png" - }, - "documentationLink": "https://developers.google.com/+/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "plusDomains:v1", - "name": "plusDomains", - "version": "v1", - "title": "Google+ Domains API", - "description": "Builds on top of the Google+ platform for Google Apps Domains.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plusDomains/v1/rest", - "discoveryLink": "./apis/plusDomains/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/gplus-16.png", - "x32": "http://www.google.com/images/icons/product/gplus-32.png" - }, - "documentationLink": "https://developers.google.com/+/domains/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "poly:v1", - "name": "poly", - "version": "v1", - "title": "Poly API", - "description": "The Poly API provides read access to assets hosted on poly.google.com to all, and upload access to poly.google.com for whitelisted accounts.", - "discoveryRestUrl": "https://poly.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/poly/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "proximitybeacon:v1beta1", - "name": "proximitybeacon", - "version": "v1beta1", - "title": "Proximity Beacon API", - "description": "Registers, manages, indexes, and searches beacons.", - "discoveryRestUrl": "https://proximitybeacon.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/beacons/proximity/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1beta1a", - "name": "pubsub", - "version": "v1beta1a", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1beta1a", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1", - "name": "pubsub", - "version": "v1", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1beta2", - "name": "pubsub", - "version": "v1beta2", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "redis:v1", - "name": "redis", - "version": "v1", - "title": "Google Cloud Memorystore for Redis API", - "description": "The Google Cloud Memorystore for Redis API is used for creating and managing Redis instances on the Google Cloud Platform.", - "discoveryRestUrl": "https://redis.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/memorystore/docs/redis/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "redis:v1beta1", - "name": "redis", - "version": "v1beta1", - "title": "Google Cloud Memorystore for Redis API", - "description": "The Google Cloud Memorystore for Redis API is used for creating and managing Redis instances on the Google Cloud Platform.", - "discoveryRestUrl": "https://redis.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/memorystore/docs/redis/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "replicapool:v1beta1", - "name": "replicapool", - "version": "v1beta1", - "title": "Replica Pool API", - "description": "The Replica Pool API allows users to declaratively provision and manage groups of Google Compute Engine instances based on a common template.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapool/v1beta1/rest", - "discoveryLink": "./apis/replicapool/v1beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/replica-pool/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "replicapoolupdater:v1beta1", - "name": "replicapoolupdater", - "version": "v1beta1", - "title": "Google Compute Engine Instance Group Updater API", - "description": "[Deprecated. Please use compute.instanceGroupManagers.update method. replicapoolupdater API will be disabled after December 30th, 2016] Updates groups of Compute Engine instances.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapoolupdater/v1beta1/rest", - "discoveryLink": "./apis/replicapoolupdater/v1beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/instance-groups/manager/#applying_rolling_updates_using_the_updater_service", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "reseller:v1", - "name": "reseller", - "version": "v1", - "title": "Enterprise Apps Reseller API", - "description": "Creates and manages your customers and their subscriptions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/reseller/v1/rest", - "discoveryLink": "./apis/reseller/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/reseller/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "runtimeconfig:v1", - "name": "runtimeconfig", - "version": "v1", - "title": "Cloud Runtime Configuration API", - "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", - "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "runtimeconfig:v1beta1", - "name": "runtimeconfig", - "version": "v1beta1", - "title": "Cloud Runtime Configuration API", - "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", - "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "safebrowsing:v4", - "name": "safebrowsing", - "version": "v4", - "title": "Safe Browsing API", - "description": "Enables client applications to check web resources (most commonly URLs) against Google-generated lists of unsafe web resources.", - "discoveryRestUrl": "https://safebrowsing.googleapis.com/$discovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/safe-browsing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "script:v1", - "name": "script", - "version": "v1", - "title": "Apps Script API", - "description": "Manages and executes Google Apps Script projects.", - "discoveryRestUrl": "https://script.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/apps-script/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "searchconsole:v1", - "name": "searchconsole", - "version": "v1", - "title": "Google Search Console URL Testing Tools API", - "description": "Provides tools for running validation tests against single URLs", - "discoveryRestUrl": "https://searchconsole.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/webmaster-tools/search-console-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1alpha1", - "name": "servicebroker", - "version": "v1alpha1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1", - "name": "servicebroker", - "version": "v1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1beta1", - "name": "servicebroker", - "version": "v1beta1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "serviceconsumermanagement:v1", - "name": "serviceconsumermanagement", - "version": "v1", - "title": "Service Consumer Management API", - "description": "Manages the service consumers of a Service Infrastructure service.", - "discoveryRestUrl": "https://serviceconsumermanagement.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-consumer-management/docs/overview", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicecontrol:v1", - "name": "servicecontrol", - "version": "v1", - "title": "Service Control API", - "description": "Provides control plane functionality to managed services, such as logging, monitoring, and status checks.", - "discoveryRestUrl": "https://servicecontrol.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-control/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicemanagement:v1", - "name": "servicemanagement", - "version": "v1", - "title": "Service Management API", - "description": "Google Service Management allows service producers to publish their services on Google Cloud Platform so that they can be discovered and used by service consumers.", - "discoveryRestUrl": "https://servicemanagement.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-management/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicenetworking:v1beta", - "name": "servicenetworking", - "version": "v1beta", - "title": "Service Networking API", - "description": "Provides automatic management of network configurations necessary for certain services.", - "discoveryRestUrl": "https://servicenetworking.googleapis.com/$discovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-infrastructure/docs/service-networking/getting-started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "serviceusage:v1", - "name": "serviceusage", - "version": "v1", - "title": "Service Usage API", - "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", - "discoveryRestUrl": "https://serviceusage.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-usage/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "serviceusage:v1beta1", - "name": "serviceusage", - "version": "v1beta1", - "title": "Service Usage API", - "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", - "discoveryRestUrl": "https://serviceusage.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-usage/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "sheets:v4", - "name": "sheets", - "version": "v4", - "title": "Google Sheets API", - "description": "Reads and writes Google Sheets.", - "discoveryRestUrl": "https://sheets.googleapis.com/$discovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/sheets/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "siteVerification:v1", - "name": "siteVerification", - "version": "v1", - "title": "Google Site Verification API", - "description": "Verifies ownership of websites or domains with Google.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/siteVerification/v1/rest", - "discoveryLink": "./apis/siteVerification/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/site-verification/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "slides:v1", - "name": "slides", - "version": "v1", - "title": "Google Slides API", - "description": "An API for creating and editing Google Slides presentations.", - "discoveryRestUrl": "https://slides.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/slides/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "sourcerepo:v1", - "name": "sourcerepo", - "version": "v1", - "title": "Cloud Source Repositories API", - "description": "Access source code repositories hosted by Google.", - "discoveryRestUrl": "https://sourcerepo.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/source-repositories/docs/apis", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "spanner:v1", - "name": "spanner", - "version": "v1", - "title": "Cloud Spanner API", - "description": "Cloud Spanner is a managed, mission-critical, globally consistent and scalable relational database service.", - "discoveryRestUrl": "https://spanner.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/spanner/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "speech:v1", - "name": "speech", - "version": "v1", - "title": "Cloud Speech API", - "description": "Converts audio to text by applying powerful neural network models.", - "discoveryRestUrl": "https://speech.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/speech-to-text/docs/quickstart-protocol", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "speech:v1beta1", - "name": "speech", - "version": "v1beta1", - "title": "Cloud Speech API", - "description": "Converts audio to text by applying powerful neural network models.", - "discoveryRestUrl": "https://speech.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/speech-to-text/docs/quickstart-protocol", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "sqladmin:v1beta4", - "name": "sqladmin", - "version": "v1beta4", - "title": "Cloud SQL Admin API", - "description": "Creates and manages Cloud SQL instances, which provide fully managed MySQL or PostgreSQL databases.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/sqladmin/v1beta4/rest", - "discoveryLink": "./apis/sqladmin/v1beta4/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/sql/docs/reference/latest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1", - "name": "storage", - "version": "v1", - "title": "Cloud Storage JSON API", - "description": "Stores and retrieves potentially large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1/rest", - "discoveryLink": "./apis/storage/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1beta1", - "name": "storage", - "version": "v1beta1", - "title": "Cloud Storage JSON API", - "description": "Lets you store and retrieve potentially-large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta1/rest", - "discoveryLink": "./apis/storage/v1beta1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1beta2", - "name": "storage", - "version": "v1beta2", - "title": "Cloud Storage JSON API", - "description": "Lets you store and retrieve potentially-large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta2/rest", - "discoveryLink": "./apis/storage/v1beta2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "storagetransfer:v1", - "name": "storagetransfer", - "version": "v1", - "title": "Storage Transfer API", - "description": "Transfers data from external data sources to a Google Cloud Storage bucket or between Google Cloud Storage buckets.", - "discoveryRestUrl": "https://storagetransfer.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/storage/transfer", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "streetviewpublish:v1", - "name": "streetviewpublish", - "version": "v1", - "title": "Street View Publish API", - "description": "Publishes 360 photos to Google Maps, along with position, orientation, and connectivity metadata. Apps can offer an interface for positioning, connecting, and uploading user-generated Street View images.", - "discoveryRestUrl": "https://streetviewpublish.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/streetview/publish/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "surveys:v2", - "name": "surveys", - "version": "v2", - "title": "Surveys API", - "description": "Creates and conducts surveys, lists the surveys that an authenticated user owns, and retrieves survey results and information about specified surveys.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/surveys/v2/rest", - "discoveryLink": "./apis/surveys/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tagmanager:v1", - "name": "tagmanager", - "version": "v1", - "title": "Tag Manager API", - "description": "Accesses Tag Manager accounts and containers.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v1/rest", - "discoveryLink": "./apis/tagmanager/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/tag-manager/api/v1/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "tagmanager:v2", - "name": "tagmanager", - "version": "v2", - "title": "Tag Manager API", - "description": "Accesses Tag Manager accounts and containers.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v2/rest", - "discoveryLink": "./apis/tagmanager/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/tag-manager/api/v2/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tasks:v1", - "name": "tasks", - "version": "v1", - "title": "Tasks API", - "description": "Lets you manage your tasks and task lists.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest", - "discoveryLink": "./apis/tasks/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/tasks-16.png", - "x32": "https://www.google.com/images/icons/product/tasks-32.png" - }, - "documentationLink": "https://developers.google.com/google-apps/tasks/firstapp", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "testing:v1", - "name": "testing", - "version": "v1", - "title": "Cloud Testing API", - "description": "Allows developers to run automated tests for their mobile applications on Google infrastructure.", - "discoveryRestUrl": "https://testing.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-test-lab/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "texttospeech:v1", - "name": "texttospeech", - "version": "v1", - "title": "Cloud Text-to-Speech API", - "description": "Synthesizes natural-sounding speech by applying powerful neural network models.", - "discoveryRestUrl": "https://texttospeech.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/text-to-speech/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "texttospeech:v1beta1", - "name": "texttospeech", - "version": "v1beta1", - "title": "Cloud Text-to-Speech API", - "description": "Synthesizes natural-sounding speech by applying powerful neural network models.", - "discoveryRestUrl": "https://texttospeech.googleapis.com/$discovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/text-to-speech/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "toolresults:v1beta3", - "name": "toolresults", - "version": "v1beta3", - "title": "Cloud Tool Results API", - "description": "Reads and publishes results from Firebase Test Lab.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/toolresults/v1beta3/rest", - "discoveryLink": "./apis/toolresults/v1beta3/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/test-lab/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tpu:v1alpha1", - "name": "tpu", - "version": "v1alpha1", - "title": "Cloud TPU API", - "description": "TPU API provides customers with access to Google TPU technology.", - "discoveryRestUrl": "https://tpu.googleapis.com/$discovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tpu/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "tpu:v1", - "name": "tpu", - "version": "v1", - "title": "Cloud TPU API", - "description": "TPU API provides customers with access to Google TPU technology.", - "discoveryRestUrl": "https://tpu.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tpu/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "translate:v2", - "name": "translate", - "version": "v2", - "title": "Cloud Translation API", - "description": "Integrates text translation into your website or application.", - "discoveryRestUrl": "https://translation.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://code.google.com/apis/language/translate/v2/getting_started.html", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "urlshortener:v1", - "name": "urlshortener", - "version": "v1", - "title": "URL Shortener API", - "description": "Lets you create, inspect, and manage goo.gl short URLs", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/urlshortener/v1/rest", - "discoveryLink": "./apis/urlshortener/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/url-shortener/v1/getting_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "vault:v1", - "name": "vault", - "version": "v1", - "title": "G Suite Vault API", - "description": "Archiving and eDiscovery for G Suite.", - "discoveryRestUrl": "https://vault.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/vault", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1p1beta1", - "name": "videointelligence", - "version": "v1p1beta1", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1", - "name": "videointelligence", - "version": "v1", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1beta2", - "name": "videointelligence", - "version": "v1beta2", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1p1beta1", - "name": "vision", - "version": "v1p1beta1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1p2beta1", - "name": "vision", - "version": "v1p2beta1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1p2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1", - "name": "vision", - "version": "v1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "webfonts:v1", - "name": "webfonts", - "version": "v1", - "title": "Google Fonts Developer API", - "description": "Accesses the metadata for all families served by Google Fonts, providing a list of families currently available (including available styles and a list of supported script subsets).", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webfonts/v1/rest", - "discoveryLink": "./apis/webfonts/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/feature/font_api-16.png", - "x32": "https://www.google.com/images/icons/feature/font_api-32.gif" - }, - "documentationLink": "https://developers.google.com/fonts/docs/developer_api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "webmasters:v3", - "name": "webmasters", - "version": "v3", - "title": "Search Console API", - "description": "View Google Search Console data for your verified sites.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webmasters/v3/rest", - "discoveryLink": "./apis/webmasters/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/webmaster_tools-16.png", - "x32": "https://www.google.com/images/icons/product/webmaster_tools-32.png" - }, - "documentationLink": "https://developers.google.com/webmaster-tools/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "websecurityscanner:v1alpha", - "name": "websecurityscanner", - "version": "v1alpha", - "title": "Web Security Scanner API", - "description": "Web Security Scanner API (under development).", - "discoveryRestUrl": "https://websecurityscanner.googleapis.com/$discovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/security-scanner/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "websecurityscanner:v1beta", - "name": "websecurityscanner", - "version": "v1beta", - "title": "Web Security Scanner API", - "description": "Web Security Scanner API (under development).", - "discoveryRestUrl": "https://websecurityscanner.googleapis.com/$discovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/security-scanner/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtube:v3", - "name": "youtube", - "version": "v3", - "title": "YouTube Data API", - "description": "Supports core YouTube features, such as uploading videos, creating and managing playlists, searching for content, and much more.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest", - "discoveryLink": "./apis/youtube/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "https://developers.google.com/youtube/v3", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v1", - "name": "youtubeAnalytics", - "version": "v1", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1/rest", - "discoveryLink": "./apis/youtubeAnalytics/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "http://developers.google.com/youtube/analytics/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v1beta1", - "name": "youtubeAnalytics", - "version": "v1beta1", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1beta1/rest", - "discoveryLink": "./apis/youtubeAnalytics/v1beta1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "http://developers.google.com/youtube/analytics/", - "labels": [ - "deprecated" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v2", - "name": "youtubeAnalytics", - "version": "v2", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://youtubeanalytics.googleapis.com/$discovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/youtube/analytics", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "youtubereporting:v1", - "name": "youtubereporting", - "version": "v1", - "title": "YouTube Reporting API", - "description": "Schedules reporting jobs containing your YouTube Analytics data and downloads the resulting bulk data reports in the form of CSV files.", - "discoveryRestUrl": "https://youtubereporting.googleapis.com/$discovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/youtube/reporting/v1/reports/", - "preferred": true - } - ] -} -_END -} - -sub pre_get_gmail_spec_json -{ - return <<'__END' -{ - "kind": "discovery#restDescription", - "etag": "\"J3WqvAcMk4eQjJXvfSI4Yr8VouA/zhBQnUVXp-QQ6Y6QUt5UiGZD_sA\"", - "discoveryVersion": "v1", - "id": "gmail:v1", - "name": "gmail", - "version": "v1", - "revision": "20180904", - "title": "Gmail API", - "description": "Access Gmail mailboxes including sending user email.", - "ownerDomain": "google.com", - "ownerName": "Google", - "icons": { - "x16": "https://www.google.com/images/icons/product/googlemail-16.png", - "x32": "https://www.google.com/images/icons/product/googlemail-32.png" - }, - "documentationLink": "https://developers.google.com/gmail/api/", - "protocol": "rest", - "baseUrl": "https://www.googleapis.com/gmail/v1/users/", - "basePath": "/gmail/v1/users/", - "rootUrl": "https://www.googleapis.com/", - "servicePath": "gmail/v1/users/", - "batchPath": "batch/gmail/v1", - "parameters": { - "alt": { - "type": "string", - "description": "Data format for the response.", - "default": "json", - "enum": [ - "json" - ], - "enumDescriptions": [ - "Responses with Content-Type of application/json" - ], - "location": "query" - }, - "fields": { - "type": "string", - "description": "Selector specifying which fields to include in a partial response.", - "location": "query" - }, - "key": { - "type": "string", - "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.", - "location": "query" - }, - "oauth_token": { - "type": "string", - "description": "OAuth 2.0 token for the current user.", - "location": "query" - }, - "prettyPrint": { - "type": "boolean", - "description": "Returns response with indentations and line breaks.", - "default": "true", - "location": "query" - }, - "quotaUser": { - "type": "string", - "description": "An opaque string that represents a user for quota purposes. Must not exceed 40 characters.", - "location": "query" - }, - "userIp": { - "type": "string", - "description": "Deprecated. Please use quotaUser instead.", - "location": "query" - } - }, - "auth": { - "oauth2": { - "scopes": { - "https://mail.google.com/": { - "description": "Read, send, delete, and manage your email" - }, - "https://www.googleapis.com/auth/gmail.compose": { - "description": "Manage drafts and send emails" - }, - "https://www.googleapis.com/auth/gmail.insert": { - "description": "Insert mail into your mailbox" - }, - "https://www.googleapis.com/auth/gmail.labels": { - "description": "Manage mailbox labels" - }, - "https://www.googleapis.com/auth/gmail.metadata": { - "description": "View your email message metadata such as labels and headers, but not the email body" - }, - "https://www.googleapis.com/auth/gmail.modify": { - "description": "View and modify but not delete your email" - }, - "https://www.googleapis.com/auth/gmail.readonly": { - "description": "View your email messages and settings" - }, - "https://www.googleapis.com/auth/gmail.send": { - "description": "Send email on your behalf" - }, - "https://www.googleapis.com/auth/gmail.settings.basic": { - "description": "Manage your basic mail settings" - }, - "https://www.googleapis.com/auth/gmail.settings.sharing": { - "description": "Manage your sensitive mail settings, including who can manage your mail" - } - } - } - }, - "schemas": { - "AutoForwarding": { - "id": "AutoForwarding", - "type": "object", - "description": "Auto-forwarding settings for an account.", - "properties": { - "disposition": { - "type": "string", - "description": "The state that a message should be left in after it has been forwarded.", - "enum": [ - "archive", - "dispositionUnspecified", - "leaveInInbox", - "markRead", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - }, - "emailAddress": { - "type": "string", - "description": "Email address to which all incoming messages are forwarded. This email address must be a verified member of the forwarding addresses." - }, - "enabled": { - "type": "boolean", - "description": "Whether all incoming mail is automatically forwarded to another address." - } - } - }, - "BatchDeleteMessagesRequest": { - "id": "BatchDeleteMessagesRequest", - "type": "object", - "properties": { - "ids": { - "type": "array", - "description": "The IDs of the messages to delete.", - "items": { - "type": "string" - } - } - } - }, - "BatchModifyMessagesRequest": { - "id": "BatchModifyMessagesRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of label IDs to add to messages.", - "items": { - "type": "string" - } - }, - "ids": { - "type": "array", - "description": "The IDs of the messages to modify. There is a limit of 1000 ids per request.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list of label IDs to remove from messages.", - "items": { - "type": "string" - } - } - } - }, - "Delegate": { - "id": "Delegate", - "type": "object", - "description": "Settings for a delegate. Delegates can read, send, and delete messages, as well as manage contacts, for the delegator's account. See \"Set up mail delegation\" for more information about delegates.", - "properties": { - "delegateEmail": { - "type": "string", - "description": "The email address of the delegate." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified and can act as a delegate for the account. Read-only.", - "enum": [ - "accepted", - "expired", - "pending", - "rejected", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - } - } - }, - "Draft": { - "id": "Draft", - "type": "object", - "description": "A draft email in the user's mailbox.", - "properties": { - "id": { - "type": "string", - "description": "The immutable ID of the draft.", - "annotations": { - "required": [ - "gmail.users.drafts.send" - ] - } - }, - "message": { - "$ref": "Message", - "description": "The message content of the draft." - } - } - }, - "Filter": { - "id": "Filter", - "type": "object", - "description": "Resource definition for Gmail filters. Filters apply to specific messages instead of an entire email thread.", - "properties": { - "action": { - "$ref": "FilterAction", - "description": "Action that the filter performs." - }, - "criteria": { - "$ref": "FilterCriteria", - "description": "Matching criteria for the filter." - }, - "id": { - "type": "string", - "description": "The server assigned ID of the filter." - } - } - }, - "FilterAction": { - "id": "FilterAction", - "type": "object", - "description": "A set of actions to perform on a message.", - "properties": { - "addLabelIds": { - "type": "array", - "description": "List of labels to add to the message.", - "items": { - "type": "string" - } - }, - "forward": { - "type": "string", - "description": "Email address that the message should be forwarded to." - }, - "removeLabelIds": { - "type": "array", - "description": "List of labels to remove from the message.", - "items": { - "type": "string" - } - } - } - }, - "FilterCriteria": { - "id": "FilterCriteria", - "type": "object", - "description": "Message matching criteria.", - "properties": { - "excludeChats": { - "type": "boolean", - "description": "Whether the response should exclude chats." - }, - "from": { - "type": "string", - "description": "The sender's display name or email address." - }, - "hasAttachment": { - "type": "boolean", - "description": "Whether the message has any attachment." - }, - "negatedQuery": { - "type": "string", - "description": "Only return messages not matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\"." - }, - "query": { - "type": "string", - "description": "Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\"." - }, - "size": { - "type": "integer", - "description": "The size of the entire RFC822 message in bytes, including all headers and attachments.", - "format": "int32" - }, - "sizeComparison": { - "type": "string", - "description": "How the message size in bytes should be in relation to the size field.", - "enum": [ - "larger", - "smaller", - "unspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - }, - "subject": { - "type": "string", - "description": "Case-insensitive phrase found in the message's subject. Trailing and leading whitespace are be trimmed and adjacent spaces are collapsed." - }, - "to": { - "type": "string", - "description": "The recipient's display name or email address. Includes recipients in the \"to\", \"cc\", and \"bcc\" header fields. You can use simply the local part of the email address. For example, \"example\" and \"example@\" both match \"example@gmail.com\". This field is case-insensitive." - } - } - }, - "ForwardingAddress": { - "id": "ForwardingAddress", - "type": "object", - "description": "Settings for a forwarding address.", - "properties": { - "forwardingEmail": { - "type": "string", - "description": "An email address to which messages can be forwarded." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified and is usable for forwarding. Read-only.", - "enum": [ - "accepted", - "pending", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - } - } - }, - "History": { - "id": "History", - "type": "object", - "description": "A record of a change to the user's mailbox. Each history change may affect multiple messages in multiple ways.", - "properties": { - "id": { - "type": "string", - "description": "The mailbox sequence ID.", - "format": "uint64" - }, - "labelsAdded": { - "type": "array", - "description": "Labels added to messages in this history record.", - "items": { - "$ref": "HistoryLabelAdded" - } - }, - "labelsRemoved": { - "type": "array", - "description": "Labels removed from messages in this history record.", - "items": { - "$ref": "HistoryLabelRemoved" - } - }, - "messages": { - "type": "array", - "description": "List of messages changed in this history record. The fields for specific change types, such as messagesAdded may duplicate messages in this field. We recommend using the specific change-type fields instead of this.", - "items": { - "$ref": "Message" - } - }, - "messagesAdded": { - "type": "array", - "description": "Messages added to the mailbox in this history record.", - "items": { - "$ref": "HistoryMessageAdded" - } - }, - "messagesDeleted": { - "type": "array", - "description": "Messages deleted (not Trashed) from the mailbox in this history record.", - "items": { - "$ref": "HistoryMessageDeleted" - } - } - } - }, - "HistoryLabelAdded": { - "id": "HistoryLabelAdded", - "type": "object", - "properties": { - "labelIds": { - "type": "array", - "description": "Label IDs added to the message.", - "items": { - "type": "string" - } - }, - "message": { - "$ref": "Message" - } - } - }, - "HistoryLabelRemoved": { - "id": "HistoryLabelRemoved", - "type": "object", - "properties": { - "labelIds": { - "type": "array", - "description": "Label IDs removed from the message.", - "items": { - "type": "string" - } - }, - "message": { - "$ref": "Message" - } - } - }, - "HistoryMessageAdded": { - "id": "HistoryMessageAdded", - "type": "object", - "properties": { - "message": { - "$ref": "Message" - } - } - }, - "HistoryMessageDeleted": { - "id": "HistoryMessageDeleted", - "type": "object", - "properties": { - "message": { - "$ref": "Message" - } - } - }, - "ImapSettings": { - "id": "ImapSettings", - "type": "object", - "description": "IMAP settings for an account.", - "properties": { - "autoExpunge": { - "type": "boolean", - "description": "If this value is true, Gmail will immediately expunge a message when it is marked as deleted in IMAP. Otherwise, Gmail will wait for an update from the client before expunging messages marked as deleted." - }, - "enabled": { - "type": "boolean", - "description": "Whether IMAP is enabled for the account." - }, - "expungeBehavior": { - "type": "string", - "description": "The action that will be executed on a message when it is marked as deleted and expunged from the last visible IMAP folder.", - "enum": [ - "archive", - "deleteForever", - "expungeBehaviorUnspecified", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "maxFolderSize": { - "type": "integer", - "description": "An optional limit on the number of messages that an IMAP folder may contain. Legal values are 0, 1000, 2000, 5000 or 10000. A value of zero is interpreted to mean that there is no limit.", - "format": "int32" - } - } - }, - "Label": { - "id": "Label", - "type": "object", - "description": "Labels are used to categorize messages and threads within the user's mailbox.", - "properties": { - "color": { - "$ref": "LabelColor", - "description": "The color to assign to the label. Color is only available for labels that have their type set to user." - }, - "id": { - "type": "string", - "description": "The immutable ID of the label.", - "annotations": { - "required": [ - "gmail.users.labels.update" - ] - } - }, - "labelListVisibility": { - "type": "string", - "description": "The visibility of the label in the label list in the Gmail web interface.", - "enum": [ - "labelHide", - "labelShow", - "labelShowIfUnread" - ], - "enumDescriptions": [ - "", - "", - "" - ], - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "messageListVisibility": { - "type": "string", - "description": "The visibility of the label in the message list in the Gmail web interface.", - "enum": [ - "hide", - "show" - ], - "enumDescriptions": [ - "", - "" - ], - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "messagesTotal": { - "type": "integer", - "description": "The total number of messages with the label.", - "format": "int32" - }, - "messagesUnread": { - "type": "integer", - "description": "The number of unread messages with the label.", - "format": "int32" - }, - "name": { - "type": "string", - "description": "The display name of the label.", - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "threadsTotal": { - "type": "integer", - "description": "The total number of threads with the label.", - "format": "int32" - }, - "threadsUnread": { - "type": "integer", - "description": "The number of unread threads with the label.", - "format": "int32" - }, - "type": { - "type": "string", - "description": "The owner type for the label. User labels are created by the user and can be modified and deleted by the user and can be applied to any message or thread. System labels are internally created and cannot be added, modified, or deleted. System labels may be able to be applied to or removed from messages and threads under some circumstances but this is not guaranteed. For example, users can apply and remove the INBOX and UNREAD labels from messages and threads, but cannot apply or remove the DRAFTS or SENT labels from messages or threads.", - "enum": [ - "system", - "user" - ], - "enumDescriptions": [ - "", - "" - ] - } - } - }, - "LabelColor": { - "id": "LabelColor", - "type": "object", - "properties": { - "backgroundColor": { - "type": "string", - "description": "The background color represented as hex string #RRGGBB (ex #000000). This field is required in order to set the color of a label. Only the following predefined set of color values are allowed:\n#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, #fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, #f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, #efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, #e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, #cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, #ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, #822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c" - }, - "textColor": { - "type": "string", - "description": "The text color of the label, represented as hex string. This field is required in order to set the color of a label. Only the following predefined set of color values are allowed:\n#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, #fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, #f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, #efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, #e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, #cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, #ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, #822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c" - } - } - }, - "ListDelegatesResponse": { - "id": "ListDelegatesResponse", - "type": "object", - "description": "Response for the ListDelegates method.", - "properties": { - "delegates": { - "type": "array", - "description": "List of the user's delegates (with any verification status).", - "items": { - "$ref": "Delegate" - } - } - } - }, - "ListDraftsResponse": { - "id": "ListDraftsResponse", - "type": "object", - "properties": { - "drafts": { - "type": "array", - "description": "List of drafts.", - "items": { - "$ref": "Draft" - } - }, - "nextPageToken": { - "type": "string", - "description": "Token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - } - } - }, - "ListFiltersResponse": { - "id": "ListFiltersResponse", - "type": "object", - "description": "Response for the ListFilters method.", - "properties": { - "filter": { - "type": "array", - "description": "List of a user's filters.", - "items": { - "$ref": "Filter" - } - } - } - }, - "ListForwardingAddressesResponse": { - "id": "ListForwardingAddressesResponse", - "type": "object", - "description": "Response for the ListForwardingAddresses method.", - "properties": { - "forwardingAddresses": { - "type": "array", - "description": "List of addresses that may be used for forwarding.", - "items": { - "$ref": "ForwardingAddress" - } - } - } - }, - "ListHistoryResponse": { - "id": "ListHistoryResponse", - "type": "object", - "properties": { - "history": { - "type": "array", - "description": "List of history records. Any messages contained in the response will typically only have id and threadId fields populated.", - "items": { - "$ref": "History" - } - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - }, - "nextPageToken": { - "type": "string", - "description": "Page token to retrieve the next page of results in the list." - } - } - }, - "ListLabelsResponse": { - "id": "ListLabelsResponse", - "type": "object", - "properties": { - "labels": { - "type": "array", - "description": "List of labels.", - "items": { - "$ref": "Label" - } - } - } - }, - "ListMessagesResponse": { - "id": "ListMessagesResponse", - "type": "object", - "properties": { - "messages": { - "type": "array", - "description": "List of messages.", - "items": { - "$ref": "Message" - } - }, - "nextPageToken": { - "type": "string", - "description": "Token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - } - } - }, - "ListSendAsResponse": { - "id": "ListSendAsResponse", - "type": "object", - "description": "Response for the ListSendAs method.", - "properties": { - "sendAs": { - "type": "array", - "description": "List of send-as aliases.", - "items": { - "$ref": "SendAs" - } - } - } - }, - "ListSmimeInfoResponse": { - "id": "ListSmimeInfoResponse", - "type": "object", - "properties": { - "smimeInfo": { - "type": "array", - "description": "List of SmimeInfo.", - "items": { - "$ref": "SmimeInfo" - } - } - } - }, - "ListThreadsResponse": { - "id": "ListThreadsResponse", - "type": "object", - "properties": { - "nextPageToken": { - "type": "string", - "description": "Page token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - }, - "threads": { - "type": "array", - "description": "List of threads.", - "items": { - "$ref": "Thread" - } - } - } - }, - "Message": { - "id": "Message", - "type": "object", - "description": "An email message.", - "properties": { - "historyId": { - "type": "string", - "description": "The ID of the last history record that modified this message.", - "format": "uint64" - }, - "id": { - "type": "string", - "description": "The immutable ID of the message." - }, - "internalDate": { - "type": "string", - "description": "The internal message creation timestamp (epoch ms), which determines ordering in the inbox. For normal SMTP-received email, this represents the time the message was originally accepted by Google, which is more reliable than the Date header. However, for API-migrated mail, it can be configured by client to be based on the Date header.", - "format": "int64" - }, - "labelIds": { - "type": "array", - "description": "List of IDs of labels applied to this message.", - "items": { - "type": "string" - } - }, - "payload": { - "$ref": "MessagePart", - "description": "The parsed email structure in the message parts." - }, - "raw": { - "type": "string", - "description": "The entire email message in an RFC 2822 formatted and base64url encoded string. Returned in messages.get and drafts.get responses when the format=RAW parameter is supplied.", - "format": "byte", - "annotations": { - "required": [ - "gmail.users.drafts.create", - "gmail.users.drafts.update", - "gmail.users.messages.insert", - "gmail.users.messages.send" - ] - } - }, - "sizeEstimate": { - "type": "integer", - "description": "Estimated size in bytes of the message.", - "format": "int32" - }, - "snippet": { - "type": "string", - "description": "A short part of the message text." - }, - "threadId": { - "type": "string", - "description": "The ID of the thread the message belongs to. To add a message or draft to a thread, the following criteria must be met: \n- The requested threadId must be specified on the Message or Draft.Message you supply with your request. \n- The References and In-Reply-To headers must be set in compliance with the RFC 2822 standard. \n- The Subject headers must match." - } - } - }, - "MessagePart": { - "id": "MessagePart", - "type": "object", - "description": "A single MIME message part.", - "properties": { - "body": { - "$ref": "MessagePartBody", - "description": "The message part body for this part, which may be empty for container MIME message parts." - }, - "filename": { - "type": "string", - "description": "The filename of the attachment. Only present if this message part represents an attachment." - }, - "headers": { - "type": "array", - "description": "List of headers on this message part. For the top-level message part, representing the entire message payload, it will contain the standard RFC 2822 email headers such as To, From, and Subject.", - "items": { - "$ref": "MessagePartHeader" - } - }, - "mimeType": { - "type": "string", - "description": "The MIME type of the message part." - }, - "partId": { - "type": "string", - "description": "The immutable ID of the message part." - }, - "parts": { - "type": "array", - "description": "The child MIME message parts of this part. This only applies to container MIME message parts, for example multipart/*. For non- container MIME message part types, such as text/plain, this field is empty. For more information, see RFC 1521.", - "items": { - "$ref": "MessagePart" - } - } - } - }, - "MessagePartBody": { - "id": "MessagePartBody", - "type": "object", - "description": "The body of a single MIME message part.", - "properties": { - "attachmentId": { - "type": "string", - "description": "When present, contains the ID of an external attachment that can be retrieved in a separate messages.attachments.get request. When not present, the entire content of the message part body is contained in the data field." - }, - "data": { - "type": "string", - "description": "The body data of a MIME message part as a base64url encoded string. May be empty for MIME container types that have no message body or when the body data is sent as a separate attachment. An attachment ID is present if the body data is contained in a separate attachment.", - "format": "byte" - }, - "size": { - "type": "integer", - "description": "Number of bytes for the message part data (encoding notwithstanding).", - "format": "int32" - } - } - }, - "MessagePartHeader": { - "id": "MessagePartHeader", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the header before the : separator. For example, To." - }, - "value": { - "type": "string", - "description": "The value of the header after the : separator. For example, someuser@example.com." - } - } - }, - "ModifyMessageRequest": { - "id": "ModifyMessageRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of IDs of labels to add to this message.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list IDs of labels to remove from this message.", - "items": { - "type": "string" - } - } - } - }, - "ModifyThreadRequest": { - "id": "ModifyThreadRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of IDs of labels to add to this thread.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list of IDs of labels to remove from this thread.", - "items": { - "type": "string" - } - } - } - }, - "PopSettings": { - "id": "PopSettings", - "type": "object", - "description": "POP settings for an account.", - "properties": { - "accessWindow": { - "type": "string", - "description": "The range of messages which are accessible via POP.", - "enum": [ - "accessWindowUnspecified", - "allMail", - "disabled", - "fromNowOn" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "disposition": { - "type": "string", - "description": "The action that will be executed on a message after it has been fetched via POP.", - "enum": [ - "archive", - "dispositionUnspecified", - "leaveInInbox", - "markRead", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - } - } - }, - "Profile": { - "id": "Profile", - "type": "object", - "description": "Profile for a Gmail user.", - "properties": { - "emailAddress": { - "type": "string", - "description": "The user's email address." - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - }, - "messagesTotal": { - "type": "integer", - "description": "The total number of messages in the mailbox.", - "format": "int32" - }, - "threadsTotal": { - "type": "integer", - "description": "The total number of threads in the mailbox.", - "format": "int32" - } - } - }, - "SendAs": { - "id": "SendAs", - "type": "object", - "description": "Settings associated with a send-as alias, which can be either the primary login address associated with the account or a custom \"from\" address. Send-as aliases correspond to the \"Send Mail As\" feature in the web interface.", - "properties": { - "displayName": { - "type": "string", - "description": "A name that appears in the \"From:\" header for mail sent using this alias. For custom \"from\" addresses, when this is empty, Gmail will populate the \"From:\" header with the name that is used for the primary address associated with the account. If the admin has disabled the ability for users to update their name format, requests to update this field for the primary login will silently fail." - }, - "isDefault": { - "type": "boolean", - "description": "Whether this address is selected as the default \"From:\" address in situations such as composing a new message or sending a vacation auto-reply. Every Gmail account has exactly one default send-as address, so the only legal value that clients may write to this field is true. Changing this from false to true for an address will result in this field becoming false for the other previous default address." - }, - "isPrimary": { - "type": "boolean", - "description": "Whether this address is the primary address used to login to the account. Every Gmail account has exactly one primary address, and it cannot be deleted from the collection of send-as aliases. This field is read-only." - }, - "replyToAddress": { - "type": "string", - "description": "An optional email address that is included in a \"Reply-To:\" header for mail sent using this alias. If this is empty, Gmail will not generate a \"Reply-To:\" header." - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias. This is read-only for all operations except create." - }, - "signature": { - "type": "string", - "description": "An optional HTML signature that is included in messages composed with this alias in the Gmail web UI." - }, - "smtpMsa": { - "$ref": "SmtpMsa", - "description": "An optional SMTP service that will be used as an outbound relay for mail sent using this alias. If this is empty, outbound mail will be sent directly from Gmail's servers to the destination SMTP service. This setting only applies to custom \"from\" aliases." - }, - "treatAsAlias": { - "type": "boolean", - "description": "Whether Gmail should treat this address as an alias for the user's primary email address. This setting only applies to custom \"from\" aliases." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified for use as a send-as alias. Read-only. This setting only applies to custom \"from\" aliases.", - "enum": [ - "accepted", - "pending", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - } - } - }, - "SmimeInfo": { - "id": "SmimeInfo", - "type": "object", - "description": "An S/MIME email config.", - "properties": { - "encryptedKeyPassword": { - "type": "string", - "description": "Encrypted key password, when key is encrypted." - }, - "expiration": { - "type": "string", - "description": "When the certificate expires (in milliseconds since epoch).", - "format": "int64" - }, - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo." - }, - "isDefault": { - "type": "boolean", - "description": "Whether this SmimeInfo is the default one for this user's send-as address." - }, - "issuerCn": { - "type": "string", - "description": "The S/MIME certificate issuer's common name." - }, - "pem": { - "type": "string", - "description": "PEM formatted X509 concatenated certificate string (standard base64 encoding). Format used for returning key, which includes public key as well as certificate chain (not private key)." - }, - "pkcs12": { - "type": "string", - "description": "PKCS#12 format containing a single private/public key pair and certificate chain. This format is only accepted from client for creating a new SmimeInfo and is never returned, because the private key is not intended to be exported. PKCS#12 may be encrypted, in which case encryptedKeyPassword should be set appropriately.", - "format": "byte" - } - } - }, - "SmtpMsa": { - "id": "SmtpMsa", - "type": "object", - "description": "Configuration for communication with an SMTP service.", - "properties": { - "host": { - "type": "string", - "description": "The hostname of the SMTP service. Required." - }, - "password": { - "type": "string", - "description": "The password that will be used for authentication with the SMTP service. This is a write-only field that can be specified in requests to create or update SendAs settings; it is never populated in responses." - }, - "port": { - "type": "integer", - "description": "The port of the SMTP service. Required.", - "format": "int32" - }, - "securityMode": { - "type": "string", - "description": "The protocol that will be used to secure communication with the SMTP service. Required.", - "enum": [ - "none", - "securityModeUnspecified", - "ssl", - "starttls" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "username": { - "type": "string", - "description": "The username that will be used for authentication with the SMTP service. This is a write-only field that can be specified in requests to create or update SendAs settings; it is never populated in responses." - } - } - }, - "Thread": { - "id": "Thread", - "type": "object", - "description": "A collection of messages representing a conversation.", - "properties": { - "historyId": { - "type": "string", - "description": "The ID of the last history record that modified this thread.", - "format": "uint64" - }, - "id": { - "type": "string", - "description": "The unique ID of the thread." - }, - "messages": { - "type": "array", - "description": "The list of messages in the thread.", - "items": { - "$ref": "Message" - } - }, - "snippet": { - "type": "string", - "description": "A short part of the message text." - } - } - }, - "VacationSettings": { - "id": "VacationSettings", - "type": "object", - "description": "Vacation auto-reply settings for an account. These settings correspond to the \"Vacation responder\" feature in the web interface.", - "properties": { - "enableAutoReply": { - "type": "boolean", - "description": "Flag that controls whether Gmail automatically replies to messages." - }, - "endTime": { - "type": "string", - "description": "An optional end time for sending auto-replies (epoch ms). When this is specified, Gmail will automatically reply only to messages that it receives before the end time. If both startTime and endTime are specified, startTime must precede endTime.", - "format": "int64" - }, - "responseBodyHtml": { - "type": "string", - "description": "Response body in HTML format. Gmail will sanitize the HTML before storing it." - }, - "responseBodyPlainText": { - "type": "string", - "description": "Response body in plain text format." - }, - "responseSubject": { - "type": "string", - "description": "Optional text to prepend to the subject line in vacation responses. In order to enable auto-replies, either the response subject or the response body must be nonempty." - }, - "restrictToContacts": { - "type": "boolean", - "description": "Flag that determines whether responses are sent to recipients who are not in the user's list of contacts." - }, - "restrictToDomain": { - "type": "boolean", - "description": "Flag that determines whether responses are sent to recipients who are outside of the user's domain. This feature is only available for G Suite users." - }, - "startTime": { - "type": "string", - "description": "An optional start time for sending auto-replies (epoch ms). When this is specified, Gmail will automatically reply only to messages that it receives after the start time. If both startTime and endTime are specified, startTime must precede endTime.", - "format": "int64" - } - } - }, - "WatchRequest": { - "id": "WatchRequest", - "type": "object", - "description": "Set up or update a new push notification watch on this user's mailbox.", - "properties": { - "labelFilterAction": { - "type": "string", - "description": "Filtering behavior of labelIds list specified.", - "enum": [ - "exclude", - "include" - ], - "enumDescriptions": [ - "", - "" - ] - }, - "labelIds": { - "type": "array", - "description": "List of label_ids to restrict notifications about. By default, if unspecified, all changes are pushed out. If specified then dictates which labels are required for a push notification to be generated.", - "items": { - "type": "string" - } - }, - "topicName": { - "type": "string", - "description": "A fully qualified Google Cloud Pub/Sub API topic name to publish the events to. This topic name **must** already exist in Cloud Pub/Sub and you **must** have already granted gmail \"publish\" permission on it. For example, \"projects/my-project-identifier/topics/my-topic-name\" (using the Cloud Pub/Sub \"v1\" topic naming format).\n\nNote that the \"my-project-identifier\" portion must exactly match your Google developer project id (the one executing this watch request)." - } - } - }, - "WatchResponse": { - "id": "WatchResponse", - "type": "object", - "description": "Push notification watch response.", - "properties": { - "expiration": { - "type": "string", - "description": "When Gmail will stop sending notifications for mailbox updates (epoch millis). Call watch again before this time to renew the watch.", - "format": "int64" - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - } - } - } - }, - "resources": { - "users": { - "methods": { - "getProfile": { - "id": "gmail.users.getProfile", - "path": "{userId}/profile", - "httpMethod": "GET", - "description": "Gets the current user's Gmail profile.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "Profile" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "stop": { - "id": "gmail.users.stop", - "path": "{userId}/stop", - "httpMethod": "POST", - "description": "Stop receiving push notifications for the given user mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "watch": { - "id": "gmail.users.watch", - "path": "{userId}/watch", - "httpMethod": "POST", - "description": "Set up or update a push notification watch on the given user mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "WatchRequest" - }, - "response": { - "$ref": "WatchResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - }, - "resources": { - "drafts": { - "methods": { - "create": { - "id": "gmail.users.drafts.create", - "path": "{userId}/drafts", - "httpMethod": "POST", - "description": "Creates a new draft with the DRAFT label.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts" - } - } - } - }, - "delete": { - "id": "gmail.users.drafts.delete", - "path": "{userId}/drafts/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified draft. Does not simply trash it.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the draft to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "get": { - "id": "gmail.users.drafts.get", - "path": "{userId}/drafts/{id}", - "httpMethod": "GET", - "description": "Gets the specified draft.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the draft in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal", - "raw" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the draft to retrieve.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.drafts.list", - "path": "{userId}/drafts", - "httpMethod": "GET", - "description": "Lists the drafts in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include drafts from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of drafts to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return draft messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\".", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListDraftsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "send": { - "id": "gmail.users.drafts.send", - "path": "{userId}/drafts/send", - "httpMethod": "POST", - "description": "Sends the specified, existing draft to the recipients in the To, Cc, and Bcc headers.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts/send" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts/send" - } - } - } - }, - "update": { - "id": "gmail.users.drafts.update", - "path": "{userId}/drafts/{id}", - "httpMethod": "PUT", - "description": "Replaces a draft's content.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the draft to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts/{id}" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts/{id}" - } - } - } - } - } - }, - "history": { - "methods": { - "list": { - "id": "gmail.users.history.list", - "path": "{userId}/history", - "httpMethod": "GET", - "description": "Lists the history of all changes to the given mailbox. History results are returned in chronological order (increasing historyId).", - "parameters": { - "historyTypes": { - "type": "string", - "description": "History types to be returned by the function", - "enum": [ - "labelAdded", - "labelRemoved", - "messageAdded", - "messageDeleted" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "repeated": true, - "location": "query" - }, - "labelId": { - "type": "string", - "description": "Only return messages with a label matching the ID.", - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "The maximum number of history records to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "startHistoryId": { - "type": "string", - "description": "Required. Returns history records after the specified startHistoryId. The supplied startHistoryId should be obtained from the historyId of a message, thread, or previous list response. History IDs increase chronologically but are not contiguous with random gaps in between valid IDs. Supplying an invalid or out of date startHistoryId typically returns an HTTP 404 error code. A historyId is typically valid for at least a week, but in some rare circumstances may be valid for only a few hours. If you receive an HTTP 404 error response, your application should perform a full sync. If you receive no nextPageToken in the response, there are no updates to retrieve and you can store the returned historyId for a future request.", - "format": "uint64", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListHistoryResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - } - }, - "labels": { - "methods": { - "create": { - "id": "gmail.users.labels.create", - "path": "{userId}/labels", - "httpMethod": "POST", - "description": "Creates a new label.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "delete": { - "id": "gmail.users.labels.delete", - "path": "{userId}/labels/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified label and removes it from any messages and threads that it is applied to.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "get": { - "id": "gmail.users.labels.get", - "path": "{userId}/labels/{id}", - "httpMethod": "GET", - "description": "Gets the specified label.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to retrieve.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.labels.list", - "path": "{userId}/labels", - "httpMethod": "GET", - "description": "Lists all labels in the user's mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListLabelsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "patch": { - "id": "gmail.users.labels.patch", - "path": "{userId}/labels/{id}", - "httpMethod": "PATCH", - "description": "Updates the specified label. This method supports patch semantics.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "update": { - "id": "gmail.users.labels.update", - "path": "{userId}/labels/{id}", - "httpMethod": "PUT", - "description": "Updates the specified label.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - } - }, - "messages": { - "methods": { - "batchDelete": { - "id": "gmail.users.messages.batchDelete", - "path": "{userId}/messages/batchDelete", - "httpMethod": "POST", - "description": "Deletes many messages by message ID. Provides no guarantees that messages were not already deleted or even existed at all.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "BatchDeleteMessagesRequest" - }, - "scopes": [ - "https://mail.google.com/" - ] - }, - "batchModify": { - "id": "gmail.users.messages.batchModify", - "path": "{userId}/messages/batchModify", - "httpMethod": "POST", - "description": "Modifies the labels on the specified messages.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "BatchModifyMessagesRequest" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "delete": { - "id": "gmail.users.messages.delete", - "path": "{userId}/messages/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified message. This operation cannot be undone. Prefer messages.trash instead.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/" - ] - }, - "get": { - "id": "gmail.users.messages.get", - "path": "{userId}/messages/{id}", - "httpMethod": "GET", - "description": "Gets the specified message.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the message in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal", - "raw" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the message to retrieve.", - "required": true, - "location": "path" - }, - "metadataHeaders": { - "type": "string", - "description": "When given and format is METADATA, only include headers specified.", - "repeated": true, - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "import": { - "id": "gmail.users.messages.import", - "path": "{userId}/messages/import", - "httpMethod": "POST", - "description": "Imports a message into only this user's mailbox, with standard email delivery scanning and classification similar to receiving via SMTP. Does not send a message.", - "parameters": { - "deleted": { - "type": "boolean", - "description": "Mark the email as permanently deleted (not TRASH) and only visible in Google Vault to a Vault administrator. Only used for G Suite accounts.", - "default": "false", - "location": "query" - }, - "internalDateSource": { - "type": "string", - "description": "Source for Gmail's internal date of the message.", - "default": "dateHeader", - "enum": [ - "dateHeader", - "receivedTime" - ], - "enumDescriptions": [ - "", - "" - ], - "location": "query" - }, - "neverMarkSpam": { - "type": "boolean", - "description": "Ignore the Gmail spam classifier decision and never mark this email as SPAM in the mailbox.", - "default": "false", - "location": "query" - }, - "processForCalendar": { - "type": "boolean", - "description": "Process calendar invites in the email and add any extracted meetings to the Google Calendar for this user.", - "default": "false", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.insert", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "50MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages/import" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages/import" - } - } - } - }, - "insert": { - "id": "gmail.users.messages.insert", - "path": "{userId}/messages", - "httpMethod": "POST", - "description": "Directly inserts a message into only this user's mailbox similar to IMAP APPEND, bypassing most scanning and classification. Does not send a message.", - "parameters": { - "deleted": { - "type": "boolean", - "description": "Mark the email as permanently deleted (not TRASH) and only visible in Google Vault to a Vault administrator. Only used for G Suite accounts.", - "default": "false", - "location": "query" - }, - "internalDateSource": { - "type": "string", - "description": "Source for Gmail's internal date of the message.", - "default": "receivedTime", - "enum": [ - "dateHeader", - "receivedTime" - ], - "enumDescriptions": [ - "", - "" - ], - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.insert", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "50MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages" - } - } - } - }, - "list": { - "id": "gmail.users.messages.list", - "path": "{userId}/messages", - "httpMethod": "GET", - "description": "Lists the messages in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include messages from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "labelIds": { - "type": "string", - "description": "Only return messages with labels that match all of the specified label IDs.", - "repeated": true, - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of messages to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid:\u003csomemsgid@example.com\u003e is:unread\". Parameter cannot be used when accessing the api using the gmail.metadata scope.", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListMessagesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "modify": { - "id": "gmail.users.messages.modify", - "path": "{userId}/messages/{id}/modify", - "httpMethod": "POST", - "description": "Modifies the labels on the specified message.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to modify.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "ModifyMessageRequest" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "send": { - "id": "gmail.users.messages.send", - "path": "{userId}/messages/send", - "httpMethod": "POST", - "description": "Sends the specified message to the recipients in the To, Cc, and Bcc headers.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.send" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages/send" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages/send" - } - } - } - }, - "trash": { - "id": "gmail.users.messages.trash", - "path": "{userId}/messages/{id}/trash", - "httpMethod": "POST", - "description": "Moves the specified message to the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "untrash": { - "id": "gmail.users.messages.untrash", - "path": "{userId}/messages/{id}/untrash", - "httpMethod": "POST", - "description": "Removes the specified message from the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to remove from Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - }, - "resources": { - "attachments": { - "methods": { - "get": { - "id": "gmail.users.messages.attachments.get", - "path": "{userId}/messages/{messageId}/attachments/{id}", - "httpMethod": "GET", - "description": "Gets the specified message attachment.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the attachment.", - "required": true, - "location": "path" - }, - "messageId": { - "type": "string", - "description": "The ID of the message containing the attachment.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "messageId", - "id" - ], - "response": { - "$ref": "MessagePartBody" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - } - } - } - }, - "settings": { - "methods": { - "getAutoForwarding": { - "id": "gmail.users.settings.getAutoForwarding", - "path": "{userId}/settings/autoForwarding", - "httpMethod": "GET", - "description": "Gets the auto-forwarding setting for the specified account.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "AutoForwarding" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getImap": { - "id": "gmail.users.settings.getImap", - "path": "{userId}/settings/imap", - "httpMethod": "GET", - "description": "Gets IMAP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ImapSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getPop": { - "id": "gmail.users.settings.getPop", - "path": "{userId}/settings/pop", - "httpMethod": "GET", - "description": "Gets POP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "PopSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getVacation": { - "id": "gmail.users.settings.getVacation", - "path": "{userId}/settings/vacation", - "httpMethod": "GET", - "description": "Gets vacation responder settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "VacationSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updateAutoForwarding": { - "id": "gmail.users.settings.updateAutoForwarding", - "path": "{userId}/settings/autoForwarding", - "httpMethod": "PUT", - "description": "Updates the auto-forwarding setting for the specified account. A verified forwarding address must be specified when auto-forwarding is enabled.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "AutoForwarding" - }, - "response": { - "$ref": "AutoForwarding" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "updateImap": { - "id": "gmail.users.settings.updateImap", - "path": "{userId}/settings/imap", - "httpMethod": "PUT", - "description": "Updates IMAP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "ImapSettings" - }, - "response": { - "$ref": "ImapSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updatePop": { - "id": "gmail.users.settings.updatePop", - "path": "{userId}/settings/pop", - "httpMethod": "PUT", - "description": "Updates POP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "PopSettings" - }, - "response": { - "$ref": "PopSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updateVacation": { - "id": "gmail.users.settings.updateVacation", - "path": "{userId}/settings/vacation", - "httpMethod": "PUT", - "description": "Updates vacation responder settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "VacationSettings" - }, - "response": { - "$ref": "VacationSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - }, - "resources": { - "delegates": { - "methods": { - "create": { - "id": "gmail.users.settings.delegates.create", - "path": "{userId}/settings/delegates", - "httpMethod": "POST", - "description": "Adds a delegate with its verification status set directly to accepted, without sending any verification email. The delegate user must be a member of the same G Suite organization as the delegator user.\n\nGmail imposes limtations on the number of delegates and delegators each user in a G Suite organization can have. These limits depend on your organization, but in general each user can have up to 25 delegates and up to 10 delegators.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nAlso note that when a new delegate is created, there may be up to a one minute delay before the new delegate is available for use.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Delegate" - }, - "response": { - "$ref": "Delegate" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.delegates.delete", - "path": "{userId}/settings/delegates/{delegateEmail}", - "httpMethod": "DELETE", - "description": "Removes the specified delegate (which can be of any verification status), and revokes any verification that may have been required for using it.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "delegateEmail": { - "type": "string", - "description": "The email address of the user to be removed as a delegate.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "delegateEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.delegates.get", - "path": "{userId}/settings/delegates/{delegateEmail}", - "httpMethod": "GET", - "description": "Gets the specified delegate.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "delegateEmail": { - "type": "string", - "description": "The email address of the user whose delegate relationship is to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "delegateEmail" - ], - "response": { - "$ref": "Delegate" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.delegates.list", - "path": "{userId}/settings/delegates", - "httpMethod": "GET", - "description": "Lists the delegates for the specified account.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListDelegatesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "filters": { - "methods": { - "create": { - "id": "gmail.users.settings.filters.create", - "path": "{userId}/settings/filters", - "httpMethod": "POST", - "description": "Creates a filter.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Filter" - }, - "response": { - "$ref": "Filter" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "delete": { - "id": "gmail.users.settings.filters.delete", - "path": "{userId}/settings/filters/{id}", - "httpMethod": "DELETE", - "description": "Deletes a filter.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the filter to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "get": { - "id": "gmail.users.settings.filters.get", - "path": "{userId}/settings/filters/{id}", - "httpMethod": "GET", - "description": "Gets a filter.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the filter to be fetched.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Filter" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.filters.list", - "path": "{userId}/settings/filters", - "httpMethod": "GET", - "description": "Lists the message filters of a Gmail user.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListFiltersResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "forwardingAddresses": { - "methods": { - "create": { - "id": "gmail.users.settings.forwardingAddresses.create", - "path": "{userId}/settings/forwardingAddresses", - "httpMethod": "POST", - "description": "Creates a forwarding address. If ownership verification is required, a message will be sent to the recipient and the resource's verification status will be set to pending; otherwise, the resource will be created with verification status set to accepted.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "ForwardingAddress" - }, - "response": { - "$ref": "ForwardingAddress" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.forwardingAddresses.delete", - "path": "{userId}/settings/forwardingAddresses/{forwardingEmail}", - "httpMethod": "DELETE", - "description": "Deletes the specified forwarding address and revokes any verification that may have been required.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "forwardingEmail": { - "type": "string", - "description": "The forwarding address to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "forwardingEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.forwardingAddresses.get", - "path": "{userId}/settings/forwardingAddresses/{forwardingEmail}", - "httpMethod": "GET", - "description": "Gets the specified forwarding address.", - "parameters": { - "forwardingEmail": { - "type": "string", - "description": "The forwarding address to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "forwardingEmail" - ], - "response": { - "$ref": "ForwardingAddress" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.forwardingAddresses.list", - "path": "{userId}/settings/forwardingAddresses", - "httpMethod": "GET", - "description": "Lists the forwarding addresses for the specified account.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListForwardingAddressesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "sendAs": { - "methods": { - "create": { - "id": "gmail.users.settings.sendAs.create", - "path": "{userId}/settings/sendAs", - "httpMethod": "POST", - "description": "Creates a custom \"from\" send-as alias. If an SMTP MSA is specified, Gmail will attempt to connect to the SMTP service to validate the configuration before creating the alias. If ownership verification is required for the alias, a message will be sent to the email address and the resource's verification status will be set to pending; otherwise, the resource will be created with verification status set to accepted. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.sendAs.delete", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "DELETE", - "description": "Deletes the specified send-as alias. Revokes any verification that may have been required for using it.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.sendAs.get", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "GET", - "description": "Gets the specified send-as alias. Fails with an HTTP 404 error if the specified address is not a member of the collection.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.sendAs.list", - "path": "{userId}/settings/sendAs", - "httpMethod": "GET", - "description": "Lists the send-as aliases for the specified account. The result includes the primary send-as address associated with the account as well as any custom \"from\" aliases.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListSendAsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "patch": { - "id": "gmail.users.settings.sendAs.patch", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "PATCH", - "description": "Updates a send-as alias. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nAddresses other than the primary address for the account can only be updated by service account clients that have been delegated domain-wide authority. This method supports patch semantics.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be updated.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "update": { - "id": "gmail.users.settings.sendAs.update", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "PUT", - "description": "Updates a send-as alias. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nAddresses other than the primary address for the account can only be updated by service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be updated.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "verify": { - "id": "gmail.users.settings.sendAs.verify", - "path": "{userId}/settings/sendAs/{sendAsEmail}/verify", - "httpMethod": "POST", - "description": "Sends a verification email to the specified send-as alias address. The verification status must be pending.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be verified.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - } - }, - "resources": { - "smimeInfo": { - "methods": { - "delete": { - "id": "gmail.users.settings.sendAs.smimeInfo.delete", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}", - "httpMethod": "DELETE", - "description": "Deletes the specified S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.sendAs.smimeInfo.get", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}", - "httpMethod": "GET", - "description": "Gets the specified S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "response": { - "$ref": "SmimeInfo" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "insert": { - "id": "gmail.users.settings.sendAs.smimeInfo.insert", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo", - "httpMethod": "POST", - "description": "Insert (upload) the given S/MIME config for the specified send-as alias. Note that pkcs12 format is required for the key.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SmimeInfo" - }, - "response": { - "$ref": "SmimeInfo" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "list": { - "id": "gmail.users.settings.sendAs.smimeInfo.list", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo", - "httpMethod": "GET", - "description": "Lists S/MIME configs for the specified send-as alias.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "response": { - "$ref": "ListSmimeInfoResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "setDefault": { - "id": "gmail.users.settings.sendAs.smimeInfo.setDefault", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}/setDefault", - "httpMethod": "POST", - "description": "Sets the default S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - } - } - } - } - } - } - }, - "threads": { - "methods": { - "delete": { - "id": "gmail.users.threads.delete", - "path": "{userId}/threads/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified thread. This operation cannot be undone. Prefer threads.trash instead.", - "parameters": { - "id": { - "type": "string", - "description": "ID of the Thread to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/" - ] - }, - "get": { - "id": "gmail.users.threads.get", - "path": "{userId}/threads/{id}", - "httpMethod": "GET", - "description": "Gets the specified thread.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the messages in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal" - ], - "enumDescriptions": [ - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the thread to retrieve.", - "required": true, - "location": "path" - }, - "metadataHeaders": { - "type": "string", - "description": "When given and format is METADATA, only include headers specified.", - "repeated": true, - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.threads.list", - "path": "{userId}/threads", - "httpMethod": "GET", - "description": "Lists the threads in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include threads from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "labelIds": { - "type": "string", - "description": "Only return threads with labels that match all of the specified label IDs.", - "repeated": true, - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of threads to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return threads matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\". Parameter cannot be used when accessing the api using the gmail.metadata scope.", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListThreadsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "modify": { - "id": "gmail.users.threads.modify", - "path": "{userId}/threads/{id}/modify", - "httpMethod": "POST", - "description": "Modifies the labels applied to the thread. This applies to all messages in the thread.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to modify.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "ModifyThreadRequest" - }, - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "trash": { - "id": "gmail.users.threads.trash", - "path": "{userId}/threads/{id}/trash", - "httpMethod": "POST", - "description": "Moves the specified thread to the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "untrash": { - "id": "gmail.users.threads.untrash", - "path": "{userId}/threads/{id}/untrash", - "httpMethod": "POST", - "description": "Removes the specified thread from the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to remove from Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - } - } - } - } - } -} -__END -} \ No newline at end of file diff --git a/t/04-client-mocked-agent.t b/t/04-client-mocked-agent.t deleted file mode 100644 index ea04d25..0000000 --- a/t/04-client-mocked-agent.t +++ /dev/null @@ -1,7110 +0,0 @@ -#!perl -T - -=head2 USAGE - -To run manually in the local directory assuming gapi.json present in source root and in xt/author/calendar directory - C - -NB: is also run as part of dzil test - -=cut - -use 5.006; -use strict; -use warnings; -use Test::More; -use Data::Dumper; ## remove this when finish tweaking -use Cwd; -use CHI; -use WebService::GoogleAPI::Client; -use Sub::Override; -use JSON; -use FindBin qw/$Bin/; -use Sub::Override; - - -my $dir = getcwd; -my $DEBUG = 1; ## to see noise of class debugging -my $warm_hash = {}; -#$warm_hash->{'https://www.googleapis.com/discovery/v1/apis'} = 'foo'; -#print Dumper $hash; - - -my $chi = CHI->new(driver => 'RawMemory', datastore => $warm_hash ); - -#$chi->set('https://www.googleapis.com/discovery/v1/apis' => from_json( pre_get_all_apis_json()) ); -#$chi->set('https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest' => from_json(pre_get_gmail_spec_json()) ); -use_ok( 'WebService::GoogleAPI::Client::Discovery' ); - -#my $client = WebService::GoogleAPI::Client::Discovery->new( ); - -ok( my $client = WebService::GoogleAPI::Client->new( gapi_json => "$Bin/gapi.json", chi=>$chi, debug=>$DEBUG ) ,'Create a new Client instance'); - -my $aref_token_emails = $client->auth_storage->storage->get_token_emails_from_storage; -my $user = $aref_token_emails->[0]; ## default to the first user -$client->user( $user ); - - ## INJECT HTTP RESPONSE FOR API DISCOVERY REQUEST - my $override = Sub::Override->new('Mojo::Transaction::res', sub { - my $res = Mojo::Message::Response->new ; - $res->code( 200 ); - $res->body( pre_get_all_apis_json() ); - return $res; - }); - - ok( my $all = $client->discover_all(), 'discover_all()' ); - - ## INJECT HTTP RESPONSE FOR GAMIL V1 API SPECIFICATION - my $override2 = Sub::Override->new('Mojo::Transaction::res', - sub { - my $res2 = Mojo::Message::Response->new ; - $res2->code( 200 ); - $res2->body( pre_get_gmail_spec_json() ); - return $res2; - }); - - - ok( my $gmail_api_spec = $client->methods_available_for_google_api_id('gmail', 'v1'), 'Get available methods for Gmail V1'); - - - - my $override3 = Sub::Override->new('Mojo::Transaction::res', - sub { - my $res2 = Mojo::Message::Response->new ; - $res2->code( 200 ); - $res2->body( '{ "status": "ok" }'); - return $res2; - }); - - - ok( $client->api_query( api_endpoint_id => 'gmail.users.messages.list' ), 'api_query - "gmail.users.messages.list"'); - ok ( $client->extract_method_discovery_detail_from_api_spec( 'gmail.users.messages.list', 'v1' ), 'extract_method_discovery_detail_from_api_spec'); - ok ( $client->ua->header_with_bearer_auth_token(), 'header_with_bearer_auth_token' ); - ok( my $cred = $client->ua->auth_storage->get_credentials_for_refresh( $user ), 'get credentials'); - ok( my $new_token = $client->ua->refresh_access_token( $cred ), 'refresh token' ); - ok( $client->debug(1), 'set debug'); - ok( $client->do_autorefresh(1), 'set debug'); - ok( $client->ua->debug(1), 'set debug'); - -#ok ( $client->available_APIs(), 'Get available APIs'); -#ok ( $client->supported_as_text(), 'Supported as text'); -#ok ( $client->available_versions('gmail'), 'Available versions for Gmail'); -#ok ( $client->latest_stable_version('gmail'), 'Latest stable version for Gmail'); -#ok( $client->api_verson_urls(), 'api version urls'); -ok( $client->methods_available_for_google_api_id('gmail'), 'Get end points available for gmail'); -ok( $client->list_of_available_google_api_ids(), 'All available Google API IDs'); -ok( $client->has_scope_to_access_api_endpoint('gmail.users.settings.sendAs.get'),'has GMail scope'); -note( ' CHI TYPE + ' . ref( $client->chi() ) ); -#note( my$y = $x->get('https://www.googleapis.com/discovery/v1/apis')); -#print Dumper $x; - -#use_ok( 'WebService::GoogleAPI::Client' ); # || print "Bail out!\n"; - - -#ok( ref( WebService::GoogleAPI::Client::Discovery->new->( chi => $chi )->discover_all() ) eq 'HASH', 'WebService::GoogleAPI::Client::Discovery->new->discover_all() return HASREF' ); - - - -done_testing(); - - -sub pre_get_all_apis_json -{ - return <<'_END' -{ - "kind": "discovery#directoryList", - "discoveryVersion": "v1", - "items": [ - { - "kind": "discovery#directoryItem", - "id": "abusiveexperiencereport:v1", - "name": "abusiveexperiencereport", - "version": "v1", - "title": "Abusive Experience Report API", - "description": "Views Abusive Experience Report data, and gets a list of sites that have a significant number of abusive experiences.", - "discoveryRestUrl": "https://abusiveexperiencereport.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/abusive-experience-report/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "acceleratedmobilepageurl:v1", - "name": "acceleratedmobilepageurl", - "version": "v1", - "title": "Accelerated Mobile Pages (AMP) URL API", - "description": "This API contains a single method, batchGet. Call this method to retrieve the AMP URL (and equivalent AMP Cache URL) for given public URL(s).", - "discoveryRestUrl": "https://acceleratedmobilepageurl.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/amp/cache/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "accesscontextmanager:v1beta", - "name": "accesscontextmanager", - "version": "v1beta", - "title": "Access Context Manager API", - "description": "An API for setting attribute based access control to requests to GCP services.", - "discoveryRestUrl": "https://accesscontextmanager.googleapis.com/$clientovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/access-context-manager/docs/reference/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.2", - "name": "adexchangebuyer", - "version": "v1.2", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.2/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.3", - "name": "adexchangebuyer", - "version": "v1.3", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.3/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer:v1.4", - "name": "adexchangebuyer", - "version": "v1.4", - "title": "Ad Exchange Buyer API", - "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.4/rest", - "discoveryLink": "./apis/adexchangebuyer/v1.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexchangebuyer2:v2beta1", - "name": "adexchangebuyer2", - "version": "v2beta1", - "title": "Ad Exchange Buyer API II", - "description": "Accesses the latest features for managing Ad Exchange accounts, Real-Time Bidding configurations and auction metrics, and Marketplace programmatic deals.", - "discoveryRestUrl": "https://adexchangebuyer.googleapis.com/$clientovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest/reference/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adexperiencereport:v1", - "name": "adexperiencereport", - "version": "v1", - "title": "Ad Experience Report API", - "description": "Views Ad Experience Report data, and gets a list of sites that have a significant number of annoying ads.", - "discoveryRestUrl": "https://adexperiencereport.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/ad-experience-report/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "admin:datatransfer_v1", - "name": "admin", - "version": "datatransfer_v1", - "title": "Admin Data Transfer API", - "description": "Transfers user data from one user to another.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/datatransfer_v1/rest", - "discoveryLink": "./apis/admin/datatransfer_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/data-transfer/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "admin:directory_v1", - "name": "admin", - "version": "directory_v1", - "title": "Admin Directory API", - "description": "Manages enterprise resources such as users and groups, administrative notifications, security features, and more.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/directory_v1/rest", - "discoveryLink": "./apis/admin/directory_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/directory/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "admin:reports_v1", - "name": "admin", - "version": "reports_v1", - "title": "Admin Reports API", - "description": "Fetches reports for the administrators of G Suite customers about the usage, collaboration, security, and risk for their users.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/reports_v1/rest", - "discoveryLink": "./apis/admin/reports_v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/reports/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adsense:v1.4", - "name": "adsense", - "version": "v1.4", - "title": "AdSense Management API", - "description": "Accesses AdSense publishers' inventory and generates performance reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsense/v1.4/rest", - "discoveryLink": "./apis/adsense/v1.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/adsense-16.png", - "x32": "https://www.google.com/images/icons/product/adsense-32.png" - }, - "documentationLink": "https://developers.google.com/adsense/management/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "adsensehost:v4.1", - "name": "adsensehost", - "version": "v4.1", - "title": "AdSense Host API", - "description": "Generates performance reports, generates ad codes, and provides publisher management capabilities for AdSense Hosts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsensehost/v4.1/rest", - "discoveryLink": "./apis/adsensehost/v4.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/adsense-16.png", - "x32": "https://www.google.com/images/icons/product/adsense-32.png" - }, - "documentationLink": "https://developers.google.com/adsense/host/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "alertcenter:v1beta1", - "name": "alertcenter", - "version": "v1beta1", - "title": "G Suite Alert Center API", - "description": "G Suite Alert Center API to view and manage alerts on issues affecting your domain.", - "discoveryRestUrl": "https://alertcenter.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/admin-sdk/alertcenter/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "analytics:v2.4", - "name": "analytics", - "version": "v2.4", - "title": "Google Analytics API", - "description": "Views and manages your Google Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v2.4/rest", - "discoveryLink": "./apis/analytics/v2.4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/analytics-16.png", - "x32": "https://www.google.com/images/icons/product/analytics-32.png" - }, - "documentationLink": "https://developers.google.com/analytics/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "analytics:v3", - "name": "analytics", - "version": "v3", - "title": "Google Analytics API", - "description": "Views and manages your Google Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v3/rest", - "discoveryLink": "./apis/analytics/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/analytics-16.png", - "x32": "https://www.google.com/images/icons/product/analytics-32.png" - }, - "documentationLink": "https://developers.google.com/analytics/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "analyticsreporting:v4", - "name": "analyticsreporting", - "version": "v4", - "title": "Google Analytics Reporting API", - "description": "Accesses Analytics report data.", - "discoveryRestUrl": "https://analyticsreporting.googleapis.com/$clientovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/analytics/devguides/reporting/core/v4/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androiddeviceprovisioning:v1", - "name": "androiddeviceprovisioning", - "version": "v1", - "title": "Android Device Provisioning Partner API", - "description": "Automates Android zero-touch enrollment for device resellers, customers, and EMMs.", - "discoveryRestUrl": "https://androiddeviceprovisioning.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/zero-touch/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidenterprise:v1", - "name": "androidenterprise", - "version": "v1", - "title": "Google Play EMM API", - "description": "Manages the deployment of apps to Android for Work users.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidenterprise/v1/rest", - "discoveryLink": "./apis/androidenterprise/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android/work/play/emm-api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidmanagement:v1", - "name": "androidmanagement", - "version": "v1", - "title": "Android Management API", - "description": "The Android Management API provides remote enterprise management of Android devices and apps.", - "discoveryRestUrl": "https://androidmanagement.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/android/management", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v1", - "name": "androidpublisher", - "version": "v1", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1/rest", - "discoveryLink": "./apis/androidpublisher/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v1.1", - "name": "androidpublisher", - "version": "v1.1", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1.1/rest", - "discoveryLink": "./apis/androidpublisher/v1.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v2", - "name": "androidpublisher", - "version": "v2", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v2/rest", - "discoveryLink": "./apis/androidpublisher/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "androidpublisher:v3", - "name": "androidpublisher", - "version": "v3", - "title": "Google Play Developer API", - "description": "Accesses Android application developers' Google Play accounts.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v3/rest", - "discoveryLink": "./apis/androidpublisher/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/android-16.png", - "x32": "https://www.google.com/images/icons/product/android-32.png" - }, - "documentationLink": "https://developers.google.com/android-publisher", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1alpha", - "name": "appengine", - "version": "v1alpha", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$clientovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta", - "name": "appengine", - "version": "v1beta", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$clientovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1", - "name": "appengine", - "version": "v1", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta4", - "name": "appengine", - "version": "v1beta4", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$clientovery/rest?version=v1beta4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appengine:v1beta5", - "name": "appengine", - "version": "v1beta5", - "title": "App Engine Admin API", - "description": "Provisions and manages developers' App Engine applications.", - "discoveryRestUrl": "https://appengine.googleapis.com/$clientovery/rest?version=v1beta5", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "appsactivity:v1", - "name": "appsactivity", - "version": "v1", - "title": "Drive Activity API", - "description": "Provides a historical view of activity.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appsactivity/v1/rest", - "discoveryLink": "./apis/appsactivity/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/activity/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "appstate:v1", - "name": "appstate", - "version": "v1", - "title": "Google App State API", - "description": "The Google App State API.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appstate/v1/rest", - "discoveryLink": "./apis/appstate/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services/web/api/states", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "bigquery:v2", - "name": "bigquery", - "version": "v2", - "title": "BigQuery API", - "description": "A data platform for customers to create, manage, share and query data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest", - "discoveryLink": "./apis/bigquery/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/search-16.gif", - "x32": "https://www.google.com/images/icons/product/search-32.gif" - }, - "documentationLink": "https://cloud.google.com/bigquery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "bigquerydatatransfer:v1", - "name": "bigquerydatatransfer", - "version": "v1", - "title": "BigQuery Data Transfer API", - "description": "Transfers data from partner SaaS applications to Google BigQuery on a scheduled, managed basis.", - "discoveryRestUrl": "https://bigquerydatatransfer.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/bigquery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "binaryauthorization:v1beta1", - "name": "binaryauthorization", - "version": "v1beta1", - "title": "Binary Authorization API", - "description": "The management interface for Binary Authorization, a system providing policy control for images deployed to Kubernetes Engine clusters.", - "discoveryRestUrl": "https://binaryauthorization.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/binary-authorization/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "blogger:v2", - "name": "blogger", - "version": "v2", - "title": "Blogger API", - "description": "API for access to the data within Blogger.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v2/rest", - "discoveryLink": "./apis/blogger/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/blogger-16.png", - "x32": "https://www.google.com/images/icons/product/blogger-32.png" - }, - "documentationLink": "https://developers.google.com/blogger/docs/2.0/json/getting_started", - "labels": [ - "limited_availability" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "blogger:v3", - "name": "blogger", - "version": "v3", - "title": "Blogger API", - "description": "API for access to the data within Blogger.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest", - "discoveryLink": "./apis/blogger/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/blogger-16.png", - "x32": "https://www.google.com/images/icons/product/blogger-32.png" - }, - "documentationLink": "https://developers.google.com/blogger/docs/3.0/getting_started", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "books:v1", - "name": "books", - "version": "v1", - "title": "Books API", - "description": "Searches for books and manages your Google Books library.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/books/v1/rest", - "discoveryLink": "./apis/books/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/ebooks-16.png", - "x32": "https://www.google.com/images/icons/product/ebooks-32.png" - }, - "documentationLink": "https://developers.google.com/books/docs/v1/getting_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "calendar:v3", - "name": "calendar", - "version": "v3", - "title": "Calendar API", - "description": "Manipulates events and other calendar data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest", - "discoveryLink": "./apis/calendar/v3/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/calendar-16.png", - "x32": "http://www.google.com/images/icons/product/calendar-32.png" - }, - "documentationLink": "https://developers.google.com/google-apps/calendar/firstapp", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "chat:v1", - "name": "chat", - "version": "v1", - "title": "Hangouts Chat API", - "description": "Create bots and extend the new Hangouts Chat.", - "discoveryRestUrl": "https://chat.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/hangouts/chat", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "civicinfo:v2", - "name": "civicinfo", - "version": "v2", - "title": "Google Civic Information API", - "description": "Provides polling places, early vote locations, contest data, election officials, and government representatives for U.S. residential addresses.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/civicinfo/v2/rest", - "discoveryLink": "./apis/civicinfo/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/civic-information", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "classroom:v1", - "name": "classroom", - "version": "v1", - "title": "Google Classroom API", - "description": "Manages classes, rosters, and invitations in Google Classroom.", - "discoveryRestUrl": "https://classroom.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/classroom", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudasset:v1beta1", - "name": "cloudasset", - "version": "v1beta1", - "title": "Cloud Asset API", - "description": "The cloud asset API manages the history and inventory of cloud resources.", - "discoveryRestUrl": "https://cloudasset.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://console.cloud.google.com/apis/api/cloudasset.googleapis.com/overview", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbilling:v1", - "name": "cloudbilling", - "version": "v1", - "title": "Cloud Billing API", - "description": "Allows developers to manage billing for their Google Cloud Platform projects programmatically.", - "discoveryRestUrl": "https://cloudbilling.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/billing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbuild:v1alpha1", - "name": "cloudbuild", - "version": "v1alpha1", - "title": "Cloud Build API", - "description": "Creates and manages builds on Google Cloud Platform.", - "discoveryRestUrl": "https://cloudbuild.googleapis.com/$clientovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/cloud-build/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudbuild:v1", - "name": "cloudbuild", - "version": "v1", - "title": "Cloud Build API", - "description": "Creates and manages builds on Google Cloud Platform.", - "discoveryRestUrl": "https://cloudbuild.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/cloud-build/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "clouddebugger:v2", - "name": "clouddebugger", - "version": "v2", - "title": "Stackdriver Debugger API", - "description": "Examines the call stack and variables of a running application without stopping or slowing it down.", - "discoveryRestUrl": "https://clouddebugger.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/debugger", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "clouderrorreporting:v1beta1", - "name": "clouderrorreporting", - "version": "v1beta1", - "title": "Stackdriver Error Reporting API", - "description": "Groups and counts similar errors from cloud services and applications, reports new errors, and provides access to error groups and their associated errors.", - "discoveryRestUrl": "https://clouderrorreporting.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/error-reporting/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudfunctions:v1", - "name": "cloudfunctions", - "version": "v1", - "title": "Cloud Functions API", - "description": "Manages lightweight user-provided functions executed in response to events.", - "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/functions", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudfunctions:v1beta2", - "name": "cloudfunctions", - "version": "v1beta2", - "title": "Cloud Functions API", - "description": "Manages lightweight user-provided functions executed in response to events.", - "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/functions", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudiot:v1", - "name": "cloudiot", - "version": "v1", - "title": "Cloud IoT API", - "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", - "discoveryRestUrl": "https://cloudiot.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iot", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudiot:v1beta1", - "name": "cloudiot", - "version": "v1beta1", - "title": "Cloud IoT API", - "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", - "discoveryRestUrl": "https://cloudiot.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iot", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudkms:v1", - "name": "cloudkms", - "version": "v1", - "title": "Cloud Key Management Service (KMS) API", - "description": "Manages keys and performs cryptographic operations in a central cloud service, for direct use by other cloud resources and applications.", - "discoveryRestUrl": "https://cloudkms.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kms/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudprofiler:v2", - "name": "cloudprofiler", - "version": "v2", - "title": "Stackdriver Profiler API", - "description": "Manages continuous profiling information.", - "discoveryRestUrl": "https://cloudprofiler.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/profiler/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v1", - "name": "cloudresourcemanager", - "version": "v1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v1beta1", - "name": "cloudresourcemanager", - "version": "v1beta1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v2", - "name": "cloudresourcemanager", - "version": "v2", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudresourcemanager:v2beta1", - "name": "cloudresourcemanager", - "version": "v2beta1", - "title": "Cloud Resource Manager API", - "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", - "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$clientovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/resource-manager", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudshell:v1alpha1", - "name": "cloudshell", - "version": "v1alpha1", - "title": "Cloud Shell API", - "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", - "discoveryRestUrl": "https://cloudshell.googleapis.com/$clientovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/shell/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudshell:v1", - "name": "cloudshell", - "version": "v1", - "title": "Cloud Shell API", - "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", - "discoveryRestUrl": "https://cloudshell.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/shell/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtasks:v2beta2", - "name": "cloudtasks", - "version": "v2beta2", - "title": "Cloud Tasks API", - "description": "Manages the execution of large numbers of distributed requests.", - "discoveryRestUrl": "https://cloudtasks.googleapis.com/$clientovery/rest?version=v2beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tasks/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtasks:v2beta3", - "name": "cloudtasks", - "version": "v2beta3", - "title": "Cloud Tasks API", - "description": "Manages the execution of large numbers of distributed requests.", - "discoveryRestUrl": "https://cloudtasks.googleapis.com/$clientovery/rest?version=v2beta3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tasks/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v2alpha1", - "name": "cloudtrace", - "version": "v2alpha1", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$clientovery/rest?version=v2alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v1", - "name": "cloudtrace", - "version": "v1", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "cloudtrace:v2", - "name": "cloudtrace", - "version": "v2", - "title": "Stackdriver Trace API", - "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API. This library is used to interact with the Trace API directly. If you are looking to instrument your application for Stackdriver Trace, we recommend using OpenCensus.", - "discoveryRestUrl": "https://cloudtrace.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/trace", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "composer:v1", - "name": "composer", - "version": "v1", - "title": "Cloud Composer API", - "description": "Manages Apache Airflow environments on Google Cloud Platform.", - "discoveryRestUrl": "https://composer.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/composer/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "composer:v1beta1", - "name": "composer", - "version": "v1beta1", - "title": "Cloud Composer API", - "description": "Manages Apache Airflow environments on Google Cloud Platform.", - "discoveryRestUrl": "https://composer.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/composer/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:alpha", - "name": "compute", - "version": "alpha", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/alpha/rest", - "discoveryLink": "./apis/compute/alpha/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:beta", - "name": "compute", - "version": "beta", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/beta/rest", - "discoveryLink": "./apis/compute/beta/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "compute:v1", - "name": "compute", - "version": "v1", - "title": "Compute Engine API", - "description": "Creates and runs virtual machines on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest", - "discoveryLink": "./apis/compute/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", - "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "container:v1", - "name": "container", - "version": "v1", - "title": "Kubernetes Engine API", - "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", - "discoveryRestUrl": "https://container.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/container-engine/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "container:v1beta1", - "name": "container", - "version": "v1beta1", - "title": "Kubernetes Engine API", - "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", - "discoveryRestUrl": "https://container.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/container-engine/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "content:v2", - "name": "content", - "version": "v2", - "title": "Content API for Shopping", - "description": "Manages product items, inventory, and Merchant Center accounts for Google Shopping.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/content/v2/rest", - "discoveryLink": "./apis/content/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/shopping-content", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "customsearch:v1", - "name": "customsearch", - "version": "v1", - "title": "CustomSearch API", - "description": "Searches over a website or collection of websites", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/customsearch/v1/rest", - "discoveryLink": "./apis/customsearch/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/custom-search/v1/using_rest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataflow:v1b3", - "name": "dataflow", - "version": "v1b3", - "title": "Dataflow API", - "description": "Manages Google Cloud Dataflow projects on Google Cloud Platform.", - "discoveryRestUrl": "https://dataflow.googleapis.com/$clientovery/rest?version=v1b3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataflow", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataproc:v1", - "name": "dataproc", - "version": "v1", - "title": "Cloud Dataproc API", - "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", - "discoveryRestUrl": "https://dataproc.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataproc/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dataproc:v1beta2", - "name": "dataproc", - "version": "v1beta2", - "title": "Cloud Dataproc API", - "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", - "discoveryRestUrl": "https://dataproc.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dataproc/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1", - "name": "datastore", - "version": "v1", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1beta1", - "name": "datastore", - "version": "v1beta1", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "datastore:v1beta3", - "name": "datastore", - "version": "v1beta3", - "title": "Cloud Datastore API", - "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", - "discoveryRestUrl": "https://datastore.googleapis.com/$clientovery/rest?version=v1beta3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/datastore/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:alpha", - "name": "deploymentmanager", - "version": "alpha", - "title": "Google Cloud Deployment Manager Alpha API", - "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/alpha/rest", - "discoveryLink": "./apis/deploymentmanager/alpha/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:v2beta", - "name": "deploymentmanager", - "version": "v2beta", - "title": "Google Cloud Deployment Manager API V2Beta Methods", - "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2beta/rest", - "discoveryLink": "./apis/deploymentmanager/v2beta/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/deployment-manager/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "deploymentmanager:v2", - "name": "deploymentmanager", - "version": "v2", - "title": "Google Cloud Deployment Manager API", - "description": "Declares, configures, and deploys complex solutions on Google Cloud Platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2/rest", - "discoveryLink": "./apis/deploymentmanager/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v2.8", - "name": "dfareporting", - "version": "v2.8", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v2.8/rest", - "discoveryLink": "./apis/dfareporting/v2.8/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.0", - "name": "dfareporting", - "version": "v3.0", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.0/rest", - "discoveryLink": "./apis/dfareporting/v3.0/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.1", - "name": "dfareporting", - "version": "v3.1", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.1/rest", - "discoveryLink": "./apis/dfareporting/v3.1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dfareporting:v3.2", - "name": "dfareporting", - "version": "v3.2", - "title": "DCM/DFA Reporting And Trafficking API", - "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.2/rest", - "discoveryLink": "./apis/dfareporting/v3.2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", - "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" - }, - "documentationLink": "https://developers.google.com/doubleclick-advertisers/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dialogflow:v2", - "name": "dialogflow", - "version": "v2", - "title": "Dialogflow API", - "description": "Builds conversational interfaces (for example, chatbots, and voice-powered apps and devices).", - "discoveryRestUrl": "https://dialogflow.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dialogflow:v2beta1", - "name": "dialogflow", - "version": "v2beta1", - "title": "Dialogflow API", - "description": "Builds conversational interfaces (for example, chatbots, and voice-powered apps and devices).", - "discoveryRestUrl": "https://dialogflow.googleapis.com/$clientovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "digitalassetlinks:v1", - "name": "digitalassetlinks", - "version": "v1", - "title": "Digital Asset Links API", - "description": "Discovers relationships between online assets such as websites or mobile apps.", - "discoveryRestUrl": "https://digitalassetlinks.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/digital-asset-links/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "discovery:v1", - "name": "discovery", - "version": "v1", - "title": "APIs Discovery Service", - "description": "Provides information about other Google APIs, such as what APIs are available, the resource, and method details for each API.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/discovery/v1/rest", - "discoveryLink": "./apis/discovery/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/feature/filing_cabinet_search-g16.png", - "x32": "http://www.google.com/images/icons/feature/filing_cabinet_search-g32.png" - }, - "documentationLink": "https://developers.google.com/discovery/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dlp:v2", - "name": "dlp", - "version": "v2", - "title": "Cloud Data Loss Prevention (DLP) API", - "description": "Provides methods for detection, risk analysis, and de-identification of privacy-sensitive fragments in text, images, and Google Cloud Platform storage repositories.", - "discoveryRestUrl": "https://dlp.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/dlp/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v1", - "name": "dns", - "version": "v1", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1/rest", - "discoveryLink": "./apis/dns/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v1beta2", - "name": "dns", - "version": "v1beta2", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1beta2/rest", - "discoveryLink": "./apis/dns/v1beta2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "dns:v2beta1", - "name": "dns", - "version": "v2beta1", - "title": "Google Cloud DNS API", - "description": "Configures and serves authoritative DNS records.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v2beta1/rest", - "discoveryLink": "./apis/dns/v2beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-dns", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "doubleclickbidmanager:v1", - "name": "doubleclickbidmanager", - "version": "v1", - "title": "DoubleClick Bid Manager API", - "description": "API for viewing and managing your reports in DoubleClick Bid Manager.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclickbidmanager/v1/rest", - "discoveryLink": "./apis/doubleclickbidmanager/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/bid-manager/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "doubleclicksearch:v2", - "name": "doubleclicksearch", - "version": "v2", - "title": "DoubleClick Search API", - "description": "Reports and modifies your advertising data in DoubleClick Search (for example, campaigns, ad groups, keywords, and conversions).", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclicksearch/v2/rest", - "discoveryLink": "./apis/doubleclicksearch/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/doubleclick-search/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "drive:v2", - "name": "drive", - "version": "v2", - "title": "Drive API", - "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v2/rest", - "discoveryLink": "./apis/drive/v2/rest", - "icons": { - "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", - "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" - }, - "documentationLink": "https://developers.google.com/drive/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "drive:v3", - "name": "drive", - "version": "v3", - "title": "Drive API", - "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", - "discoveryLink": "./apis/drive/v3/rest", - "icons": { - "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", - "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" - }, - "documentationLink": "https://developers.google.com/drive/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "file:v1beta1", - "name": "file", - "version": "v1beta1", - "title": "Cloud Filestore API", - "description": "The Cloud Filestore API is used for creating and managing cloud file servers.", - "discoveryRestUrl": "https://file.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/filestore/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebasedynamiclinks:v1", - "name": "firebasedynamiclinks", - "version": "v1", - "title": "Firebase Dynamic Links API", - "description": "Programmatically creates and manages Firebase Dynamic Links.", - "discoveryRestUrl": "https://firebasedynamiclinks.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/dynamic-links/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebasehosting:v1beta1", - "name": "firebasehosting", - "version": "v1beta1", - "title": "Firebase Hosting API", - "description": "", - "discoveryRestUrl": "https://firebasehosting.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/hosting/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firebaserules:v1", - "name": "firebaserules", - "version": "v1", - "title": "Firebase Rules API", - "description": "Creates and manages rules that determine when a Firebase Rules-enabled service should permit a request.", - "discoveryRestUrl": "https://firebaserules.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/storage/security", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1", - "name": "firestore", - "version": "v1", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1beta1", - "name": "firestore", - "version": "v1beta1", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "firestore:v1beta2", - "name": "firestore", - "version": "v1beta2", - "title": "Cloud Firestore API", - "description": "Accesses the NoSQL document database built for automatic scaling, high performance, and ease of application development.", - "discoveryRestUrl": "https://firestore.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/firestore", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "fitness:v1", - "name": "fitness", - "version": "v1", - "title": "Fitness", - "description": "Stores and accesses user data in the fitness store from apps on any platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fitness/v1/rest", - "discoveryLink": "./apis/fitness/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fit/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "fusiontables:v1", - "name": "fusiontables", - "version": "v1", - "title": "Fusion Tables API", - "description": "API for working with Fusion Tables data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v1/rest", - "discoveryLink": "./apis/fusiontables/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fusiontables", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "fusiontables:v2", - "name": "fusiontables", - "version": "v2", - "title": "Fusion Tables API", - "description": "API for working with Fusion Tables data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v2/rest", - "discoveryLink": "./apis/fusiontables/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/fusiontables", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "games:v1", - "name": "games", - "version": "v1", - "title": "Google Play Game Services API", - "description": "The API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/games/v1/rest", - "discoveryLink": "./apis/games/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gamesConfiguration:v1configuration", - "name": "gamesConfiguration", - "version": "v1configuration", - "title": "Google Play Game Services Publishing API", - "description": "The Publishing API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesConfiguration/v1configuration/rest", - "discoveryLink": "./apis/gamesConfiguration/v1configuration/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gamesManagement:v1management", - "name": "gamesManagement", - "version": "v1management", - "title": "Google Play Game Services Management API", - "description": "The Management API for Google Play Game Services.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesManagement/v1management/rest", - "discoveryLink": "./apis/gamesManagement/v1management/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/games/services", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v1alpha2", - "name": "genomics", - "version": "v1alpha2", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$clientovery/rest?version=v1alpha2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v2alpha1", - "name": "genomics", - "version": "v2alpha1", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$clientovery/rest?version=v2alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "genomics:v1", - "name": "genomics", - "version": "v1", - "title": "Genomics API", - "description": "Uploads, processes, queries, and searches Genomics data in the cloud.", - "discoveryRestUrl": "https://genomics.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/genomics", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "gmail:v1", - "name": "gmail", - "version": "v1", - "title": "Gmail API", - "description": "Access Gmail mailboxes including sending user email.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest", - "discoveryLink": "./apis/gmail/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/googlemail-16.png", - "x32": "https://www.google.com/images/icons/product/googlemail-32.png" - }, - "documentationLink": "https://developers.google.com/gmail/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "groupsmigration:v1", - "name": "groupsmigration", - "version": "v1", - "title": "Groups Migration API", - "description": "Groups Migration Api.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupsmigration/v1/rest", - "discoveryLink": "./apis/groupsmigration/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/discussions-16.gif", - "x32": "https://www.google.com/images/icons/product/discussions-32.gif" - }, - "documentationLink": "https://developers.google.com/google-apps/groups-migration/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "groupssettings:v1", - "name": "groupssettings", - "version": "v1", - "title": "Groups Settings API", - "description": "Lets you manage permission levels and related settings of a group.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupssettings/v1/rest", - "discoveryLink": "./apis/groupssettings/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/groups-settings/get_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iam:v1", - "name": "iam", - "version": "v1", - "title": "Identity and Access Management (IAM) API", - "description": "Manages identity and access control for Google Cloud Platform resources, including the creation of service accounts, which you can use to authenticate to Google and make API calls.", - "discoveryRestUrl": "https://iam.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iam/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iamcredentials:v1", - "name": "iamcredentials", - "version": "v1", - "title": "IAM Service Account Credentials API", - "description": "Creates short-lived, limited-privilege credentials for IAM service accounts.", - "discoveryRestUrl": "https://iamcredentials.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "iap:v1beta1", - "name": "iap", - "version": "v1beta1", - "title": "Cloud Identity-Aware Proxy API", - "description": "Controls access to cloud applications running on Google Cloud Platform.", - "discoveryRestUrl": "https://iap.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/iap", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "identitytoolkit:v3", - "name": "identitytoolkit", - "version": "v3", - "title": "Google Identity Toolkit API", - "description": "Help the third party sites to implement federated login.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/identitytoolkit/v3/rest", - "discoveryLink": "./apis/identitytoolkit/v3/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/identity-toolkit/v3/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "indexing:v3", - "name": "indexing", - "version": "v3", - "title": "Indexing API", - "description": "Notifies Google when your web pages change.", - "discoveryRestUrl": "https://indexing.googleapis.com/$clientovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/search/apis/indexing-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v3p1beta1", - "name": "jobs", - "version": "v3p1beta1", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$clientovery/rest?version=v3p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v2", - "name": "jobs", - "version": "v2", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "jobs:v3", - "name": "jobs", - "version": "v3", - "title": "Cloud Talent Solution API", - "description": "Cloud Talent Solution provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", - "discoveryRestUrl": "https://jobs.googleapis.com/$clientovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/talent-solution/job-search/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "kgsearch:v1", - "name": "kgsearch", - "version": "v1", - "title": "Knowledge Graph Search API", - "description": "Searches the Google Knowledge Graph for entities.", - "discoveryRestUrl": "https://kgsearch.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/knowledge-graph/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1", - "name": "language", - "version": "v1", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1beta1", - "name": "language", - "version": "v1beta1", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "language:v1beta2", - "name": "language", - "version": "v1beta2", - "title": "Cloud Natural Language API", - "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", - "discoveryRestUrl": "https://language.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/natural-language/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "licensing:v1", - "name": "licensing", - "version": "v1", - "title": "Enterprise License Manager API", - "description": "Views and manages licenses for your domain.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/licensing/v1/rest", - "discoveryLink": "./apis/licensing/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/licensing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "logging:v2", - "name": "logging", - "version": "v2", - "title": "Stackdriver Logging API", - "description": "Writes log entries and manages your Logging configuration.", - "discoveryRestUrl": "https://logging.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/logging/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "logging:v2beta1", - "name": "logging", - "version": "v2beta1", - "title": "Stackdriver Logging API", - "description": "Writes log entries and manages your Logging configuration.", - "discoveryRestUrl": "https://logging.googleapis.com/$clientovery/rest?version=v2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/logging/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "manufacturers:v1", - "name": "manufacturers", - "version": "v1", - "title": "Manufacturer Center API", - "description": "Public API for managing Manufacturer Center related data.", - "discoveryRestUrl": "https://manufacturers.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/manufacturers/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "mirror:v1", - "name": "mirror", - "version": "v1", - "title": "Google Mirror API", - "description": "Interacts with Glass users via the timeline.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/mirror/v1/rest", - "discoveryLink": "./apis/mirror/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/glass", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "ml:v1", - "name": "ml", - "version": "v1", - "title": "Cloud Machine Learning Engine", - "description": "An API to enable creating and using machine learning models.", - "discoveryRestUrl": "https://ml.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/ml/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "monitoring:v3", - "name": "monitoring", - "version": "v3", - "title": "Stackdriver Monitoring API", - "description": "Manages your Stackdriver Monitoring data and configurations. Most projects must be associated with a Stackdriver account, with a few exceptions as noted on the individual method pages.", - "discoveryRestUrl": "https://monitoring.googleapis.com/$clientovery/rest?version=v3", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/monitoring/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "oauth2:v1", - "name": "oauth2", - "version": "v1", - "title": "Google OAuth2 API", - "description": "Obtains end-user authorization grants for use with other Google APIs.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v1/rest", - "discoveryLink": "./apis/oauth2/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oauth2:v2", - "name": "oauth2", - "version": "v2", - "title": "Google OAuth2 API", - "description": "Obtains end-user authorization grants for use with other Google APIs.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v2/rest", - "discoveryLink": "./apis/oauth2/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1alpha", - "name": "oslogin", - "version": "v1alpha", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$clientovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1beta", - "name": "oslogin", - "version": "v1beta", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$clientovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "oslogin:v1", - "name": "oslogin", - "version": "v1", - "title": "Cloud OS Login API", - "description": "Manages OS login configuration for Google account users.", - "discoveryRestUrl": "https://oslogin.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v1", - "name": "pagespeedonline", - "version": "v1", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v1/rest", - "discoveryLink": "./apis/pagespeedonline/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v1/getting_started", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v2", - "name": "pagespeedonline", - "version": "v2", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v2/rest", - "discoveryLink": "./apis/pagespeedonline/v2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v2/getting-started", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pagespeedonline:v4", - "name": "pagespeedonline", - "version": "v4", - "title": "PageSpeed Insights API", - "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v4/rest", - "discoveryLink": "./apis/pagespeedonline/v4/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", - "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" - }, - "documentationLink": "https://developers.google.com/speed/docs/insights/v4/getting-started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "partners:v2", - "name": "partners", - "version": "v2", - "title": "Google Partners API", - "description": "Searches certified companies and creates contact leads with them, and also audits the usage of clients.", - "discoveryRestUrl": "https://partners.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/partners/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "people:v1", - "name": "people", - "version": "v1", - "title": "People API", - "description": "Provides access to information about profiles and contacts.", - "discoveryRestUrl": "https://people.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/people/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "playcustomapp:v1", - "name": "playcustomapp", - "version": "v1", - "title": "Google Play Custom App Publishing API", - "description": "An API to publish custom Android apps.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/playcustomapp/v1/rest", - "discoveryLink": "./apis/playcustomapp/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/android/work/play/custom-app-api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "plus:v1", - "name": "plus", - "version": "v1", - "title": "Google+ API", - "description": "Builds on top of the Google+ platform.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plus/v1/rest", - "discoveryLink": "./apis/plus/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/gplus-16.png", - "x32": "http://www.google.com/images/icons/product/gplus-32.png" - }, - "documentationLink": "https://developers.google.com/+/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "plusDomains:v1", - "name": "plusDomains", - "version": "v1", - "title": "Google+ Domains API", - "description": "Builds on top of the Google+ platform for Google Apps Domains.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plusDomains/v1/rest", - "discoveryLink": "./apis/plusDomains/v1/rest", - "icons": { - "x16": "http://www.google.com/images/icons/product/gplus-16.png", - "x32": "http://www.google.com/images/icons/product/gplus-32.png" - }, - "documentationLink": "https://developers.google.com/+/domains/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "poly:v1", - "name": "poly", - "version": "v1", - "title": "Poly API", - "description": "The Poly API provides read access to assets hosted on poly.google.com to all, and upload access to poly.google.com for whitelisted accounts.", - "discoveryRestUrl": "https://poly.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/poly/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "proximitybeacon:v1beta1", - "name": "proximitybeacon", - "version": "v1beta1", - "title": "Proximity Beacon API", - "description": "Registers, manages, indexes, and searches beacons.", - "discoveryRestUrl": "https://proximitybeacon.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/beacons/proximity/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1beta1a", - "name": "pubsub", - "version": "v1beta1a", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$clientovery/rest?version=v1beta1a", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1", - "name": "pubsub", - "version": "v1", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "pubsub:v1beta2", - "name": "pubsub", - "version": "v1beta2", - "title": "Cloud Pub/Sub API", - "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", - "discoveryRestUrl": "https://pubsub.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/pubsub/docs", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "redis:v1", - "name": "redis", - "version": "v1", - "title": "Google Cloud Memorystore for Redis API", - "description": "The Google Cloud Memorystore for Redis API is used for creating and managing Redis instances on the Google Cloud Platform.", - "discoveryRestUrl": "https://redis.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/memorystore/docs/redis/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "redis:v1beta1", - "name": "redis", - "version": "v1beta1", - "title": "Google Cloud Memorystore for Redis API", - "description": "The Google Cloud Memorystore for Redis API is used for creating and managing Redis instances on the Google Cloud Platform.", - "discoveryRestUrl": "https://redis.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/memorystore/docs/redis/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "replicapool:v1beta1", - "name": "replicapool", - "version": "v1beta1", - "title": "Replica Pool API", - "description": "The Replica Pool API allows users to declaratively provision and manage groups of Google Compute Engine instances based on a common template.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapool/v1beta1/rest", - "discoveryLink": "./apis/replicapool/v1beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/compute/docs/replica-pool/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "replicapoolupdater:v1beta1", - "name": "replicapoolupdater", - "version": "v1beta1", - "title": "Google Compute Engine Instance Group Updater API", - "description": "[Deprecated. Please use compute.instanceGroupManagers.update method. replicapoolupdater API will be disabled after December 30th, 2016] Updates groups of Compute Engine instances.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapoolupdater/v1beta1/rest", - "discoveryLink": "./apis/replicapoolupdater/v1beta1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/compute/docs/instance-groups/manager/#applying_rolling_updates_using_the_updater_service", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "reseller:v1", - "name": "reseller", - "version": "v1", - "title": "Enterprise Apps Reseller API", - "description": "Creates and manages your customers and their subscriptions.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/reseller/v1/rest", - "discoveryLink": "./apis/reseller/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/google-apps/reseller/", - "labels": [ - "limited_availability" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "runtimeconfig:v1", - "name": "runtimeconfig", - "version": "v1", - "title": "Cloud Runtime Configuration API", - "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", - "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "runtimeconfig:v1beta1", - "name": "runtimeconfig", - "version": "v1beta1", - "title": "Cloud Runtime Configuration API", - "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", - "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "safebrowsing:v4", - "name": "safebrowsing", - "version": "v4", - "title": "Safe Browsing API", - "description": "Enables client applications to check web resources (most commonly URLs) against Google-generated lists of unsafe web resources.", - "discoveryRestUrl": "https://safebrowsing.googleapis.com/$clientovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/safe-browsing/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "script:v1", - "name": "script", - "version": "v1", - "title": "Apps Script API", - "description": "Manages and executes Google Apps Script projects.", - "discoveryRestUrl": "https://script.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/apps-script/api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "searchconsole:v1", - "name": "searchconsole", - "version": "v1", - "title": "Google Search Console URL Testing Tools API", - "description": "Provides tools for running validation tests against single URLs", - "discoveryRestUrl": "https://searchconsole.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/webmaster-tools/search-console-api/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1alpha1", - "name": "servicebroker", - "version": "v1alpha1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$clientovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1", - "name": "servicebroker", - "version": "v1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicebroker:v1beta1", - "name": "servicebroker", - "version": "v1beta1", - "title": "Service Broker API", - "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", - "discoveryRestUrl": "https://servicebroker.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "serviceconsumermanagement:v1", - "name": "serviceconsumermanagement", - "version": "v1", - "title": "Service Consumer Management API", - "description": "Manages the service consumers of a Service Infrastructure service.", - "discoveryRestUrl": "https://serviceconsumermanagement.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-consumer-management/docs/overview", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicecontrol:v1", - "name": "servicecontrol", - "version": "v1", - "title": "Service Control API", - "description": "Provides control plane functionality to managed services, such as logging, monitoring, and status checks.", - "discoveryRestUrl": "https://servicecontrol.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-control/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicemanagement:v1", - "name": "servicemanagement", - "version": "v1", - "title": "Service Management API", - "description": "Google Service Management allows service producers to publish their services on Google Cloud Platform so that they can be discovered and used by service consumers.", - "discoveryRestUrl": "https://servicemanagement.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-management/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "servicenetworking:v1beta", - "name": "servicenetworking", - "version": "v1beta", - "title": "Service Networking API", - "description": "Provides automatic management of network configurations necessary for certain services.", - "discoveryRestUrl": "https://servicenetworking.googleapis.com/$clientovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-infrastructure/docs/service-networking/getting-started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "serviceusage:v1", - "name": "serviceusage", - "version": "v1", - "title": "Service Usage API", - "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", - "discoveryRestUrl": "https://serviceusage.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-usage/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "serviceusage:v1beta1", - "name": "serviceusage", - "version": "v1beta1", - "title": "Service Usage API", - "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", - "discoveryRestUrl": "https://serviceusage.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/service-usage/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "sheets:v4", - "name": "sheets", - "version": "v4", - "title": "Google Sheets API", - "description": "Reads and writes Google Sheets.", - "discoveryRestUrl": "https://sheets.googleapis.com/$clientovery/rest?version=v4", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/sheets/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "siteVerification:v1", - "name": "siteVerification", - "version": "v1", - "title": "Google Site Verification API", - "description": "Verifies ownership of websites or domains with Google.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/siteVerification/v1/rest", - "discoveryLink": "./apis/siteVerification/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/site-verification/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "slides:v1", - "name": "slides", - "version": "v1", - "title": "Google Slides API", - "description": "An API for creating and editing Google Slides presentations.", - "discoveryRestUrl": "https://slides.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/slides/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "sourcerepo:v1", - "name": "sourcerepo", - "version": "v1", - "title": "Cloud Source Repositories API", - "description": "Access source code repositories hosted by Google.", - "discoveryRestUrl": "https://sourcerepo.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/source-repositories/docs/apis", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "spanner:v1", - "name": "spanner", - "version": "v1", - "title": "Cloud Spanner API", - "description": "Cloud Spanner is a managed, mission-critical, globally consistent and scalable relational database service.", - "discoveryRestUrl": "https://spanner.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/spanner/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "speech:v1", - "name": "speech", - "version": "v1", - "title": "Cloud Speech API", - "description": "Converts audio to text by applying powerful neural network models.", - "discoveryRestUrl": "https://speech.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/speech-to-text/docs/quickstart-protocol", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "speech:v1beta1", - "name": "speech", - "version": "v1beta1", - "title": "Cloud Speech API", - "description": "Converts audio to text by applying powerful neural network models.", - "discoveryRestUrl": "https://speech.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/speech-to-text/docs/quickstart-protocol", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "sqladmin:v1beta4", - "name": "sqladmin", - "version": "v1beta4", - "title": "Cloud SQL Admin API", - "description": "Creates and manages Cloud SQL instances, which provide fully managed MySQL or PostgreSQL databases.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/sqladmin/v1beta4/rest", - "discoveryLink": "./apis/sqladmin/v1beta4/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/sql/docs/reference/latest", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1", - "name": "storage", - "version": "v1", - "title": "Cloud Storage JSON API", - "description": "Stores and retrieves potentially large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1/rest", - "discoveryLink": "./apis/storage/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1beta1", - "name": "storage", - "version": "v1beta1", - "title": "Cloud Storage JSON API", - "description": "Lets you store and retrieve potentially-large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta1/rest", - "discoveryLink": "./apis/storage/v1beta1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "storage:v1beta2", - "name": "storage", - "version": "v1beta2", - "title": "Cloud Storage JSON API", - "description": "Lets you store and retrieve potentially-large, immutable data objects.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta2/rest", - "discoveryLink": "./apis/storage/v1beta2/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", - "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" - }, - "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "labels": [ - "labs" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "storagetransfer:v1", - "name": "storagetransfer", - "version": "v1", - "title": "Storage Transfer API", - "description": "Transfers data from external data sources to a Google Cloud Storage bucket or between Google Cloud Storage buckets.", - "discoveryRestUrl": "https://storagetransfer.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/storage/transfer", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "streetviewpublish:v1", - "name": "streetviewpublish", - "version": "v1", - "title": "Street View Publish API", - "description": "Publishes 360 photos to Google Maps, along with position, orientation, and connectivity metadata. Apps can offer an interface for positioning, connecting, and uploading user-generated Street View images.", - "discoveryRestUrl": "https://streetviewpublish.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/streetview/publish/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "surveys:v2", - "name": "surveys", - "version": "v2", - "title": "Surveys API", - "description": "Creates and conducts surveys, lists the surveys that an authenticated user owns, and retrieves survey results and information about specified surveys.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/surveys/v2/rest", - "discoveryLink": "./apis/surveys/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tagmanager:v1", - "name": "tagmanager", - "version": "v1", - "title": "Tag Manager API", - "description": "Accesses Tag Manager accounts and containers.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v1/rest", - "discoveryLink": "./apis/tagmanager/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/tag-manager/api/v1/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "tagmanager:v2", - "name": "tagmanager", - "version": "v2", - "title": "Tag Manager API", - "description": "Accesses Tag Manager accounts and containers.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v2/rest", - "discoveryLink": "./apis/tagmanager/v2/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/tag-manager/api/v2/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tasks:v1", - "name": "tasks", - "version": "v1", - "title": "Tasks API", - "description": "Lets you manage your tasks and task lists.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest", - "discoveryLink": "./apis/tasks/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/tasks-16.png", - "x32": "https://www.google.com/images/icons/product/tasks-32.png" - }, - "documentationLink": "https://developers.google.com/google-apps/tasks/firstapp", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "testing:v1", - "name": "testing", - "version": "v1", - "title": "Cloud Testing API", - "description": "Allows developers to run automated tests for their mobile applications on Google infrastructure.", - "discoveryRestUrl": "https://testing.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/cloud-test-lab/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "texttospeech:v1", - "name": "texttospeech", - "version": "v1", - "title": "Cloud Text-to-Speech API", - "description": "Synthesizes natural-sounding speech by applying powerful neural network models.", - "discoveryRestUrl": "https://texttospeech.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/text-to-speech/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "texttospeech:v1beta1", - "name": "texttospeech", - "version": "v1beta1", - "title": "Cloud Text-to-Speech API", - "description": "Synthesizes natural-sounding speech by applying powerful neural network models.", - "discoveryRestUrl": "https://texttospeech.googleapis.com/$clientovery/rest?version=v1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/text-to-speech/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "toolresults:v1beta3", - "name": "toolresults", - "version": "v1beta3", - "title": "Cloud Tool Results API", - "description": "Reads and publishes results from Firebase Test Lab.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/toolresults/v1beta3/rest", - "discoveryLink": "./apis/toolresults/v1beta3/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://firebase.google.com/docs/test-lab/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "tpu:v1alpha1", - "name": "tpu", - "version": "v1alpha1", - "title": "Cloud TPU API", - "description": "TPU API provides customers with access to Google TPU technology.", - "discoveryRestUrl": "https://tpu.googleapis.com/$clientovery/rest?version=v1alpha1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tpu/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "tpu:v1", - "name": "tpu", - "version": "v1", - "title": "Cloud TPU API", - "description": "TPU API provides customers with access to Google TPU technology.", - "discoveryRestUrl": "https://tpu.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/tpu/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "translate:v2", - "name": "translate", - "version": "v2", - "title": "Cloud Translation API", - "description": "Integrates text translation into your website or application.", - "discoveryRestUrl": "https://translation.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://code.google.com/apis/language/translate/v2/getting_started.html", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "urlshortener:v1", - "name": "urlshortener", - "version": "v1", - "title": "URL Shortener API", - "description": "Lets you create, inspect, and manage goo.gl short URLs", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/urlshortener/v1/rest", - "discoveryLink": "./apis/urlshortener/v1/rest", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/url-shortener/v1/getting_started", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "vault:v1", - "name": "vault", - "version": "v1", - "title": "G Suite Vault API", - "description": "Archiving and eDiscovery for G Suite.", - "discoveryRestUrl": "https://vault.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/vault", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1p1beta1", - "name": "videointelligence", - "version": "v1p1beta1", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$clientovery/rest?version=v1p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1", - "name": "videointelligence", - "version": "v1", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "videointelligence:v1beta2", - "name": "videointelligence", - "version": "v1beta2", - "title": "Cloud Video Intelligence API", - "description": "Cloud Video Intelligence API.", - "discoveryRestUrl": "https://videointelligence.googleapis.com/$clientovery/rest?version=v1beta2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/video-intelligence/docs/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1p1beta1", - "name": "vision", - "version": "v1p1beta1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$clientovery/rest?version=v1p1beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1p2beta1", - "name": "vision", - "version": "v1p2beta1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$clientovery/rest?version=v1p2beta1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "vision:v1", - "name": "vision", - "version": "v1", - "title": "Cloud Vision API", - "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", - "discoveryRestUrl": "https://vision.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/vision/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "webfonts:v1", - "name": "webfonts", - "version": "v1", - "title": "Google Fonts Developer API", - "description": "Accesses the metadata for all families served by Google Fonts, providing a list of families currently available (including available styles and a list of supported script subsets).", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webfonts/v1/rest", - "discoveryLink": "./apis/webfonts/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/feature/font_api-16.png", - "x32": "https://www.google.com/images/icons/feature/font_api-32.gif" - }, - "documentationLink": "https://developers.google.com/fonts/docs/developer_api", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "webmasters:v3", - "name": "webmasters", - "version": "v3", - "title": "Search Console API", - "description": "View Google Search Console data for your verified sites.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webmasters/v3/rest", - "discoveryLink": "./apis/webmasters/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/webmaster_tools-16.png", - "x32": "https://www.google.com/images/icons/product/webmaster_tools-32.png" - }, - "documentationLink": "https://developers.google.com/webmaster-tools/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "websecurityscanner:v1alpha", - "name": "websecurityscanner", - "version": "v1alpha", - "title": "Web Security Scanner API", - "description": "Web Security Scanner API (under development).", - "discoveryRestUrl": "https://websecurityscanner.googleapis.com/$clientovery/rest?version=v1alpha", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/security-scanner/", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "websecurityscanner:v1beta", - "name": "websecurityscanner", - "version": "v1beta", - "title": "Web Security Scanner API", - "description": "Web Security Scanner API (under development).", - "discoveryRestUrl": "https://websecurityscanner.googleapis.com/$clientovery/rest?version=v1beta", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://cloud.google.com/security-scanner/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtube:v3", - "name": "youtube", - "version": "v3", - "title": "YouTube Data API", - "description": "Supports core YouTube features, such as uploading videos, creating and managing playlists, searching for content, and much more.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest", - "discoveryLink": "./apis/youtube/v3/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "https://developers.google.com/youtube/v3", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v1", - "name": "youtubeAnalytics", - "version": "v1", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1/rest", - "discoveryLink": "./apis/youtubeAnalytics/v1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "http://developers.google.com/youtube/analytics/", - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v1beta1", - "name": "youtubeAnalytics", - "version": "v1beta1", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1beta1/rest", - "discoveryLink": "./apis/youtubeAnalytics/v1beta1/rest", - "icons": { - "x16": "https://www.google.com/images/icons/product/youtube-16.png", - "x32": "https://www.google.com/images/icons/product/youtube-32.png" - }, - "documentationLink": "http://developers.google.com/youtube/analytics/", - "labels": [ - "deprecated" - ], - "preferred": false - }, - { - "kind": "discovery#directoryItem", - "id": "youtubeAnalytics:v2", - "name": "youtubeAnalytics", - "version": "v2", - "title": "YouTube Analytics API", - "description": "Retrieves your YouTube Analytics data.", - "discoveryRestUrl": "https://youtubeanalytics.googleapis.com/$clientovery/rest?version=v2", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/youtube/analytics", - "preferred": true - }, - { - "kind": "discovery#directoryItem", - "id": "youtubereporting:v1", - "name": "youtubereporting", - "version": "v1", - "title": "YouTube Reporting API", - "description": "Schedules reporting jobs containing your YouTube Analytics data and downloads the resulting bulk data reports in the form of CSV files.", - "discoveryRestUrl": "https://youtubereporting.googleapis.com/$clientovery/rest?version=v1", - "icons": { - "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", - "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" - }, - "documentationLink": "https://developers.google.com/youtube/reporting/v1/reports/", - "preferred": true - } - ] -} -_END -} - -sub pre_get_gmail_spec_json -{ - return <<'__END' -{ - "kind": "discovery#restDescription", - "etag": "\"J3WqvAcMk4eQjJXvfSI4Yr8VouA/zhBQnUVXp-QQ6Y6QUt5UiGZD_sA\"", - "discoveryVersion": "v1", - "id": "gmail:v1", - "name": "gmail", - "version": "v1", - "revision": "20180904", - "title": "Gmail API", - "description": "Access Gmail mailboxes including sending user email.", - "ownerDomain": "google.com", - "ownerName": "Google", - "icons": { - "x16": "https://www.google.com/images/icons/product/googlemail-16.png", - "x32": "https://www.google.com/images/icons/product/googlemail-32.png" - }, - "documentationLink": "https://developers.google.com/gmail/api/", - "protocol": "rest", - "baseUrl": "https://www.googleapis.com/gmail/v1/users/", - "basePath": "/gmail/v1/users/", - "rootUrl": "https://www.googleapis.com/", - "servicePath": "gmail/v1/users/", - "batchPath": "batch/gmail/v1", - "parameters": { - "alt": { - "type": "string", - "description": "Data format for the response.", - "default": "json", - "enum": [ - "json" - ], - "enumDescriptions": [ - "Responses with Content-Type of application/json" - ], - "location": "query" - }, - "fields": { - "type": "string", - "description": "Selector specifying which fields to include in a partial response.", - "location": "query" - }, - "key": { - "type": "string", - "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.", - "location": "query" - }, - "oauth_token": { - "type": "string", - "description": "OAuth 2.0 token for the current user.", - "location": "query" - }, - "prettyPrint": { - "type": "boolean", - "description": "Returns response with indentations and line breaks.", - "default": "true", - "location": "query" - }, - "quotaUser": { - "type": "string", - "description": "An opaque string that represents a user for quota purposes. Must not exceed 40 characters.", - "location": "query" - }, - "userIp": { - "type": "string", - "description": "Deprecated. Please use quotaUser instead.", - "location": "query" - } - }, - "auth": { - "oauth2": { - "scopes": { - "https://mail.google.com/": { - "description": "Read, send, delete, and manage your email" - }, - "https://www.googleapis.com/auth/gmail.compose": { - "description": "Manage drafts and send emails" - }, - "https://www.googleapis.com/auth/gmail.insert": { - "description": "Insert mail into your mailbox" - }, - "https://www.googleapis.com/auth/gmail.labels": { - "description": "Manage mailbox labels" - }, - "https://www.googleapis.com/auth/gmail.metadata": { - "description": "View your email message metadata such as labels and headers, but not the email body" - }, - "https://www.googleapis.com/auth/gmail.modify": { - "description": "View and modify but not delete your email" - }, - "https://www.googleapis.com/auth/gmail.readonly": { - "description": "View your email messages and settings" - }, - "https://www.googleapis.com/auth/gmail.send": { - "description": "Send email on your behalf" - }, - "https://www.googleapis.com/auth/gmail.settings.basic": { - "description": "Manage your basic mail settings" - }, - "https://www.googleapis.com/auth/gmail.settings.sharing": { - "description": "Manage your sensitive mail settings, including who can manage your mail" - } - } - } - }, - "schemas": { - "AutoForwarding": { - "id": "AutoForwarding", - "type": "object", - "description": "Auto-forwarding settings for an account.", - "properties": { - "disposition": { - "type": "string", - "description": "The state that a message should be left in after it has been forwarded.", - "enum": [ - "archive", - "dispositionUnspecified", - "leaveInInbox", - "markRead", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - }, - "emailAddress": { - "type": "string", - "description": "Email address to which all incoming messages are forwarded. This email address must be a verified member of the forwarding addresses." - }, - "enabled": { - "type": "boolean", - "description": "Whether all incoming mail is automatically forwarded to another address." - } - } - }, - "BatchDeleteMessagesRequest": { - "id": "BatchDeleteMessagesRequest", - "type": "object", - "properties": { - "ids": { - "type": "array", - "description": "The IDs of the messages to delete.", - "items": { - "type": "string" - } - } - } - }, - "BatchModifyMessagesRequest": { - "id": "BatchModifyMessagesRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of label IDs to add to messages.", - "items": { - "type": "string" - } - }, - "ids": { - "type": "array", - "description": "The IDs of the messages to modify. There is a limit of 1000 ids per request.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list of label IDs to remove from messages.", - "items": { - "type": "string" - } - } - } - }, - "Delegate": { - "id": "Delegate", - "type": "object", - "description": "Settings for a delegate. Delegates can read, send, and delete messages, as well as manage contacts, for the delegator's account. See \"Set up mail delegation\" for more information about delegates.", - "properties": { - "delegateEmail": { - "type": "string", - "description": "The email address of the delegate." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified and can act as a delegate for the account. Read-only.", - "enum": [ - "accepted", - "expired", - "pending", - "rejected", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - } - } - }, - "Draft": { - "id": "Draft", - "type": "object", - "description": "A draft email in the user's mailbox.", - "properties": { - "id": { - "type": "string", - "description": "The immutable ID of the draft.", - "annotations": { - "required": [ - "gmail.users.drafts.send" - ] - } - }, - "message": { - "$ref": "Message", - "description": "The message content of the draft." - } - } - }, - "Filter": { - "id": "Filter", - "type": "object", - "description": "Resource definition for Gmail filters. Filters apply to specific messages instead of an entire email thread.", - "properties": { - "action": { - "$ref": "FilterAction", - "description": "Action that the filter performs." - }, - "criteria": { - "$ref": "FilterCriteria", - "description": "Matching criteria for the filter." - }, - "id": { - "type": "string", - "description": "The server assigned ID of the filter." - } - } - }, - "FilterAction": { - "id": "FilterAction", - "type": "object", - "description": "A set of actions to perform on a message.", - "properties": { - "addLabelIds": { - "type": "array", - "description": "List of labels to add to the message.", - "items": { - "type": "string" - } - }, - "forward": { - "type": "string", - "description": "Email address that the message should be forwarded to." - }, - "removeLabelIds": { - "type": "array", - "description": "List of labels to remove from the message.", - "items": { - "type": "string" - } - } - } - }, - "FilterCriteria": { - "id": "FilterCriteria", - "type": "object", - "description": "Message matching criteria.", - "properties": { - "excludeChats": { - "type": "boolean", - "description": "Whether the response should exclude chats." - }, - "from": { - "type": "string", - "description": "The sender's display name or email address." - }, - "hasAttachment": { - "type": "boolean", - "description": "Whether the message has any attachment." - }, - "negatedQuery": { - "type": "string", - "description": "Only return messages not matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\"." - }, - "query": { - "type": "string", - "description": "Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\"." - }, - "size": { - "type": "integer", - "description": "The size of the entire RFC822 message in bytes, including all headers and attachments.", - "format": "int32" - }, - "sizeComparison": { - "type": "string", - "description": "How the message size in bytes should be in relation to the size field.", - "enum": [ - "larger", - "smaller", - "unspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - }, - "subject": { - "type": "string", - "description": "Case-insensitive phrase found in the message's subject. Trailing and leading whitespace are be trimmed and adjacent spaces are collapsed." - }, - "to": { - "type": "string", - "description": "The recipient's display name or email address. Includes recipients in the \"to\", \"cc\", and \"bcc\" header fields. You can use simply the local part of the email address. For example, \"example\" and \"example@\" both match \"example@gmail.com\". This field is case-insensitive." - } - } - }, - "ForwardingAddress": { - "id": "ForwardingAddress", - "type": "object", - "description": "Settings for a forwarding address.", - "properties": { - "forwardingEmail": { - "type": "string", - "description": "An email address to which messages can be forwarded." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified and is usable for forwarding. Read-only.", - "enum": [ - "accepted", - "pending", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - } - } - }, - "History": { - "id": "History", - "type": "object", - "description": "A record of a change to the user's mailbox. Each history change may affect multiple messages in multiple ways.", - "properties": { - "id": { - "type": "string", - "description": "The mailbox sequence ID.", - "format": "uint64" - }, - "labelsAdded": { - "type": "array", - "description": "Labels added to messages in this history record.", - "items": { - "$ref": "HistoryLabelAdded" - } - }, - "labelsRemoved": { - "type": "array", - "description": "Labels removed from messages in this history record.", - "items": { - "$ref": "HistoryLabelRemoved" - } - }, - "messages": { - "type": "array", - "description": "List of messages changed in this history record. The fields for specific change types, such as messagesAdded may duplicate messages in this field. We recommend using the specific change-type fields instead of this.", - "items": { - "$ref": "Message" - } - }, - "messagesAdded": { - "type": "array", - "description": "Messages added to the mailbox in this history record.", - "items": { - "$ref": "HistoryMessageAdded" - } - }, - "messagesDeleted": { - "type": "array", - "description": "Messages deleted (not Trashed) from the mailbox in this history record.", - "items": { - "$ref": "HistoryMessageDeleted" - } - } - } - }, - "HistoryLabelAdded": { - "id": "HistoryLabelAdded", - "type": "object", - "properties": { - "labelIds": { - "type": "array", - "description": "Label IDs added to the message.", - "items": { - "type": "string" - } - }, - "message": { - "$ref": "Message" - } - } - }, - "HistoryLabelRemoved": { - "id": "HistoryLabelRemoved", - "type": "object", - "properties": { - "labelIds": { - "type": "array", - "description": "Label IDs removed from the message.", - "items": { - "type": "string" - } - }, - "message": { - "$ref": "Message" - } - } - }, - "HistoryMessageAdded": { - "id": "HistoryMessageAdded", - "type": "object", - "properties": { - "message": { - "$ref": "Message" - } - } - }, - "HistoryMessageDeleted": { - "id": "HistoryMessageDeleted", - "type": "object", - "properties": { - "message": { - "$ref": "Message" - } - } - }, - "ImapSettings": { - "id": "ImapSettings", - "type": "object", - "description": "IMAP settings for an account.", - "properties": { - "autoExpunge": { - "type": "boolean", - "description": "If this value is true, Gmail will immediately expunge a message when it is marked as deleted in IMAP. Otherwise, Gmail will wait for an update from the client before expunging messages marked as deleted." - }, - "enabled": { - "type": "boolean", - "description": "Whether IMAP is enabled for the account." - }, - "expungeBehavior": { - "type": "string", - "description": "The action that will be executed on a message when it is marked as deleted and expunged from the last visible IMAP folder.", - "enum": [ - "archive", - "deleteForever", - "expungeBehaviorUnspecified", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "maxFolderSize": { - "type": "integer", - "description": "An optional limit on the number of messages that an IMAP folder may contain. Legal values are 0, 1000, 2000, 5000 or 10000. A value of zero is interpreted to mean that there is no limit.", - "format": "int32" - } - } - }, - "Label": { - "id": "Label", - "type": "object", - "description": "Labels are used to categorize messages and threads within the user's mailbox.", - "properties": { - "color": { - "$ref": "LabelColor", - "description": "The color to assign to the label. Color is only available for labels that have their type set to user." - }, - "id": { - "type": "string", - "description": "The immutable ID of the label.", - "annotations": { - "required": [ - "gmail.users.labels.update" - ] - } - }, - "labelListVisibility": { - "type": "string", - "description": "The visibility of the label in the label list in the Gmail web interface.", - "enum": [ - "labelHide", - "labelShow", - "labelShowIfUnread" - ], - "enumDescriptions": [ - "", - "", - "" - ], - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "messageListVisibility": { - "type": "string", - "description": "The visibility of the label in the message list in the Gmail web interface.", - "enum": [ - "hide", - "show" - ], - "enumDescriptions": [ - "", - "" - ], - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "messagesTotal": { - "type": "integer", - "description": "The total number of messages with the label.", - "format": "int32" - }, - "messagesUnread": { - "type": "integer", - "description": "The number of unread messages with the label.", - "format": "int32" - }, - "name": { - "type": "string", - "description": "The display name of the label.", - "annotations": { - "required": [ - "gmail.users.labels.create", - "gmail.users.labels.update" - ] - } - }, - "threadsTotal": { - "type": "integer", - "description": "The total number of threads with the label.", - "format": "int32" - }, - "threadsUnread": { - "type": "integer", - "description": "The number of unread threads with the label.", - "format": "int32" - }, - "type": { - "type": "string", - "description": "The owner type for the label. User labels are created by the user and can be modified and deleted by the user and can be applied to any message or thread. System labels are internally created and cannot be added, modified, or deleted. System labels may be able to be applied to or removed from messages and threads under some circumstances but this is not guaranteed. For example, users can apply and remove the INBOX and UNREAD labels from messages and threads, but cannot apply or remove the DRAFTS or SENT labels from messages or threads.", - "enum": [ - "system", - "user" - ], - "enumDescriptions": [ - "", - "" - ] - } - } - }, - "LabelColor": { - "id": "LabelColor", - "type": "object", - "properties": { - "backgroundColor": { - "type": "string", - "description": "The background color represented as hex string #RRGGBB (ex #000000). This field is required in order to set the color of a label. Only the following predefined set of color values are allowed:\n#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, #fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, #f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, #efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, #e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, #cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, #ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, #822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c" - }, - "textColor": { - "type": "string", - "description": "The text color of the label, represented as hex string. This field is required in order to set the color of a label. Only the following predefined set of color values are allowed:\n#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, #fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, #f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, #efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, #e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, #cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, #ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, #822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c" - } - } - }, - "ListDelegatesResponse": { - "id": "ListDelegatesResponse", - "type": "object", - "description": "Response for the ListDelegates method.", - "properties": { - "delegates": { - "type": "array", - "description": "List of the user's delegates (with any verification status).", - "items": { - "$ref": "Delegate" - } - } - } - }, - "ListDraftsResponse": { - "id": "ListDraftsResponse", - "type": "object", - "properties": { - "drafts": { - "type": "array", - "description": "List of drafts.", - "items": { - "$ref": "Draft" - } - }, - "nextPageToken": { - "type": "string", - "description": "Token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - } - } - }, - "ListFiltersResponse": { - "id": "ListFiltersResponse", - "type": "object", - "description": "Response for the ListFilters method.", - "properties": { - "filter": { - "type": "array", - "description": "List of a user's filters.", - "items": { - "$ref": "Filter" - } - } - } - }, - "ListForwardingAddressesResponse": { - "id": "ListForwardingAddressesResponse", - "type": "object", - "description": "Response for the ListForwardingAddresses method.", - "properties": { - "forwardingAddresses": { - "type": "array", - "description": "List of addresses that may be used for forwarding.", - "items": { - "$ref": "ForwardingAddress" - } - } - } - }, - "ListHistoryResponse": { - "id": "ListHistoryResponse", - "type": "object", - "properties": { - "history": { - "type": "array", - "description": "List of history records. Any messages contained in the response will typically only have id and threadId fields populated.", - "items": { - "$ref": "History" - } - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - }, - "nextPageToken": { - "type": "string", - "description": "Page token to retrieve the next page of results in the list." - } - } - }, - "ListLabelsResponse": { - "id": "ListLabelsResponse", - "type": "object", - "properties": { - "labels": { - "type": "array", - "description": "List of labels.", - "items": { - "$ref": "Label" - } - } - } - }, - "ListMessagesResponse": { - "id": "ListMessagesResponse", - "type": "object", - "properties": { - "messages": { - "type": "array", - "description": "List of messages.", - "items": { - "$ref": "Message" - } - }, - "nextPageToken": { - "type": "string", - "description": "Token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - } - } - }, - "ListSendAsResponse": { - "id": "ListSendAsResponse", - "type": "object", - "description": "Response for the ListSendAs method.", - "properties": { - "sendAs": { - "type": "array", - "description": "List of send-as aliases.", - "items": { - "$ref": "SendAs" - } - } - } - }, - "ListSmimeInfoResponse": { - "id": "ListSmimeInfoResponse", - "type": "object", - "properties": { - "smimeInfo": { - "type": "array", - "description": "List of SmimeInfo.", - "items": { - "$ref": "SmimeInfo" - } - } - } - }, - "ListThreadsResponse": { - "id": "ListThreadsResponse", - "type": "object", - "properties": { - "nextPageToken": { - "type": "string", - "description": "Page token to retrieve the next page of results in the list." - }, - "resultSizeEstimate": { - "type": "integer", - "description": "Estimated total number of results.", - "format": "uint32" - }, - "threads": { - "type": "array", - "description": "List of threads.", - "items": { - "$ref": "Thread" - } - } - } - }, - "Message": { - "id": "Message", - "type": "object", - "description": "An email message.", - "properties": { - "historyId": { - "type": "string", - "description": "The ID of the last history record that modified this message.", - "format": "uint64" - }, - "id": { - "type": "string", - "description": "The immutable ID of the message." - }, - "internalDate": { - "type": "string", - "description": "The internal message creation timestamp (epoch ms), which determines ordering in the inbox. For normal SMTP-received email, this represents the time the message was originally accepted by Google, which is more reliable than the Date header. However, for API-migrated mail, it can be configured by client to be based on the Date header.", - "format": "int64" - }, - "labelIds": { - "type": "array", - "description": "List of IDs of labels applied to this message.", - "items": { - "type": "string" - } - }, - "payload": { - "$ref": "MessagePart", - "description": "The parsed email structure in the message parts." - }, - "raw": { - "type": "string", - "description": "The entire email message in an RFC 2822 formatted and base64url encoded string. Returned in messages.get and drafts.get responses when the format=RAW parameter is supplied.", - "format": "byte", - "annotations": { - "required": [ - "gmail.users.drafts.create", - "gmail.users.drafts.update", - "gmail.users.messages.insert", - "gmail.users.messages.send" - ] - } - }, - "sizeEstimate": { - "type": "integer", - "description": "Estimated size in bytes of the message.", - "format": "int32" - }, - "snippet": { - "type": "string", - "description": "A short part of the message text." - }, - "threadId": { - "type": "string", - "description": "The ID of the thread the message belongs to. To add a message or draft to a thread, the following criteria must be met: \n- The requested threadId must be specified on the Message or Draft.Message you supply with your request. \n- The References and In-Reply-To headers must be set in compliance with the RFC 2822 standard. \n- The Subject headers must match." - } - } - }, - "MessagePart": { - "id": "MessagePart", - "type": "object", - "description": "A single MIME message part.", - "properties": { - "body": { - "$ref": "MessagePartBody", - "description": "The message part body for this part, which may be empty for container MIME message parts." - }, - "filename": { - "type": "string", - "description": "The filename of the attachment. Only present if this message part represents an attachment." - }, - "headers": { - "type": "array", - "description": "List of headers on this message part. For the top-level message part, representing the entire message payload, it will contain the standard RFC 2822 email headers such as To, From, and Subject.", - "items": { - "$ref": "MessagePartHeader" - } - }, - "mimeType": { - "type": "string", - "description": "The MIME type of the message part." - }, - "partId": { - "type": "string", - "description": "The immutable ID of the message part." - }, - "parts": { - "type": "array", - "description": "The child MIME message parts of this part. This only applies to container MIME message parts, for example multipart/*. For non- container MIME message part types, such as text/plain, this field is empty. For more information, see RFC 1521.", - "items": { - "$ref": "MessagePart" - } - } - } - }, - "MessagePartBody": { - "id": "MessagePartBody", - "type": "object", - "description": "The body of a single MIME message part.", - "properties": { - "attachmentId": { - "type": "string", - "description": "When present, contains the ID of an external attachment that can be retrieved in a separate messages.attachments.get request. When not present, the entire content of the message part body is contained in the data field." - }, - "data": { - "type": "string", - "description": "The body data of a MIME message part as a base64url encoded string. May be empty for MIME container types that have no message body or when the body data is sent as a separate attachment. An attachment ID is present if the body data is contained in a separate attachment.", - "format": "byte" - }, - "size": { - "type": "integer", - "description": "Number of bytes for the message part data (encoding notwithstanding).", - "format": "int32" - } - } - }, - "MessagePartHeader": { - "id": "MessagePartHeader", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the header before the : separator. For example, To." - }, - "value": { - "type": "string", - "description": "The value of the header after the : separator. For example, someuser@example.com." - } - } - }, - "ModifyMessageRequest": { - "id": "ModifyMessageRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of IDs of labels to add to this message.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list IDs of labels to remove from this message.", - "items": { - "type": "string" - } - } - } - }, - "ModifyThreadRequest": { - "id": "ModifyThreadRequest", - "type": "object", - "properties": { - "addLabelIds": { - "type": "array", - "description": "A list of IDs of labels to add to this thread.", - "items": { - "type": "string" - } - }, - "removeLabelIds": { - "type": "array", - "description": "A list of IDs of labels to remove from this thread.", - "items": { - "type": "string" - } - } - } - }, - "PopSettings": { - "id": "PopSettings", - "type": "object", - "description": "POP settings for an account.", - "properties": { - "accessWindow": { - "type": "string", - "description": "The range of messages which are accessible via POP.", - "enum": [ - "accessWindowUnspecified", - "allMail", - "disabled", - "fromNowOn" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "disposition": { - "type": "string", - "description": "The action that will be executed on a message after it has been fetched via POP.", - "enum": [ - "archive", - "dispositionUnspecified", - "leaveInInbox", - "markRead", - "trash" - ], - "enumDescriptions": [ - "", - "", - "", - "", - "" - ] - } - } - }, - "Profile": { - "id": "Profile", - "type": "object", - "description": "Profile for a Gmail user.", - "properties": { - "emailAddress": { - "type": "string", - "description": "The user's email address." - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - }, - "messagesTotal": { - "type": "integer", - "description": "The total number of messages in the mailbox.", - "format": "int32" - }, - "threadsTotal": { - "type": "integer", - "description": "The total number of threads in the mailbox.", - "format": "int32" - } - } - }, - "SendAs": { - "id": "SendAs", - "type": "object", - "description": "Settings associated with a send-as alias, which can be either the primary login address associated with the account or a custom \"from\" address. Send-as aliases correspond to the \"Send Mail As\" feature in the web interface.", - "properties": { - "displayName": { - "type": "string", - "description": "A name that appears in the \"From:\" header for mail sent using this alias. For custom \"from\" addresses, when this is empty, Gmail will populate the \"From:\" header with the name that is used for the primary address associated with the account. If the admin has disabled the ability for users to update their name format, requests to update this field for the primary login will silently fail." - }, - "isDefault": { - "type": "boolean", - "description": "Whether this address is selected as the default \"From:\" address in situations such as composing a new message or sending a vacation auto-reply. Every Gmail account has exactly one default send-as address, so the only legal value that clients may write to this field is true. Changing this from false to true for an address will result in this field becoming false for the other previous default address." - }, - "isPrimary": { - "type": "boolean", - "description": "Whether this address is the primary address used to login to the account. Every Gmail account has exactly one primary address, and it cannot be deleted from the collection of send-as aliases. This field is read-only." - }, - "replyToAddress": { - "type": "string", - "description": "An optional email address that is included in a \"Reply-To:\" header for mail sent using this alias. If this is empty, Gmail will not generate a \"Reply-To:\" header." - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias. This is read-only for all operations except create." - }, - "signature": { - "type": "string", - "description": "An optional HTML signature that is included in messages composed with this alias in the Gmail web UI." - }, - "smtpMsa": { - "$ref": "SmtpMsa", - "description": "An optional SMTP service that will be used as an outbound relay for mail sent using this alias. If this is empty, outbound mail will be sent directly from Gmail's servers to the destination SMTP service. This setting only applies to custom \"from\" aliases." - }, - "treatAsAlias": { - "type": "boolean", - "description": "Whether Gmail should treat this address as an alias for the user's primary email address. This setting only applies to custom \"from\" aliases." - }, - "verificationStatus": { - "type": "string", - "description": "Indicates whether this address has been verified for use as a send-as alias. Read-only. This setting only applies to custom \"from\" aliases.", - "enum": [ - "accepted", - "pending", - "verificationStatusUnspecified" - ], - "enumDescriptions": [ - "", - "", - "" - ] - } - } - }, - "SmimeInfo": { - "id": "SmimeInfo", - "type": "object", - "description": "An S/MIME email config.", - "properties": { - "encryptedKeyPassword": { - "type": "string", - "description": "Encrypted key password, when key is encrypted." - }, - "expiration": { - "type": "string", - "description": "When the certificate expires (in milliseconds since epoch).", - "format": "int64" - }, - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo." - }, - "isDefault": { - "type": "boolean", - "description": "Whether this SmimeInfo is the default one for this user's send-as address." - }, - "issuerCn": { - "type": "string", - "description": "The S/MIME certificate issuer's common name." - }, - "pem": { - "type": "string", - "description": "PEM formatted X509 concatenated certificate string (standard base64 encoding). Format used for returning key, which includes public key as well as certificate chain (not private key)." - }, - "pkcs12": { - "type": "string", - "description": "PKCS#12 format containing a single private/public key pair and certificate chain. This format is only accepted from client for creating a new SmimeInfo and is never returned, because the private key is not intended to be exported. PKCS#12 may be encrypted, in which case encryptedKeyPassword should be set appropriately.", - "format": "byte" - } - } - }, - "SmtpMsa": { - "id": "SmtpMsa", - "type": "object", - "description": "Configuration for communication with an SMTP service.", - "properties": { - "host": { - "type": "string", - "description": "The hostname of the SMTP service. Required." - }, - "password": { - "type": "string", - "description": "The password that will be used for authentication with the SMTP service. This is a write-only field that can be specified in requests to create or update SendAs settings; it is never populated in responses." - }, - "port": { - "type": "integer", - "description": "The port of the SMTP service. Required.", - "format": "int32" - }, - "securityMode": { - "type": "string", - "description": "The protocol that will be used to secure communication with the SMTP service. Required.", - "enum": [ - "none", - "securityModeUnspecified", - "ssl", - "starttls" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ] - }, - "username": { - "type": "string", - "description": "The username that will be used for authentication with the SMTP service. This is a write-only field that can be specified in requests to create or update SendAs settings; it is never populated in responses." - } - } - }, - "Thread": { - "id": "Thread", - "type": "object", - "description": "A collection of messages representing a conversation.", - "properties": { - "historyId": { - "type": "string", - "description": "The ID of the last history record that modified this thread.", - "format": "uint64" - }, - "id": { - "type": "string", - "description": "The unique ID of the thread." - }, - "messages": { - "type": "array", - "description": "The list of messages in the thread.", - "items": { - "$ref": "Message" - } - }, - "snippet": { - "type": "string", - "description": "A short part of the message text." - } - } - }, - "VacationSettings": { - "id": "VacationSettings", - "type": "object", - "description": "Vacation auto-reply settings for an account. These settings correspond to the \"Vacation responder\" feature in the web interface.", - "properties": { - "enableAutoReply": { - "type": "boolean", - "description": "Flag that controls whether Gmail automatically replies to messages." - }, - "endTime": { - "type": "string", - "description": "An optional end time for sending auto-replies (epoch ms). When this is specified, Gmail will automatically reply only to messages that it receives before the end time. If both startTime and endTime are specified, startTime must precede endTime.", - "format": "int64" - }, - "responseBodyHtml": { - "type": "string", - "description": "Response body in HTML format. Gmail will sanitize the HTML before storing it." - }, - "responseBodyPlainText": { - "type": "string", - "description": "Response body in plain text format." - }, - "responseSubject": { - "type": "string", - "description": "Optional text to prepend to the subject line in vacation responses. In order to enable auto-replies, either the response subject or the response body must be nonempty." - }, - "restrictToContacts": { - "type": "boolean", - "description": "Flag that determines whether responses are sent to recipients who are not in the user's list of contacts." - }, - "restrictToDomain": { - "type": "boolean", - "description": "Flag that determines whether responses are sent to recipients who are outside of the user's domain. This feature is only available for G Suite users." - }, - "startTime": { - "type": "string", - "description": "An optional start time for sending auto-replies (epoch ms). When this is specified, Gmail will automatically reply only to messages that it receives after the start time. If both startTime and endTime are specified, startTime must precede endTime.", - "format": "int64" - } - } - }, - "WatchRequest": { - "id": "WatchRequest", - "type": "object", - "description": "Set up or update a new push notification watch on this user's mailbox.", - "properties": { - "labelFilterAction": { - "type": "string", - "description": "Filtering behavior of labelIds list specified.", - "enum": [ - "exclude", - "include" - ], - "enumDescriptions": [ - "", - "" - ] - }, - "labelIds": { - "type": "array", - "description": "List of label_ids to restrict notifications about. By default, if unspecified, all changes are pushed out. If specified then dictates which labels are required for a push notification to be generated.", - "items": { - "type": "string" - } - }, - "topicName": { - "type": "string", - "description": "A fully qualified Google Cloud Pub/Sub API topic name to publish the events to. This topic name **must** already exist in Cloud Pub/Sub and you **must** have already granted gmail \"publish\" permission on it. For example, \"projects/my-project-identifier/topics/my-topic-name\" (using the Cloud Pub/Sub \"v1\" topic naming format).\n\nNote that the \"my-project-identifier\" portion must exactly match your Google developer project id (the one executing this watch request)." - } - } - }, - "WatchResponse": { - "id": "WatchResponse", - "type": "object", - "description": "Push notification watch response.", - "properties": { - "expiration": { - "type": "string", - "description": "When Gmail will stop sending notifications for mailbox updates (epoch millis). Call watch again before this time to renew the watch.", - "format": "int64" - }, - "historyId": { - "type": "string", - "description": "The ID of the mailbox's current history record.", - "format": "uint64" - } - } - } - }, - "resources": { - "users": { - "methods": { - "getProfile": { - "id": "gmail.users.getProfile", - "path": "{userId}/profile", - "httpMethod": "GET", - "description": "Gets the current user's Gmail profile.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "Profile" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "stop": { - "id": "gmail.users.stop", - "path": "{userId}/stop", - "httpMethod": "POST", - "description": "Stop receiving push notifications for the given user mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "watch": { - "id": "gmail.users.watch", - "path": "{userId}/watch", - "httpMethod": "POST", - "description": "Set up or update a push notification watch on the given user mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "WatchRequest" - }, - "response": { - "$ref": "WatchResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - }, - "resources": { - "drafts": { - "methods": { - "create": { - "id": "gmail.users.drafts.create", - "path": "{userId}/drafts", - "httpMethod": "POST", - "description": "Creates a new draft with the DRAFT label.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts" - } - } - } - }, - "delete": { - "id": "gmail.users.drafts.delete", - "path": "{userId}/drafts/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified draft. Does not simply trash it.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the draft to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "get": { - "id": "gmail.users.drafts.get", - "path": "{userId}/drafts/{id}", - "httpMethod": "GET", - "description": "Gets the specified draft.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the draft in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal", - "raw" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the draft to retrieve.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.drafts.list", - "path": "{userId}/drafts", - "httpMethod": "GET", - "description": "Lists the drafts in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include drafts from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of drafts to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return draft messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\".", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListDraftsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "send": { - "id": "gmail.users.drafts.send", - "path": "{userId}/drafts/send", - "httpMethod": "POST", - "description": "Sends the specified, existing draft to the recipients in the To, Cc, and Bcc headers.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts/send" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts/send" - } - } - } - }, - "update": { - "id": "gmail.users.drafts.update", - "path": "{userId}/drafts/{id}", - "httpMethod": "PUT", - "description": "Replaces a draft's content.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the draft to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Draft" - }, - "response": { - "$ref": "Draft" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/drafts/{id}" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/drafts/{id}" - } - } - } - } - } - }, - "history": { - "methods": { - "list": { - "id": "gmail.users.history.list", - "path": "{userId}/history", - "httpMethod": "GET", - "description": "Lists the history of all changes to the given mailbox. History results are returned in chronological order (increasing historyId).", - "parameters": { - "historyTypes": { - "type": "string", - "description": "History types to be returned by the function", - "enum": [ - "labelAdded", - "labelRemoved", - "messageAdded", - "messageDeleted" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "repeated": true, - "location": "query" - }, - "labelId": { - "type": "string", - "description": "Only return messages with a label matching the ID.", - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "The maximum number of history records to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "startHistoryId": { - "type": "string", - "description": "Required. Returns history records after the specified startHistoryId. The supplied startHistoryId should be obtained from the historyId of a message, thread, or previous list response. History IDs increase chronologically but are not contiguous with random gaps in between valid IDs. Supplying an invalid or out of date startHistoryId typically returns an HTTP 404 error code. A historyId is typically valid for at least a week, but in some rare circumstances may be valid for only a few hours. If you receive an HTTP 404 error response, your application should perform a full sync. If you receive no nextPageToken in the response, there are no updates to retrieve and you can store the returned historyId for a future request.", - "format": "uint64", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListHistoryResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - } - }, - "labels": { - "methods": { - "create": { - "id": "gmail.users.labels.create", - "path": "{userId}/labels", - "httpMethod": "POST", - "description": "Creates a new label.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "delete": { - "id": "gmail.users.labels.delete", - "path": "{userId}/labels/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified label and removes it from any messages and threads that it is applied to.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "get": { - "id": "gmail.users.labels.get", - "path": "{userId}/labels/{id}", - "httpMethod": "GET", - "description": "Gets the specified label.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to retrieve.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.labels.list", - "path": "{userId}/labels", - "httpMethod": "GET", - "description": "Lists all labels in the user's mailbox.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListLabelsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "patch": { - "id": "gmail.users.labels.patch", - "path": "{userId}/labels/{id}", - "httpMethod": "PATCH", - "description": "Updates the specified label. This method supports patch semantics.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "update": { - "id": "gmail.users.labels.update", - "path": "{userId}/labels/{id}", - "httpMethod": "PUT", - "description": "Updates the specified label.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the label to update.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "Label" - }, - "response": { - "$ref": "Label" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - } - }, - "messages": { - "methods": { - "batchDelete": { - "id": "gmail.users.messages.batchDelete", - "path": "{userId}/messages/batchDelete", - "httpMethod": "POST", - "description": "Deletes many messages by message ID. Provides no guarantees that messages were not already deleted or even existed at all.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "BatchDeleteMessagesRequest" - }, - "scopes": [ - "https://mail.google.com/" - ] - }, - "batchModify": { - "id": "gmail.users.messages.batchModify", - "path": "{userId}/messages/batchModify", - "httpMethod": "POST", - "description": "Modifies the labels on the specified messages.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "BatchModifyMessagesRequest" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "delete": { - "id": "gmail.users.messages.delete", - "path": "{userId}/messages/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified message. This operation cannot be undone. Prefer messages.trash instead.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/" - ] - }, - "get": { - "id": "gmail.users.messages.get", - "path": "{userId}/messages/{id}", - "httpMethod": "GET", - "description": "Gets the specified message.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the message in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal", - "raw" - ], - "enumDescriptions": [ - "", - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the message to retrieve.", - "required": true, - "location": "path" - }, - "metadataHeaders": { - "type": "string", - "description": "When given and format is METADATA, only include headers specified.", - "repeated": true, - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "import": { - "id": "gmail.users.messages.import", - "path": "{userId}/messages/import", - "httpMethod": "POST", - "description": "Imports a message into only this user's mailbox, with standard email delivery scanning and classification similar to receiving via SMTP. Does not send a message.", - "parameters": { - "deleted": { - "type": "boolean", - "description": "Mark the email as permanently deleted (not TRASH) and only visible in Google Vault to a Vault administrator. Only used for G Suite accounts.", - "default": "false", - "location": "query" - }, - "internalDateSource": { - "type": "string", - "description": "Source for Gmail's internal date of the message.", - "default": "dateHeader", - "enum": [ - "dateHeader", - "receivedTime" - ], - "enumDescriptions": [ - "", - "" - ], - "location": "query" - }, - "neverMarkSpam": { - "type": "boolean", - "description": "Ignore the Gmail spam classifier decision and never mark this email as SPAM in the mailbox.", - "default": "false", - "location": "query" - }, - "processForCalendar": { - "type": "boolean", - "description": "Process calendar invites in the email and add any extracted meetings to the Google Calendar for this user.", - "default": "false", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.insert", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "50MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages/import" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages/import" - } - } - } - }, - "insert": { - "id": "gmail.users.messages.insert", - "path": "{userId}/messages", - "httpMethod": "POST", - "description": "Directly inserts a message into only this user's mailbox similar to IMAP APPEND, bypassing most scanning and classification. Does not send a message.", - "parameters": { - "deleted": { - "type": "boolean", - "description": "Mark the email as permanently deleted (not TRASH) and only visible in Google Vault to a Vault administrator. Only used for G Suite accounts.", - "default": "false", - "location": "query" - }, - "internalDateSource": { - "type": "string", - "description": "Source for Gmail's internal date of the message.", - "default": "receivedTime", - "enum": [ - "dateHeader", - "receivedTime" - ], - "enumDescriptions": [ - "", - "" - ], - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.insert", - "https://www.googleapis.com/auth/gmail.modify" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "50MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages" - } - } - } - }, - "list": { - "id": "gmail.users.messages.list", - "path": "{userId}/messages", - "httpMethod": "GET", - "description": "Lists the messages in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include messages from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "labelIds": { - "type": "string", - "description": "Only return messages with labels that match all of the specified label IDs.", - "repeated": true, - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of messages to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid:\u003csomemsgid@example.com\u003e is:unread\". Parameter cannot be used when accessing the api using the gmail.metadata scope.", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListMessagesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "modify": { - "id": "gmail.users.messages.modify", - "path": "{userId}/messages/{id}/modify", - "httpMethod": "POST", - "description": "Modifies the labels on the specified message.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to modify.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "ModifyMessageRequest" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "send": { - "id": "gmail.users.messages.send", - "path": "{userId}/messages/send", - "httpMethod": "POST", - "description": "Sends the specified message to the recipients in the To, Cc, and Bcc headers.", - "parameters": { - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Message" - }, - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.compose", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.send" - ], - "supportsMediaUpload": true, - "mediaUpload": { - "accept": [ - "message/rfc822" - ], - "maxSize": "35MB", - "protocols": { - "simple": { - "multipart": true, - "path": "/upload/gmail/v1/users/{userId}/messages/send" - }, - "resumable": { - "multipart": true, - "path": "/resumable/upload/gmail/v1/users/{userId}/messages/send" - } - } - } - }, - "trash": { - "id": "gmail.users.messages.trash", - "path": "{userId}/messages/{id}/trash", - "httpMethod": "POST", - "description": "Moves the specified message to the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "untrash": { - "id": "gmail.users.messages.untrash", - "path": "{userId}/messages/{id}/untrash", - "httpMethod": "POST", - "description": "Removes the specified message from the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the message to remove from Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Message" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - }, - "resources": { - "attachments": { - "methods": { - "get": { - "id": "gmail.users.messages.attachments.get", - "path": "{userId}/messages/{messageId}/attachments/{id}", - "httpMethod": "GET", - "description": "Gets the specified message attachment.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the attachment.", - "required": true, - "location": "path" - }, - "messageId": { - "type": "string", - "description": "The ID of the message containing the attachment.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "messageId", - "id" - ], - "response": { - "$ref": "MessagePartBody" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - } - } - } - } - }, - "settings": { - "methods": { - "getAutoForwarding": { - "id": "gmail.users.settings.getAutoForwarding", - "path": "{userId}/settings/autoForwarding", - "httpMethod": "GET", - "description": "Gets the auto-forwarding setting for the specified account.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "AutoForwarding" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getImap": { - "id": "gmail.users.settings.getImap", - "path": "{userId}/settings/imap", - "httpMethod": "GET", - "description": "Gets IMAP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ImapSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getPop": { - "id": "gmail.users.settings.getPop", - "path": "{userId}/settings/pop", - "httpMethod": "GET", - "description": "Gets POP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "PopSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "getVacation": { - "id": "gmail.users.settings.getVacation", - "path": "{userId}/settings/vacation", - "httpMethod": "GET", - "description": "Gets vacation responder settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "VacationSettings" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updateAutoForwarding": { - "id": "gmail.users.settings.updateAutoForwarding", - "path": "{userId}/settings/autoForwarding", - "httpMethod": "PUT", - "description": "Updates the auto-forwarding setting for the specified account. A verified forwarding address must be specified when auto-forwarding is enabled.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "AutoForwarding" - }, - "response": { - "$ref": "AutoForwarding" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "updateImap": { - "id": "gmail.users.settings.updateImap", - "path": "{userId}/settings/imap", - "httpMethod": "PUT", - "description": "Updates IMAP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "ImapSettings" - }, - "response": { - "$ref": "ImapSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updatePop": { - "id": "gmail.users.settings.updatePop", - "path": "{userId}/settings/pop", - "httpMethod": "PUT", - "description": "Updates POP settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "PopSettings" - }, - "response": { - "$ref": "PopSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "updateVacation": { - "id": "gmail.users.settings.updateVacation", - "path": "{userId}/settings/vacation", - "httpMethod": "PUT", - "description": "Updates vacation responder settings.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "VacationSettings" - }, - "response": { - "$ref": "VacationSettings" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - }, - "resources": { - "delegates": { - "methods": { - "create": { - "id": "gmail.users.settings.delegates.create", - "path": "{userId}/settings/delegates", - "httpMethod": "POST", - "description": "Adds a delegate with its verification status set directly to accepted, without sending any verification email. The delegate user must be a member of the same G Suite organization as the delegator user.\n\nGmail imposes limtations on the number of delegates and delegators each user in a G Suite organization can have. These limits depend on your organization, but in general each user can have up to 25 delegates and up to 10 delegators.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nAlso note that when a new delegate is created, there may be up to a one minute delay before the new delegate is available for use.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Delegate" - }, - "response": { - "$ref": "Delegate" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.delegates.delete", - "path": "{userId}/settings/delegates/{delegateEmail}", - "httpMethod": "DELETE", - "description": "Removes the specified delegate (which can be of any verification status), and revokes any verification that may have been required for using it.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "delegateEmail": { - "type": "string", - "description": "The email address of the user to be removed as a delegate.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "delegateEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.delegates.get", - "path": "{userId}/settings/delegates/{delegateEmail}", - "httpMethod": "GET", - "description": "Gets the specified delegate.\n\nNote that a delegate user must be referred to by their primary email address, and not an email alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "delegateEmail": { - "type": "string", - "description": "The email address of the user whose delegate relationship is to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "delegateEmail" - ], - "response": { - "$ref": "Delegate" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.delegates.list", - "path": "{userId}/settings/delegates", - "httpMethod": "GET", - "description": "Lists the delegates for the specified account.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListDelegatesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "filters": { - "methods": { - "create": { - "id": "gmail.users.settings.filters.create", - "path": "{userId}/settings/filters", - "httpMethod": "POST", - "description": "Creates a filter.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "Filter" - }, - "response": { - "$ref": "Filter" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "delete": { - "id": "gmail.users.settings.filters.delete", - "path": "{userId}/settings/filters/{id}", - "httpMethod": "DELETE", - "description": "Deletes a filter.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the filter to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "get": { - "id": "gmail.users.settings.filters.get", - "path": "{userId}/settings/filters/{id}", - "httpMethod": "GET", - "description": "Gets a filter.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the filter to be fetched.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Filter" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.filters.list", - "path": "{userId}/settings/filters", - "httpMethod": "GET", - "description": "Lists the message filters of a Gmail user.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListFiltersResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "forwardingAddresses": { - "methods": { - "create": { - "id": "gmail.users.settings.forwardingAddresses.create", - "path": "{userId}/settings/forwardingAddresses", - "httpMethod": "POST", - "description": "Creates a forwarding address. If ownership verification is required, a message will be sent to the recipient and the resource's verification status will be set to pending; otherwise, the resource will be created with verification status set to accepted.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "ForwardingAddress" - }, - "response": { - "$ref": "ForwardingAddress" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.forwardingAddresses.delete", - "path": "{userId}/settings/forwardingAddresses/{forwardingEmail}", - "httpMethod": "DELETE", - "description": "Deletes the specified forwarding address and revokes any verification that may have been required.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "forwardingEmail": { - "type": "string", - "description": "The forwarding address to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "forwardingEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.forwardingAddresses.get", - "path": "{userId}/settings/forwardingAddresses/{forwardingEmail}", - "httpMethod": "GET", - "description": "Gets the specified forwarding address.", - "parameters": { - "forwardingEmail": { - "type": "string", - "description": "The forwarding address to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "forwardingEmail" - ], - "response": { - "$ref": "ForwardingAddress" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.forwardingAddresses.list", - "path": "{userId}/settings/forwardingAddresses", - "httpMethod": "GET", - "description": "Lists the forwarding addresses for the specified account.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListForwardingAddressesResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - } - } - }, - "sendAs": { - "methods": { - "create": { - "id": "gmail.users.settings.sendAs.create", - "path": "{userId}/settings/sendAs", - "httpMethod": "POST", - "description": "Creates a custom \"from\" send-as alias. If an SMTP MSA is specified, Gmail will attempt to connect to the SMTP service to validate the configuration before creating the alias. If ownership verification is required for the alias, a message will be sent to the email address and the resource's verification status will be set to pending; otherwise, the resource will be created with verification status set to accepted. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "delete": { - "id": "gmail.users.settings.sendAs.delete", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "DELETE", - "description": "Deletes the specified send-as alias. Revokes any verification that may have been required for using it.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be deleted.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.sendAs.get", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "GET", - "description": "Gets the specified send-as alias. Fails with an HTTP 404 error if the specified address is not a member of the collection.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be retrieved.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "list": { - "id": "gmail.users.settings.sendAs.list", - "path": "{userId}/settings/sendAs", - "httpMethod": "GET", - "description": "Lists the send-as aliases for the specified account. The result includes the primary send-as address associated with the account as well as any custom \"from\" aliases.", - "parameters": { - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListSendAsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic" - ] - }, - "patch": { - "id": "gmail.users.settings.sendAs.patch", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "PATCH", - "description": "Updates a send-as alias. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nAddresses other than the primary address for the account can only be updated by service account clients that have been delegated domain-wide authority. This method supports patch semantics.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be updated.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "update": { - "id": "gmail.users.settings.sendAs.update", - "path": "{userId}/settings/sendAs/{sendAsEmail}", - "httpMethod": "PUT", - "description": "Updates a send-as alias. If a signature is provided, Gmail will sanitize the HTML before saving it with the alias.\n\nAddresses other than the primary address for the account can only be updated by service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be updated.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SendAs" - }, - "response": { - "$ref": "SendAs" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "verify": { - "id": "gmail.users.settings.sendAs.verify", - "path": "{userId}/settings/sendAs/{sendAsEmail}/verify", - "httpMethod": "POST", - "description": "Sends a verification email to the specified send-as alias address. The verification status must be pending.\n\nThis method is only available to service account clients that have been delegated domain-wide authority.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The send-as alias to be verified.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "User's email address. The special value \"me\" can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - } - }, - "resources": { - "smimeInfo": { - "methods": { - "delete": { - "id": "gmail.users.settings.sendAs.smimeInfo.delete", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}", - "httpMethod": "DELETE", - "description": "Deletes the specified S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "get": { - "id": "gmail.users.settings.sendAs.smimeInfo.get", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}", - "httpMethod": "GET", - "description": "Gets the specified S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "response": { - "$ref": "SmimeInfo" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "insert": { - "id": "gmail.users.settings.sendAs.smimeInfo.insert", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo", - "httpMethod": "POST", - "description": "Insert (upload) the given S/MIME config for the specified send-as alias. Note that pkcs12 format is required for the key.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "request": { - "$ref": "SmimeInfo" - }, - "response": { - "$ref": "SmimeInfo" - }, - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "list": { - "id": "gmail.users.settings.sendAs.smimeInfo.list", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo", - "httpMethod": "GET", - "description": "Lists S/MIME configs for the specified send-as alias.", - "parameters": { - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail" - ], - "response": { - "$ref": "ListSmimeInfoResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - }, - "setDefault": { - "id": "gmail.users.settings.sendAs.smimeInfo.setDefault", - "path": "{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}/setDefault", - "httpMethod": "POST", - "description": "Sets the default S/MIME config for the specified send-as alias.", - "parameters": { - "id": { - "type": "string", - "description": "The immutable ID for the SmimeInfo.", - "required": true, - "location": "path" - }, - "sendAsEmail": { - "type": "string", - "description": "The email address that appears in the \"From:\" header for mail sent using this alias.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "sendAsEmail", - "id" - ], - "scopes": [ - "https://www.googleapis.com/auth/gmail.settings.basic", - "https://www.googleapis.com/auth/gmail.settings.sharing" - ] - } - } - } - } - } - } - }, - "threads": { - "methods": { - "delete": { - "id": "gmail.users.threads.delete", - "path": "{userId}/threads/{id}", - "httpMethod": "DELETE", - "description": "Immediately and permanently deletes the specified thread. This operation cannot be undone. Prefer threads.trash instead.", - "parameters": { - "id": { - "type": "string", - "description": "ID of the Thread to delete.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "scopes": [ - "https://mail.google.com/" - ] - }, - "get": { - "id": "gmail.users.threads.get", - "path": "{userId}/threads/{id}", - "httpMethod": "GET", - "description": "Gets the specified thread.", - "parameters": { - "format": { - "type": "string", - "description": "The format to return the messages in.", - "default": "full", - "enum": [ - "full", - "metadata", - "minimal" - ], - "enumDescriptions": [ - "", - "", - "" - ], - "location": "query" - }, - "id": { - "type": "string", - "description": "The ID of the thread to retrieve.", - "required": true, - "location": "path" - }, - "metadataHeaders": { - "type": "string", - "description": "When given and format is METADATA, only include headers specified.", - "repeated": true, - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "list": { - "id": "gmail.users.threads.list", - "path": "{userId}/threads", - "httpMethod": "GET", - "description": "Lists the threads in the user's mailbox.", - "parameters": { - "includeSpamTrash": { - "type": "boolean", - "description": "Include threads from SPAM and TRASH in the results.", - "default": "false", - "location": "query" - }, - "labelIds": { - "type": "string", - "description": "Only return threads with labels that match all of the specified label IDs.", - "repeated": true, - "location": "query" - }, - "maxResults": { - "type": "integer", - "description": "Maximum number of threads to return.", - "default": "100", - "format": "uint32", - "location": "query" - }, - "pageToken": { - "type": "string", - "description": "Page token to retrieve a specific page of results in the list.", - "location": "query" - }, - "q": { - "type": "string", - "description": "Only return threads matching the specified query. Supports the same query format as the Gmail search box. For example, \"from:someuser@example.com rfc822msgid: is:unread\". Parameter cannot be used when accessing the api using the gmail.metadata scope.", - "location": "query" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId" - ], - "response": { - "$ref": "ListThreadsResponse" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.metadata", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly" - ] - }, - "modify": { - "id": "gmail.users.threads.modify", - "path": "{userId}/threads/{id}/modify", - "httpMethod": "POST", - "description": "Modifies the labels applied to the thread. This applies to all messages in the thread.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to modify.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "request": { - "$ref": "ModifyThreadRequest" - }, - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "trash": { - "id": "gmail.users.threads.trash", - "path": "{userId}/threads/{id}/trash", - "httpMethod": "POST", - "description": "Moves the specified thread to the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - }, - "untrash": { - "id": "gmail.users.threads.untrash", - "path": "{userId}/threads/{id}/untrash", - "httpMethod": "POST", - "description": "Removes the specified thread from the trash.", - "parameters": { - "id": { - "type": "string", - "description": "The ID of the thread to remove from Trash.", - "required": true, - "location": "path" - }, - "userId": { - "type": "string", - "description": "The user's email address. The special value me can be used to indicate the authenticated user.", - "default": "me", - "required": true, - "location": "path" - } - }, - "parameterOrder": [ - "userId", - "id" - ], - "response": { - "$ref": "Thread" - }, - "scopes": [ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - } - } - } - } - } -} -__END -} \ No newline at end of file diff --git a/t/04-no-method.t b/t/04-no-method.t new file mode 100644 index 0000000..51508ef --- /dev/null +++ b/t/04-no-method.t @@ -0,0 +1,27 @@ +use Test2::V0; +use lib 't/lib'; +use TestTools qw/gapi_json DEBUG user/; +use WebService::GoogleAPI::Client; + +my $gapi = WebService::GoogleAPI::Client->new( + debug => DEBUG, gapi_json => gapi_json, user => user); + +ok dies { + $gapi->_process_params({ + api_endpoint_id => 'jobs.non.existant', + options => { + fields => 'your(fez)' + } + }) +}, 'blows up if an endpoint does not exist'; + +ok dies { + $gapi->_process_params({ + api_endpoint_id => 'i.am.non.existant', + options => { + fields => 'your(fez)' + } + }) +}, 'blows up if an API does not exist'; + +done_testing; diff --git a/t/05-spec-interpolation.t b/t/05-spec-interpolation.t new file mode 100644 index 0000000..a40ea95 --- /dev/null +++ b/t/05-spec-interpolation.t @@ -0,0 +1,135 @@ +use strict; +use warnings; +use Test2::V0; + +use lib 't/lib'; +use TestTools qw/DEBUG gapi_json user/; +use WebService::GoogleAPI::Client; + +my $gapi = WebService::GoogleAPI::Client->new( + debug => DEBUG, gapi_json => gapi_json, user => user); + +my $options = { + api_endpoint_id => 'drive.files.list', + options => { + fields => 'files(id,name,parents)' + } +}; + +sub build_req { + $gapi->_process_params(shift); +} + +build_req($options); +is $options->{path}, +'https://www.googleapis.com/drive/v3/files?fields=files%28id%2Cname%2Cparents%29', +'Can interpolate globally available query parameters'; + +$options = { + api_endpoint_id => "sheets:v4.spreadsheets.values.update", + options => { + spreadsheetId => 'sner', + includeValuesInResponse => 'true', + valueInputOption => 'RAW', + range => 'Sheet1!A1:A2', + 'values' => [[99],[98]] + }, + cb_method_discovery_modify => sub { + my $meth_spec = shift; + $meth_spec->{parameters}{valueInputOption}{location} = 'path'; + $meth_spec->{path} .= "?valueInputOption={valueInputOption}"; + return $meth_spec; + } +}; + +build_req($options); + +is $options->{path}, 'https://sheets.googleapis.com/v4/spreadsheets/sner/values/Sheet1!A1:A2?valueInputOption=RAW&includeValuesInResponse=true', +'interpolation works with user fiddled path, too'; + +$options = { + api_endpoint_id => "sheets:v4.spreadsheets.values.batchGet", + options => { + spreadsheetId => 'sner', + ranges => ['Sheet1!A1:A2', 'Sheet1!A3:B5'], + }, +}; +build_req($options); +is $options->{path}, +'https://sheets.googleapis.com/v4/spreadsheets/sner/values:batchGet?ranges=Sheet1%21A1%3AA2&ranges=Sheet1%21A3%3AB5', +'interpolates arrayref correctly' ; + +subtest 'funky stuff in the jobs api' => sub { + my $endpoint = 'jobs.projects.tenants.jobs.delete'; + + subtest 'Testing {+param} type interpolation options' => sub { + my @errors; + my $interpolated = 'https://jobs.googleapis.com/v4/projects/sner/tenants/your-fez/jobs'; + + $options = { + api_endpoint_id => $endpoint, + options => { + name => 'projects/sner/tenants/your-fez/jobs/bler' + } + }; + @errors = $gapi->_process_params( $options ); + is $options->{path}, "$interpolated/bler", + 'Interpolates a {+param} that matches the spec pattern', @errors; + + $options->{options} = {projectsId => 'sner', jobsId => 'bler'}; + @errors = $gapi->_process_params( $options ); + + is $options->{path}, "$interpolated/bler", + 'Interpolates params that match the flatName spec (camelCase)', @errors; + + $options->{options} = {projects_id => 'sner', jobs_id => 'bler'}; + @errors = $gapi->_process_params( $options ); + + is $options->{path}, "$interpolated/bler", + 'Interpolates params that match the names in the api description (snake_case)', + @errors; + + $options = { + api_endpoint_id => 'jobs.projects.tenants.list', + options => { parent => 'sner' } + }; + @errors = $gapi->_process_params( $options ); + is $options->{path}, $interpolated =~ s+/your-fez.*$++r, + 'Interpolates just the dynamic part of the {+param}, when not matching the spec pattern', + @errors; + }; + + + subtest 'Checking for proper failure with {+params} in unsupported ways' => sub { + my @errors; + $options = { + api_endpoint_id => $endpoint, + options => { name => 'sner' } + }; + @errors = $gapi->_process_params( $options ); + is $errors[0], 'Not enough parameters given for {+name}.', + "Fails if you don't supply enough values to fill the dynamic parts of {+param}"; + + $options = { + api_endpoint_id => 'jobs.projects.tenants.jobs.list', + options => { parent => 'sner' } + }; + @errors = $gapi->_process_params( $options ); + is $errors[0], 'Not enough parameters given for {+parent}.', + "Fails if you don't supply enough values to fill the dynamic parts of {+param}"; + + $options = { + api_endpoint_id => $endpoint, + options => { jobsId => 'sner' } + }; + @errors = $gapi->_process_params( $options ); + is $errors[0], 'Missing a parameter for {projectsId}.', + "Fails if you don't supply enough values to fill the flatPath"; + }; + +}; + + + + +done_testing; diff --git a/t/01-client-discovery.t b/t/WebService/GoogleAPI/Client/Discovery.t similarity index 66% rename from t/01-client-discovery.t rename to t/WebService/GoogleAPI/Client/Discovery.t index 4241aaf..bc799b2 100755 --- a/t/01-client-discovery.t +++ b/t/WebService/GoogleAPI/Client/Discovery.t @@ -1,64 +1,255 @@ -#!perl -T +#!/usr/bin/env perl -=head2 USAGE +use strict; +use warnings; +use Test2::V0; +use CHI; +use Mojo::File qw/tempdir/; -To run manually in the local directory assuming gapi.json present in source root and in xt/author/calendar directory - C +use lib 't/lib'; +use TestTools qw/has_credentials set_credentials DEBUG/; -NB: is also run as part of dzil test +use WebService::GoogleAPI::Client; +use WebService::GoogleAPI::Client::Discovery; -=cut +my $package = 'WebService::GoogleAPI::Client::Discovery'; +my $tmp = tempdir; +my $cache = CHI->new(driver => 'File', root_dir => $tmp->to_string); -use 5.006; -use strict; -use warnings; -use Test::More; -use Data::Dumper; ## remove this when finish tweaking -use Cwd; -use CHI; +ok my $disco = WebService::GoogleAPI::Client::Discovery->new(chi => $cache), 'instanciation works'; -my $dir = getcwd; -my $DEBUG = 0; ## to see noise of class debugging +subtest 'WebService::GoogleAPI::Client::Discovery class properties' => sub { + #TODO- these tests are stupid, ne? bakajanaikana? + is ref($disco->ua), 'WebService::GoogleAPI::Client::UserAgent', + 'ua property is of type WebService::GoogleAPI::Client::UserAgent'; + like ref($disco->chi), qr/^CHI::Driver/xm, + 'chi property (WebService::GoogleAPI::Client::Discovery->new->chi) is of sub-type CHI::Driver::'; -use_ok( 'WebService::GoogleAPI::Client' ); # || print "Bail out!\n"; -use_ok( 'WebService::GoogleAPI::Client::Discovery' ); + note( "SESSION DEFAULT CHI Root Directory = " . $disco->chi->root_dir ); + is $disco->debug, '0', 'debug property defaults to 0'; +}; +$disco->debug(DEBUG); + +#TODO- mock away the actual get request... +# will prevent the occasional flake on this in the future +subtest 'discover_all' => sub { + subtest 'hits the wire with no cache' => sub { + like $disco->discover_all->{items}, bag { + item hash { + field kind => "discovery#directoryItem"; + field id => "gmail:v1"; + field name => "gmail"; + field version => "v1"; + field title => "Gmail API"; + etc; + }; + etc; + }, 'got a reasonable discovery document'; + like $disco->stats, { + cache => { get => 0 }, + network => { get => 1 } + }, 'used the network'; + }; + + subtest 'uses cache if available' => sub { + like $disco->discover_all->{items}, bag { + item hash { + field kind => "discovery#directoryItem"; + field id => "gmail:v1"; + field name => "gmail"; + field version => "v1"; + field title => "Gmail API"; + etc; + }; + etc; + }, 'got a reasonable discovery document'; + like $disco->stats, { + cache => { get => 1 }, + network => { get => 1 } + }, 'used the cache'; + }; + + subtest 'Ignores cache if passed $force flag' => sub { + like $disco->discover_all(1)->{items}, bag { + item hash { + field kind => "discovery#directoryItem"; + field id => "gmail:v1"; + field name => "gmail"; + field version => "v1"; + field title => "Gmail API"; + etc; + }; + etc; + }, 'got a reasonable discovery document'; + like $disco->stats, { + cache => { get => 1 }, + network => { get => 2 } + }, 'used the network'; + }; + + subtest 'Ignores cache if expired' => sub { + $disco->chi->set($disco->discover_key, {}, 'now'); + like $disco->discover_all->{items}, bag { + item hash { + field kind => "discovery#directoryItem"; + field id => "gmail:v1"; + field name => "gmail"; + field version => "v1"; + field title => "Gmail API"; + etc; + }; + etc; + }, 'got a reasonable discovery document'; + + like $disco->stats, { + cache => { get => 1 }, + network => { get => 3 } + }, 'used the network'; + }; + + subtest 'Uses authenticated request when asked' => sub { + skip_all 'needs real credentials' unless has_credentials; + my $obj = $disco->new; + set_credentials($obj); + like $obj->discover_all(1,1)->{items}, bag { + item hash { + field kind => "discovery#directoryItem"; + field id => "gmail:v1"; + field name => "gmail"; + field version => "v1"; + field title => "Gmail API"; + etc; + }; + etc; + }, 'got a reasonable discovery document'; + like $obj->stats, { + network => { authorized => 1 } + }, 'used the credentials'; + }; +}; #end of discover_all subtest + +subtest 'Augmenting the api' => sub { + my $to_augment = { + 'version' => 'v4', + 'preferred' => 1, + 'title' => 'Google My Business API', + 'description' => 'The Google My Business API provides an interface for managing business location information on Google.', + 'id' => 'mybusiness:v4', + 'kind' => 'discovery#directoryItem', + 'documentationLink' => "https://developers.google.com/my-business/", + 'icons' => { + "x16"=> "http://www.google.com/images/icons/product/search-16.gif", + "x32"=> "http://www.google.com/images/icons/product/search-32.gif" + }, + 'discoveryRestUrl' => + 'https://developers.google.com/my-business/samples/mybusiness_google_rest_v4p2.json', + 'name' => 'mybusiness' + }; + + $disco->augment_with($to_augment); + like $disco->discover_all->{items}, bag { + item hash { + field $_ => $to_augment->{$_} for qw/kind id name version title/; + etc; + }; + etc; + }, 'got back what we just added'; -my $default_file = $ENV{ 'GOOGLE_TOKENSFILE' } || "$dir/../../gapi.json"; ## assumes running in a sub of the build dir by dzil -$default_file = "$dir/../gapi.json" unless -e $default_file; ## if file doesn't exist try one level up ( allows to run directly from t/ if gapi.json in parent dir ) -my $user = $ENV{ 'GMAIL_FOR_TESTING' } || ''; ## will be populated by first available if set to '' and default_file exists +}; +subtest 'checking for API availablity' => sub { + #NOTE- this is used a lot internally, so let's just make sure it + # does what we want + my $list = $disco->available_APIs; + + like $list, hash { + field gmail => hash { + field version => bag { item 'v1'; etc; }; + field documentationLink => bag { item 'https://developers.google.com/gmail/api/'; etc; }; + field discoveryRestUrl => bag { item 'https://gmail.googleapis.com/$discovery/rest?version=v1'; etc; }; + end; + }; + etc; + }, 'collapsed structure as expected'; + + subtest 'service_exists' => sub { + ok !$disco->service_exists('yourfez'), 'non-extant tells us such'; + ok $disco->service_exists('gmail'), 'verified that gmail exists'; + ok !$disco->service_exists('Gmail'), 'is case sensitive'; + ok $disco->service_exists('youtubeAnalytics'), 'gets youtube analytics'; + }; + + subtest 'available_version' => sub { + is $disco->available_versions('gmail'), [ 'v1' ], 'got gmail'; + is $disco->available_versions('GMAIL'), [], 'case sensitive gmail'; + is $disco->available_versions('firestore'), bag { item $_ for qw/v1 v1beta1 v1beta2/; end }, + 'got many versions for firestore'; + is $disco->available_versions('youtubeAnalytics'), [ 'v2' ], + 'got correct only one version for youtube analytics'; + is $disco->available_versions('yourfez'), [], 'empty for non-existant'; + }; + + subtest 'latest_stable_version' => sub { + is $disco->latest_stable_version('gmail'), 'v1', 'got for gmail'; + is $disco->latest_stable_version('compute'), 'v1', 'got for compute'; + is $disco->latest_stable_version('bigqueryreservation'), + 'v1', 'ignores alphas AND betas'; + }; + + subtest 'list_api_ids' => sub { + for my $id (qw/gmail compute bigqueryreservation/) { + like scalar($disco->list_api_ids), qr/$id/, + "has an entry for $id in scalar mode"; + like [ $disco->list_api_ids ], bag { + item $id; + etc; + }, "has an entry for $id in list mode"; + } + }; + + subtest 'process_api_version' => sub { + is $disco->process_api_version('gmail'), + { api => 'gmail', version => 'v1' }, + 'got default'; + + is $disco->process_api_version({ api => 'gmail' }), + { api => 'gmail', version => 'v1' }, + 'got default from hashref'; + + is $disco->process_api_version('gmail:v9000'), + { api => 'gmail', version => 'v9000' }, + 'take a version if given (even if imaginary)'; + + is $disco->process_api_version({ api => 'gmail', version => 'v2' }), + { api => 'gmail', version => 'v2' }, + 'take a version if given'; + + like dies { $disco->process_api_version('fleurbop') }, + qr/fleurbop .* not .* valid .* API/, 'errors on non-found api'; + }; -subtest 'WebService::GoogleAPI::Client::Discovery class properties' => sub { - ok( - ref WebService::GoogleAPI::Client::Discovery->new->ua eq 'WebService::GoogleAPI::Client::UserAgent', - 'ua property (WebService::GoogleAPI::Client::Discovery->new->ua) is of type WebService::GoogleAPI::Client::UserAgent' - ); - ok( - ref( WebService::GoogleAPI::Client::Discovery->new->chi ) =~ /^CHI::Driver/xm, - 'chi property (WebService::GoogleAPI::Client::Discovery->new->chi) is of sub-type CHI::Driver::' - ); - note( "SESSION DEFAULT CHI Root Directory = " . WebService::GoogleAPI::Client::Discovery->new()->chi->root_dir ); - ok( WebService::GoogleAPI::Client::Discovery->new->debug eq '0', 'debug property defaults to 0' ); - ok( WebService::GoogleAPI::Client::Discovery->new( debug => 1 )->debug eq '1', 'debug property when set to 1 on new returns 1' ); }; +# TODO - we need to deal with issues when you can't find a method. +# We had a bug once where google updated, but our cached discovery document +# didn't and we kept crashing b/c it couldn't find the old version that we were +# using (b/c we were relying on the default version, i think) +done_testing; -## NB - should probably skip tests that will fail when a dependent test fails -subtest 'Naked instance method tests (without Client parent container)' => sub { +__DATA__ +#we'll get back to these eventually - ok( ref( WebService::GoogleAPI::Client->new->api_query() ) eq 'Mojo::Message::Response', "WebService::GoogleAPI::Client->new->api_query() is a 'Mojo::Message::Response'" ); - ok( - WebService::GoogleAPI::Client::Discovery->new->list_of_available_google_api_ids() =~ /gmail/xm, - 'WebService::GoogleAPI::Client::Discovery->new->list_of_available_google_api_ids()' - ); +subtest 'Naked instance method tests (without Client parent container)' => sub { + subtest 'Getting api id for gmail' => sub { + like scalar($disco->list_of_available_google_api_ids), qr/gmail/xm, 'gets id from a string in scalar context'; + like [ $disco->list_of_available_google_api_ids ], bag { + item qr/gmail/; + etc; + }, 'gets it in list context too'; + }; - ok( ref( WebService::GoogleAPI::Client::Discovery->new->discover_all() ) eq 'HASH', 'WebService::GoogleAPI::Client::Discovery->new->discover_all() return HASREF' ); - ok( - ref( WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api() ) eq 'HASH', - ' WebService::GoogleAPI::Client::Discovery->new->augment_discover_all_with_unlisted_experimental_api() returns HASHREF' - ); ok( length( WebService::GoogleAPI::Client::Discovery->new->supported_as_text ) > 100, 'WebService::GoogleAPI::Client::Discovery->new->supported_as_text() returns string > 100 chars' @@ -190,7 +381,7 @@ subtest 'Discovery methods with User Configuration' => sub { #ok( ref $gapi->auth_storage->setup( { type => 'jsonfile', path => $default_file } ) eq 'WebService::GoogleAPI::Client::AuthStorage', 'auth_storage returns WebService::GoogleAPI::Client::AuthStorage'); ok( my $gapi = WebService::GoogleAPI::Client->new( debug => $DEBUG, gapi_json => $default_file ), 'Creating test session instance of WebService::GoogleAPI::Client' ); - ok( my $aref_token_emails = $gapi->auth_storage->storage->get_token_emails_from_storage, 'Load token emails from config' ); + ok( my $aref_token_emails = $gapi->auth_storage->get_token_emails_from_storage, 'Load token emails from config' ); if ( !$user ) ## default to the first user in config file if none defined yet { ok( $user = $aref_token_emails->[0], "setting test user to first configured entry in config - '$user'" ); @@ -204,10 +395,8 @@ subtest 'Discovery methods with User Configuration' => sub { ok( $gapi->user( $user ) eq $user, "\$gapi->user('$user') eq '$user'" ); -#$ENV{CHI_FILE_PATH} = $ENV{TMPDIR}; plan( skip_all => 'Skipping network impacting tests unless ENV VAR CHI_FILE_PATH is set' ) unless defined $ENV{ CHI_FILE_PATH }; - ok( my $chi = CHI->new( driver => 'File', @@ -234,7 +423,7 @@ subtest 'Discovery methods with User Configuration' => sub { ## ensure that tests don't fail when Google blocks discovery requests for unauthenticated users ## due to exceeding access limits. - ## DISCOVERY ALL - RETURNS THE DESCIVOERY STRUCTURE DESCRIBING ALL GOOGLE SERVICE API ID's (gmail,calendar etc) + ## DISCOVERY ALL - RETURNS THE DISCOVERY STRUCTURE DESCRIBING ALL GOOGLE SERVICE API ID's (gmail,calendar etc) #ok( my $ret = WebService::GoogleAPI::Client->new( chi => $chi )->discovery->new->discover_all, 'WebService::GoogleAPI::Client::Discovery->new->discover_all returns something'); ok( ref( $gapi->discover_all ) eq 'HASH', 'Client->discover_all returns HASHREF' ); ok( join( ',', sort keys( %{ WebService::GoogleAPI::Client::Discovery->new->discover_all() } ) ) eq 'discoveryVersion,items,kind', @@ -260,7 +449,7 @@ subtest 'Discovery methods with User Configuration' => sub { ok( keys %{ $gapi->extract_method_discovery_detail_from_api_spec( 'not-a-google-service.list' ) } == 0, "WebService::GoogleAPI::Client->extract_method_discovery_detail_from_api_spec('not-a-google-service.list') returns empty hashref" ); - ok( scalar( [$gapi->get_scopes_as_array()] ) > 0, 'more than 0 scopes returned from config' ); + ok @$gapi->scopes + 0, 'more than 0 scopes returned from config'; ok( $gapi->has_scope_to_access_api_endpoint( "gmail.users.messages.send" ) =~ /^0|1$/xmg, 'has_scope_to_access_api_endpoint("gmail.users.messages.send") returns either 0 or 1' diff --git a/t/gapi.json b/t/gapi.json index eb51aa4..89462fa 100644 --- a/t/gapi.json +++ b/t/gapi.json @@ -2,7 +2,7 @@ "gapi" : { "client_id" : "mocked.apps.googleusercontent.com", "client_secret" : "6iQ5pFYLgsssssssssssssssssssss", - "scopes" : "email profile https://www.googleapis.com/auth/plus.profile.emails.read https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/contacts.readonly https://mail.google.com", + "scopes" : "email profile https://www.googleapis.com/auth/plus.profile.emails.read https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/contacts.readonly https://mail.google.com https://www.googleapis.com/auth/jobs https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive", "tokens" : { "peter@shotgundriver.com" : { "access_token" : "ya29.GltBBsl56Dd-drJHt3MfpuRkp7A3cwVJy--areTiZvSlHdsfdsjkfdsjkfdskfjaii--------mocked--------------------", diff --git a/t/lib/TestTools.pm b/t/lib/TestTools.pm new file mode 100644 index 0000000..8258ee7 --- /dev/null +++ b/t/lib/TestTools.pm @@ -0,0 +1,31 @@ +package TestTools; +use strict; +use warnings; + +use Exporter::Shiny qw/ gapi_json DEBUG user has_credentials set_credentials/; +use Mojo::File qw/curfile path/; +use WebService::GoogleAPI::Client::AuthStorage::GapiJSON; + +my $gapi; +#try and find a good gapi.json to use here. Check as follows: +# for sanity, we only use the fake gapi.json in the t/ directory unless the user +# explicitly gives a GOOGLE_TOKENSFILE +$gapi = path($ENV{GOOGLE_TOKENSFILE} || curfile->dirname->sibling('gapi.json')); + +sub gapi_json { + return "$gapi"; +} +sub user { $ENV{GMAIL_FOR_TESTING} // 'peter@shotgundriver.com' } + +sub has_credentials { $gapi->stat && user } +sub set_credentials { + my ($obj) = @_; + my $storage = WebService::GoogleAPI::Client::AuthStorage::GapiJSON->new( + path => "$gapi", user => user); + $obj->ua->auth_storage($storage); +} + + +sub DEBUG { $ENV{GAPI_DEBUG_LEVEL} // 0 } + +9033 diff --git a/t/manifest.t b/t/manifest.t index 10e775b..701c00d 100755 --- a/t/manifest.t +++ b/t/manifest.t @@ -1,4 +1,4 @@ -#!perl -T +#!perl use 5.006; use strict; use warnings; diff --git a/t/pod.t b/t/pod.t index 5950ec1..3237e0b 100755 --- a/t/pod.t +++ b/t/pod.t @@ -1,4 +1,4 @@ -#!perl -T +#!perl use 5.006; use strict; use warnings; diff --git a/weaver.ini b/weaver.ini new file mode 100644 index 0000000..7223daf --- /dev/null +++ b/weaver.ini @@ -0,0 +1,4 @@ +[@Default] + +[-Transformer] +transformer = List diff --git a/xt/live_test.t b/xt/live_test.t new file mode 100644 index 0000000..341fd03 --- /dev/null +++ b/xt/live_test.t @@ -0,0 +1,62 @@ +use Test2::V0; +use Test2::Tools::Spec; + +# TODO - make a simple test which creates a file, lists it, then deletes it, for +# both a service account and a regular account. + +use WebService::GoogleAPI::Client; + +bail_out <new( + gapi_json => $path, user => $email +); + +my $s = WebService::GoogleAPI::Client->new( + service_account => $service_creds, + scopes => [ 'https://www.googleapis.com/auth/drive' ] +); + +my $filename = 'a-rather-unlikely-named-file-for-xt-testing'; + +describe 'file creation and deletion' => sub { + my $ua; + case 'user account' => sub { $ua = $u }; + case 'service account' => sub { $ua = $s }; + + tests 'doing it' => sub { + my $res = $ua->api_query({ + api_endpoint_id => 'drive.files.create', + options => { name => $filename } + }); + + is $res->json('/name'), $filename, 'request worked'; + my $id = $res->json('/id'); + + $res = $ua->api_query({ + api_endpoint_id => 'drive.files.delete', + options => { fileId => $id } + }); + + is $res->code, 204, 'delete went as planned'; + }; +}; + + +done_testing;