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