view release on metacpan or search on metacpan
Once you have successfully created your OAuth2 token, you can run the tutorials
to ensure everything is working correctly. Set the environment variable
`GOOGLE_RESTAPI_CONFIG` to the path to your auth config file. See the
`tutorial/` directory for step-by-step tutorials covering Sheets, Drive,
Calendar, Documents, Gmail, and Tasks. These will help you understand how the
API interacts with Google.
## Chained API Calls
Every Google API module has an `api()` method. Sub-resource objects
(see [Google::RestApi::SubResource](https://metacpan.org/pod/Google%3A%3ARestApi%3A%3ASubResource)) don't call the Google endpoint
directly; instead, each `api()` prepends its own URI segment and
delegates to its parent's `api()`. The calls chain upward until they
reach the top-level API module (e.g. DriveApi3), which prepends the
endpoint base URL and hands the fully-assembled URI to
`Google::RestApi` for the actual HTTP request.
For example, deleting a reply on a comment on a file produces this chain:
$reply->api(method => 'delete')
# Reply prepends "replies/$reply_id"
-> $comment->api(uri => "replies/$reply_id", method => 'delete')
# Comment prepends "comments/$comment_id"
-> $file->api(uri => "comments/$comment_id/replies/$reply_id", ...)
# File prepends "files/$file_id"
auth:
class: OAuth2Client
config_file: <path_to_oauth_config_file>
This allows you the option to keep the auth file in a separate, more secure place.
- api(%args);
The ultimate Google API call for the underlying classes. Handles timeouts and retries etc. %args consists of:
- `uri` <uri\_string>: The Google API endpoint such as https://www.googleapis.com/drive/v3 along with any path segments added.
- `method` <http\_method\_string>: The http method being used get|head|put|patch|post|delete.
- `headers` <headers\_string\_array>: Array ref of http headers.
- `params` <query\_parameters\_hash>: Http query params to be added to the uri.
- `content` <payload hash>: The body being sent for post/put etc. Will be encoded to JSON.
You would not normally call this directly unless you were making a Google API call not currently supported by this API framework.
Returns the response hash from Google API.
- api\_callback(<coderef>);
lib/Google/RestApi.pm view on Meta::CPAN
if ($self->{log4perl_config} && !Log::Log4perl->initialized()) {
Log::Log4perl->init($self->{log4perl_config});
}
$self->{ua} = Furl->new(timeout => $self->{timeout});
return bless $self, $class;
}
# this is the actual call to the google api endpoint. handles retries, error checking etc.
# this would normally be called via Drive or Sheets objects.
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => StrMatch[qr(^https://)],
method => StrMatch[qr/^(get|head|put|patch|post|delete)$/i], { default => 'get' },
params => HashRef[Str|ArrayRef[Str]], { default => {} }, # uri param string.
lib/Google/RestApi.pm view on Meta::CPAN
my ($transaction) = @_;
my $details = eval { $transaction->{decoded_response}{error}{details} };
return unless ref $details eq 'ARRAY';
for my $detail (@$details) {
my $url = eval { $detail->{metadata}{activationUrl} };
return $url if $url;
}
return;
}
# the maximum number of attempts to call the google api endpoint before giving up.
# undef returns current value. postitive int sets and returns new value.
# 0 sets and returns default value.
sub max_attempts {
my $self = shift;
state $check = signature(positional => [PositiveOrZeroInt->where(sub { $_ < 10; }), { optional => 1 }]);
my ($max_attempts) = $check->(@_);
$self->{max_attempts} = $max_attempts if $max_attempts;
$self->{max_attempts} = 4 if defined $max_attempts && $max_attempts == 0;
return $self->{max_attempts};
}
lib/Google/RestApi.pm view on Meta::CPAN
Once you have successfully created your OAuth2 token, you can run the tutorials
to ensure everything is working correctly. Set the environment variable
C<GOOGLE_RESTAPI_CONFIG> to the path to your auth config file. See the
C<tutorial/> directory for step-by-step tutorials covering Sheets, Drive,
Calendar, Documents, Gmail, and Tasks. These will help you understand how the
API interacts with Google.
=head2 Chained API Calls
Every Google API module has an C<api()> method. Sub-resource objects
(see L<Google::RestApi::SubResource>) don't call the Google endpoint
directly; instead, each C<api()> prepends its own URI segment and
delegates to its parent's C<api()>. The calls chain upward until they
reach the top-level API module (e.g. DriveApi3), which prepends the
endpoint base URL and hands the fully-assembled URI to
C<Google::RestApi> for the actual HTTP request.
For example, deleting a reply on a comment on a file produces this chain:
$reply->api(method => 'delete')
# Reply prepends "replies/$reply_id"
-> $comment->api(uri => "replies/$reply_id", method => 'delete')
# Comment prepends "comments/$comment_id"
-> $file->api(uri => "comments/$comment_id/replies/$reply_id", ...)
# File prepends "files/$file_id"
lib/Google/RestApi.pm view on Meta::CPAN
config_file: <path_to_oauth_config_file>
This allows you the option to keep the auth file in a separate, more secure place.
=item api(%args);
The ultimate Google API call for the underlying classes. Handles timeouts and retries etc. %args consists of:
=over
=item * C<uri> <uri_string>: The Google API endpoint such as https://www.googleapis.com/drive/v3 along with any path segments added.
=item * C<method> <http_method_string>: The http method being used get|head|put|patch|post|delete.
=item * C<headers> <headers_string_array>: Array ref of http headers.
=item * C<params> <query_parameters_hash>: Http query params to be added to the uri.
=item * C<content> <payload hash>: The body being sent for post/put etc. Will be encoded to JSON.
=back
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
Readonly our $Calendar_Endpoint => 'https://www.googleapis.com/calendar/v3';
Readonly our $Calendar_Id => '[a-zA-Z0-9._@-]+';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
endpoint => Str, { default => $Calendar_Endpoint },
],
);
return bless $check->(@_), $class;
}
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { optional => 1 },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = "$self->{endpoint}/";
$uri .= delete $p->{uri} if defined $p->{uri};
return $self->{api}->api(%$p, uri => $uri);
}
sub calendar {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str,
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
Creates a new CalendarApi3 instance.
my $cal_api = Google::RestApi::CalendarApi3->new(api => $rest_api);
%args consists of:
=over
=item * C<api> L<Google::RestApi>: Required. A configured RestApi instance.
=item * C<endpoint> <string>: Optional. Override the default Calendar API endpoint.
=back
=head2 api(%args)
Low-level method to make API calls. You would not normally call this directly
unless making a Google API call not currently supported by this framework.
%args consists of:
=over
=item * C<uri> <string>: Path segments to append to the Calendar endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 calendar(%args)
Returns a Calendar object for the given calendar ID.
lib/Google/RestApi/DocsApi1.pm view on Meta::CPAN
Readonly our $Document_Filter => "mimeType = 'application/vnd.google-apps.document'";
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
drive => HasMethods[qw(list)], { optional => 1 },
endpoint => Str, { default => $Docs_Endpoint },
],
);
my $self = $check->(@_);
return bless $self, $class;
}
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { default => '' },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = $self->{endpoint};
$uri .= "/$p->{uri}" if $p->{uri};
return $self->rest_api()->api(%$p, uri => $uri);
}
sub create_document {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
lib/Google/RestApi/DocsApi1.pm view on Meta::CPAN
my $docs_api = Google::RestApi::DocsApi1->new(api => $rest_api);
%args consists of:
=over
=item * C<api> L<Google::RestApi>: Required. A configured RestApi instance.
=item * C<drive> <object>: Optional. A Drive API instance for listing/deleting documents.
=item * C<endpoint> <string>: Optional. Override the default Docs API endpoint.
=back
=head2 api(%args)
Low-level method to make API calls. You would not normally call this directly
unless making a Google API call not currently supported by this framework.
%args consists of:
=over
=item * C<uri> <string>: Path segments to append to the Docs endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 create_document(%args)
Creates a new Google Docs document.
lib/Google/RestApi/DocsApi1/Document.pm view on Meta::CPAN
%args consists of:
=over
=item * C<fields> <string>: Optional. Fields to return (e.g. 'title', 'body').
=back
=item submit_requests()
Submits all queued batch requests to the Google Docs API batchUpdate endpoint.
=item insert_text(%args)
Queues an insertText request.
%args: C<text> (required), C<index> (optional), C<segment_id> (optional).
=item delete_content(%args)
Queues a deleteContentRange request.
lib/Google/RestApi/DriveApi3.pm view on Meta::CPAN
Readonly our $Drive_Endpoint => 'https://www.googleapis.com/drive/v3';
Readonly our $Drive_File_Id => '[a-zA-Z0-9-_]+';
Readonly our $Drive_Id => '[a-zA-Z0-9-_]+';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
endpoint => Str, { default => $Drive_Endpoint },
],
);
return bless $check->(@_), $class;
}
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { optional => 1 },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = "$self->{endpoint}/";
$uri .= delete $p->{uri} if defined $p->{uri};
return $self->{api}->api(%$p, uri => $uri);
}
sub list {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
filter => Str,
lib/Google/RestApi/DriveApi3.pm view on Meta::CPAN
result_key => 'files',
default_fields => 'files(id, name)',
max_pages => $p->{max_pages},
params => $p->{params},
($p->{page_callback} ? (page_callback => $p->{page_callback}) : ()),
);
}
# backward compatibility.
*filter_files = *list{CODE};
sub upload_endpoint {
my $self = shift;
my $upload = $self->{endpoint};
$upload =~ s|googleapis.com/|googleapis.com/upload/|;
return $upload;
}
sub file { File->new(drive => shift, @_); }
sub about { About->new(drive_api => shift); }
sub changes { Changes->new(drive_api => shift); }
lib/Google/RestApi/DriveApi3.pm view on Meta::CPAN
Creates a new DriveApi3 instance.
my $drive = Google::RestApi::DriveApi3->new(api => $rest_api);
%args consists of:
=over
=item * C<api> L<Google::RestApi>: Required. A configured RestApi instance.
=item * C<endpoint> <string>: Optional. Override the default Drive API endpoint.
=back
=head2 api(%args)
Low-level method to make API calls. You would not normally call this directly
unless making a Google API call not currently supported by this framework.
%args consists of:
=over
=item * C<uri> <string>: Path segments to append to the Drive endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 list(%args)
Lists files matching the given query filter.
lib/Google/RestApi/DriveApi3.pm view on Meta::CPAN
Returns a list of generated file ID strings.
=head2 empty_trash()
Permanently deletes all files in the user's trash. Use with caution!
$drive->empty_trash();
Returns the API response (empty on success).
=head2 upload_endpoint()
Returns the upload endpoint URL for file uploads. Used internally.
=head2 rest_api()
Returns the underlying L<Google::RestApi> instance.
=head1 QUERY SYNTAX
The list() method accepts Google Drive query syntax. Common examples:
# By name
lib/Google/RestApi/GmailApi1.pm view on Meta::CPAN
Readonly our $Gmail_Endpoint => 'https://gmail.googleapis.com/gmail/v1/users';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
user_id => Str, { default => 'me' },
endpoint => Str, { default => $Gmail_Endpoint },
],
);
return bless $check->(@_), $class;
}
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { optional => 1 },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = "$self->{endpoint}/$self->{user_id}/";
$uri .= delete $p->{uri} if defined $p->{uri};
return $self->{api}->api(%$p, uri => $uri);
}
sub message {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
lib/Google/RestApi/GmailApi1.pm view on Meta::CPAN
my $gmail_api = Google::RestApi::GmailApi1->new(api => $rest_api);
%args consists of:
=over
=item * C<api> L<Google::RestApi>: Required. A configured RestApi instance.
=item * C<user_id> <string>: Optional. The user ID (default 'me' for authenticated user).
=item * C<endpoint> <string>: Optional. Override the default Gmail API endpoint.
=back
=head2 api(%args)
Low-level method to make API calls. You would not normally call this directly
unless making a Google API call not currently supported by this framework.
%args consists of:
=over
=item * C<uri> <string>: Path segments to append to the Gmail endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 message(%args)
Returns a Message object for the given message ID.
lib/Google/RestApi/SheetsApi4.pm view on Meta::CPAN
Readonly our $Spreadsheet_Filter => "mimeType = 'application/vnd.google-apps.spreadsheet'";
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi, # the G::RestApi object that will be used to send http calls.
drive => HasMethods[qw(list)], { optional => 1 }, # a drive instnace, could be your own, defaults to G::R::DriveApi3.
endpoint => Str, { default => $Sheets_Endpoint }, # this gets tacked on to the api uri to reach the sheets endpoint.
],
);
my $self = $check->(@_);
return bless $self, $class;
}
# this gets called by lower-level classes like worksheet and range objects. they
# will have passed thier own uri with params and possible body, we tack on the
# sheets endpoint and pass it up the line to G::RestApi to make the actual call.
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { default => '' },
_extra_ => slurpy HashRef, # just pass through any extra params to G::RestApi::api call.
],
);
my $p = named_extra($check->(@_));
my $uri = $self->{endpoint}; # tack on the uri endpoint and pass the buck.
$uri .= "/$p->{uri}" if $p->{uri};
return $self->rest_api()->api(%$p, uri => $uri);
}
sub create_spreadsheet {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
lib/Google/RestApi/SheetsApi4.pm view on Meta::CPAN
=item C<api> L<<Google::RestApi>>: A reference to a configured L<Google::RestApi> instance.
=back
=item api(%args);
%args consists of:
=over
=item * C<uri> <path_segments_string>: Adds this path segment to the Sheets endpoint and calls the L<Google::RestApi>'s C<api> subroutine.
=item * C<%args>: Passes any extra arguments to the L<Google::RestApi>'s C<api> subroutine (content, params, method etc).
=back
This is essentially a pass-through method between lower-level Worksheet/Range objects and L<Google::RestApi>, where this method adds in the Sheets endpoint.
See <Google::RestApi::SheetsApi4::Worksheet>'s C<api> routine for how this is called. You would not normally call this directly unless you were making a Google API call not currently
supported by this API framework.
Returns the response hash from Google API.
=item create_spreadsheet(%args);
Creates a new spreadsheet.
%args consists of:
lib/Google/RestApi/SheetsApi4/Range.pm view on Meta::CPAN
=back
You would not normally call this directly, you'd use Worksheet::range* methods to create the range object for you. It is recommended and safer to use
the Worksheet's methods to create ranges.
=item api(%args);
Calls the parent Worksheet's 'api' routine with the range added into the URI or content appropriately. This then get's passed to the
Spreadsheet's C<api> routine where the spreadsheet ID is tacked on to the URI. This then gets passed to the SheetsApi4's C<api>
routine where the Sheets endpoint is tacked on to the URI. This then gets passed to RestApi's api routine for actual execution.
You would not normally call this directly unless you were making a Google API call not currently supported by this API framework.
=item clear();
Clears the values using Google API's 'A1:clear' call.
=item refresh_values();
Immediately refreshes and returns the values from the spreadsheet.
lib/Google/RestApi/SheetsApi4/Spreadsheet.pm view on Meta::CPAN
$self = bless $self, $class;
$self->{name} ||= $self->{title};
delete $self->{title};
$self->{id} || $self->{name} || $self->{uri} or LOGDIE "At least one of id, name, or uri must be specified";
return $self;
}
# take the passed uri from worksheet/range/rangegroup etc, and tack on the spreadsheet id,
# then pass it up to G::R::SheetsApi4 which will tack on the endpoint.
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { default => '' },
_extra_ => slurpy HashRef, # we'll just pass the params/content etc up for processing.
],
);
my $p = named_extra($check->(@_));
lib/Google/RestApi/TasksApi1.pm view on Meta::CPAN
use aliased 'Google::RestApi::TasksApi1::TaskList';
Readonly our $Tasks_Endpoint => 'https://tasks.googleapis.com/tasks/v1';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
endpoint => Str, { default => $Tasks_Endpoint },
],
);
return bless $check->(@_), $class;
}
sub api {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
uri => Str, { optional => 1 },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = "$self->{endpoint}/";
$uri .= delete $p->{uri} if defined $p->{uri};
return $self->{api}->api(%$p, uri => $uri);
}
sub task_list {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
lib/Google/RestApi/TasksApi1.pm view on Meta::CPAN
Creates a new TasksApi1 instance.
my $tasks_api = Google::RestApi::TasksApi1->new(api => $rest_api);
%args consists of:
=over
=item * C<api> L<Google::RestApi>: Required. A configured RestApi instance.
=item * C<endpoint> <string>: Optional. Override the default Tasks API endpoint.
=back
=head2 api(%args)
Low-level method to make API calls. You would not normally call this directly
unless making a Google API call not currently supported by this framework.
%args consists of:
=over
=item * C<uri> <string>: Path segments to append to the Tasks endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 task_list(%args)
Returns a TaskList object for the given task list ID.
t/lib/Test/Unit/Utils.pm view on Meta::CPAN
use File::Spec::Functions qw( catfile );
use Module::Load qw( load );
use Exporter qw(import);
our @EXPORT_OK = qw(
mock_config_file mock_token_file
mock_spreadsheet_name mock_spreadsheet_name2
mock_worksheet_id mock_worksheet_name
mock_rest_api mock_sheets_api mock_drive_api mock_calendar_api mock_gmail_api mock_tasks_api mock_docs_api
mock_calendar_id mock_task_list_id mock_document_id
drive_endpoint sheets_endpoint calendar_endpoint gmail_endpoint tasks_endpoint docs_endpoint
);
our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
sub mock_config_file { $ENV{GOOGLE_RESTAPI_CONFIG} ? $ENV{GOOGLE_RESTAPI_CONFIG} : catfile($FindBin::RealBin, qw(etc rest_config.yaml)); }
sub mock_token_file { catfile($FindBin::RealBin, qw(etc rest_config.token)); }
sub mock_spreadsheet_name { 'mock_spreadsheet1'; }
sub mock_spreadsheet_name2 { 'mock_spreadsheet2'; }
sub mock_worksheet_id { 0; }
sub mock_worksheet_name { 'Sheet1'; }
t/lib/Test/Unit/Utils.pm view on Meta::CPAN
sub mock_sheets_api { _load_and_new('Google::RestApi::SheetsApi4', api => mock_rest_api(), @_); }
sub mock_drive_api { _load_and_new('Google::RestApi::DriveApi3', api => mock_rest_api(), @_); }
sub mock_calendar_api { _load_and_new('Google::RestApi::CalendarApi3', api => mock_rest_api(), @_); }
sub mock_gmail_api { _load_and_new('Google::RestApi::GmailApi1', api => mock_rest_api(), @_); }
sub mock_tasks_api { _load_and_new('Google::RestApi::TasksApi1', api => mock_rest_api(), @_); }
sub mock_docs_api { _load_and_new('Google::RestApi::DocsApi1', api => mock_rest_api(), @_); }
sub mock_calendar_id { 'mock_calendar_id@group.calendar.google.com'; }
sub mock_task_list_id { 'mock_task_list_id_12345'; }
sub mock_document_id { 'mock_document_id_12345'; }
sub drive_endpoint { $Google::RestApi::DriveApi3::Drive_Endpoint; }
sub sheets_endpoint { $Google::RestApi::SheetsApi4::Sheets_Endpoint; }
sub calendar_endpoint { $Google::RestApi::CalendarApi3::Calendar_Endpoint; }
sub gmail_endpoint { $Google::RestApi::GmailApi1::Gmail_Endpoint; }
sub tasks_endpoint { $Google::RestApi::TasksApi1::Tasks_Endpoint; }
sub docs_endpoint { $Google::RestApi::DocsApi1::Docs_Endpoint; }
sub _load_and_new {
my $class = shift;
load $class;
return $class->new(@_);
}
1;
t/unit/Test/Google/RestApi/DriveApi3.pm view on Meta::CPAN
sub _constructor : Tests(4) {
my $self = shift;
throws_ok sub { DriveApi3->new() },
qr/api/i,
'Constructor without api should throw';
ok my $drive = DriveApi3->new(api => mock_rest_api()), 'Constructor should succeed';
isa_ok $drive, DriveApi3, 'Constructor returns';
can_ok $drive, qw(api list file about changes shared_drive list_drives
create_drive generate_ids empty_trash upload_endpoint);
return;
}
sub file_factory : Tests(3) {
my $self = shift;
my $ss = $self->mock_spreadsheet();
my $file_id = $ss->spreadsheet_id();
t/unit/Test/Google/RestApi/SheetsApi4/Spreadsheet.pm view on Meta::CPAN
return;
}
sub api : Tests(2) {
my $self = shift;
my $ss = $self->mock_spreadsheet();
is_valid $ss->api(), HashRef, 'Get returns hashref';
my $transaction = $ss->rest_api()->transaction();
is $transaction->{request}->{uri}, sheets_endpoint() . "/" . $self->mock_spreadsheet_id(),
'Request base spreadsheet uri string is valid';
return;
}
sub spreadsheet_id : Tests(4) {
my $self = shift;
my $ms = $self->mock_spreadsheet();
my $ms_id = $ms->spreadsheet_id;