NAME
WebService::GoogleAPI::Client - Google API Discovery and SDK
VERSION
version 0.21
SYNOPSIS
Access Google API Services Version 1 using an OAUTH2 User Agent.
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_
use WebService::GoogleAPI::Client;
my $gapi_client = WebService::GoogleAPI::Client->new( debug => 1, gapi_json => 'gapi.json', user=> 'peter@pscott.com.au' );
say $gapi_client->list_of_available_google_api_ids();
my @gmail_endpoint_list = $gapi_client->methods_available_for_google_api_id('gmail')
if $gapi_agent->has_scope_to_access_api_endpoint( 'gmail.users.settings.sendAs.get' ) {
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 go_auth CLI Script to collect initial end-user authorisation to scoped services
EXAMPLES
AUTOMATIC API REQUEST CONSTRUCTION - SEND EMAL
## using dotted API Endpoint id to invoke helper validation and default value interpolations etc to send email to self
use Email::Simple; ## RFC2822 formatted messages
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
);
$gapi_client->api_query(
api_endpoint_id => 'gmail.users.messages.send',
options => { raw => $raw_email_payload },
);
MANUAL API REQUEST CONSTRUCTION - GET CALENDAR LIST
## Completely manually constructed API End-Point Request to obtain Perl Data Structure converted from JSON response.
my $res = $gapi_client->api_query(
method => 'get',
path => 'https://www.googleapis.com/calendar/users/me/calendarList',
)->json;
METHODS
new
WebService::GoogleAPI::Client->new( user => 'peter@pscott.com.au', gapi_json => '/fullpath/gapi.json' );
PARAMETERS
user :: the email address that identifies key of credentials in the config file
gapi_json :: Location of the configuration credentials - default gapi.json
debug :: if '1' then diagnostics are send to STDERR - default false
chi :: an instance to a CHI persistent storage case object - if none provided FILE is used
api_query
query Google API with option to validate request before submitting
handles user auth token inclusion in request headers and refreshes token if required and possible
Required params: method, route
Optional params: api_endpoint_id cb_method_discovery_modify
$self->access_token must be valid
$gapi->api_query({
method => 'get',
path => 'https://www.googleapis.com/calendar/users/me/calendarList',
});
$gapi->api_query({
method => 'post',
path => 'https://www.googleapis.com/calendar/v3/calendars/'.$calendar_id.'/events',
options => { key => value }
}
## 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; ##
print $gapi_agent->api_query(
api_endpoint_id => 'gmail.users.messages.list', ## auto sets method to GET, path to 'https://www.googleapis.com/calendar'
)->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 ;^) ).
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 )
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.
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;
}
);
Returns Mojo::Message::Response object
has_scope_to_access_api_endpoint
Given an API Endpoint such as 'gmail.users.settings.sendAs.get' returns 1 iff user has scope to access
say 'User has Access' if $gapi_agent->has_scope_to_access_api_endpoint( 'gmail.users.settings.sendAs.get' );
Returns 0 if scope to access is not available to the user.
warns and returns 0 on error ( eg user or config not specified etc )
METHODS DELEGATED TO WebService::GoogleAPI::Client::Discovery
discover_all
Return details about all Available Google APIs as provided by Google or in CHI Cache
On Success: Returns HASHREF containing items key => list of hashes describing each API
On Failure: Warns and returns empty hashref
my $client = WebService::GoogleAPI::Client->new; ## has discovery member WebService::GoogleAPI::Client::Discovery
$d = $client->discover_all();
$d = $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
## OR
$d = $client->discovery-> discover_all();
$d = WebService::GoogleAPI::Client::Discovery->discover_all();
print Dumper $d;
$VAR1 = {
'items' => [
{
'preferred' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
'id' => 'abusiveexperiencereport:v1',
'icons' => {
'x32' => 'https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png',
'x16' => 'https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png'
},
'version' => 'v1',
'documentationLink' => 'https://developers.google.com/abusive-experience-report/',
'kind' => 'discovery#directoryItem',
'discoveryRestUrl' => 'https://abusiveexperiencereport.googleapis.com/$discovery/rest?version=v1',
'title' => 'Abusive Experience Report API',
'name' => 'abusiveexperiencereport',
'description' => 'Views Abusive Experience Report data, and gets a list of sites that have a significant number of abusive experiences.'
}, ...
## NB because the structure isn't indexed on the api name it can be convenient to post-process it
##
my $new_hash = {};
foreach my $api ( @{ %{$client->discover_all()}{items} } )
{
# convert JSON::PP::Boolean to true|false strings
$api->{preferred} = "$api->{preferred}" if defined $api->{preferred};
$api->{preferred} = $api->{preferred} eq '0' ? 'false' : 'true';
$new_hash->{ $api->{name} } = $api;
}
print dump $new_hash->{gmail};
get_api_discovery_for_api_id
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' );
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.
methods_available_for_google_api_id
Returns a hashref keyed on the Google service API Endpoint in dotted format. The hashed content contains a structure representing the corresponding discovery specification for that method ( API Endpoint ).
methods_available_for_google_api_id('gmail')
extract_method_discovery_detail_from_api_spec
$my $api_detail = $gapi->discovery->extract_method_discovery_detail_from_api_spec( '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
list_of_available_google_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();
print "List of API Services ( comma separated): $r\n";
my @list = $agent->list_of_available_google_api_ids();
FEATURES
API Discovery requests cached with CHI ( Default File )
OAUTH app and user credentials (client_id, client_secret, scope, users access_token and refresh_tokens) stored in local file (default name = gapi.json)
access_token auto-refreshes when expires (if user has refresh_token) saving refreshed token back to json file
helper api_query to streamline request composition without preventing manual construction if preferred.
CLI tool (goauth) with lightweight Mojo HTTP server to simplify OAuth2 configuration, sccoping, authorization and obtaining access_ and refresh_ tokens from users
AUTHOR
Peter Scott <localshop@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2017-2018 by Peter Scott and others.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004