Google-ContentAPI

 view release on metacpan or  search on metacpan

lib/Google/ContentAPI.pm  view on Meta::CPAN

##############################################################################
# Google::ContentAPI
#
# Add, modify and delete items from the Google Merchant Center platform via
# the Content API for Shopping.
#
# https://developers.google.com/shopping-content/v2/quickstart
#
# Authentication is done via Service Account credentials. For details see:
# https://developers.google.com/shopping-content/v2/how-tos/service-accounts
#
# AUTHOR
#
# Bill Gerrard <bill@gerrard.org>
#
# VERSION HISTORY
#
# + v1.03       12/10/2020 Allow custom endpoint, update docs for v2.1 API
# + v1.02       04/11/2018 Add accountstatuses, productstatuses methods. Add "custom" resource
# + v1.01       03/27/2018 Added config_json, merchant_id options and switched to Crypt::JWT
# + v1.00       03/23/2018 initial release
#
# COPYRIGHT AND LICENSE
#
# Copyright (C) 2018,2020 Bill Gerrard
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself, either Perl version 5.20.2 or,
# at your option, any later version of Perl 5 you may have available.
#
# Disclaimer of warranty: This program is provided by the copyright holder
# and contributors "As is" and without any express or implied warranties.
# The implied warranties of merchantability, fitness for a particular purpose,
# or non-infringement are disclaimed to the extent permitted by your local
# law. Unless required by law, no copyright holder or contributor will be
# liable for any direct, indirect, incidental, or consequential damages
# arising in any way out of the use of the package, even if advised of the
# possibility of such damage.
#
################################################################################

package Google::ContentAPI;

use strict;
use warnings;
use Carp;

use JSON;
use Crypt::JWT qw(encode_jwt);
use REST::Client;
use HTML::Entities;

our $VERSION = '1.03';

sub new {
    my ($class, $params) = @_;
    my $self = {};

    if ($params->{config_file}) {
        $self->{config} = load_google_config($params->{config_file});
    } elsif ($params->{config_json}) {
         $self->{config} = decode_json $params->{config_json};
    } else {
      croak "config_file or config_json not provided in new()";
    }
    $self->{merchant_id} = $self->{config}->{merchant_id}
        || $params->{merchant_id}
        || croak "'merchant_id' not provided in json config in new()";

lib/Google/ContentAPI.pm  view on Meta::CPAN

    my $self = shift;

    my $gapiTokenURI     = 'https://www.googleapis.com/oauth2/v4/token';
    my $gapiContentScope = 'https://www.googleapis.com/auth/content';
    my $time = time();

    # 1) Create JSON Web Token
    # https://developers.google.com/accounts/docs/OAuth2ServiceAccount
    #
    my $jwt = encode_jwt(
        payload => {
            iss => $self->{config}->{client_email},
            scope => $gapiContentScope,
            aud => $gapiTokenURI,
            exp => $time + 3660, # max 60 minutes
            iat => $time
        },
        key => \$self->{config}->{private_key},
        alg => 'RS256'
    );

    # 2) Request an access token
    #
    my $ua = LWP::UserAgent->new();
    my $response = $ua->post($gapiTokenURI, {
        grant_type => encode_entities('urn:ietf:params:oauth:grant-type:jwt-bearer'),
        assertion => $jwt
    });

    print "Request Access Token response:\n". $response->content if $self->{debug};

    unless($response->is_success()) {
        die("Error receiving access token:\n", $response->code, "\n", $response->content, "\n");
    }

    my $data = decode_json $response->content;
    return 'Bearer '. $data->{access_token};
}

sub load_google_config {
  my $json_file = shift;
  open my $fh, '<', $json_file or croak "Error reading config_file '$json_file': $!";
  my $json_text;
  { local $/; $json_text = <$fh>; }
  close $fh;
  return decode_json $json_text;
}

1;

__END__
=head1 NAME

Google::ContentAPI - Interact with Google's Content API for Shopping

=head1 DESCRIPTION

Add, modify and delete items from the Google Merchant Center platform via
the Content API for Shopping.

Authentication is done via Service Account credentials. See the following for details:
L<https://developers.google.com/shopping-content/v2/how-tos/service-accounts>

You will also need to create a Merchant Center Account:
L<https://developers.google.com/shopping-content/v2/quickstart>

For convenience, add your Merchant account ID to the *.json file provided by Google.
Your complete *.json file, after adding your merchant ID, will look something like this:

  {
    "endpoint": "https://www.googleapis.com/content/v2.1",
    "merchant_id": "123456789",
    "type": "service_account",
    "project_id": "content-api-194321",
    "private_key_id": "11b8e20c2540c788e98b49e623ae8167dc3e4a6f",
    "private_key": "-----BEGIN PRIVATE KEY-----
    ...
    -----END PRIVATE KEY-----\n",
    "client_email": "google@content-api.iam.gserviceaccount.com",
    "client_id": "999999999",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google%40content-api.iam.gserviceaccount.com"
  }

=head1 SYNOPSIS

  use Google::ContentAPI;
  use Data::Dumper;

  my $google = Google::ContentAPI->new({
      endpoint => 'https://www.googleapis.com/content/v2.1',
      debug => 0,
      config_file => 'content-api-key.json',
      config_json => $json_text,
      merchant_id => '123456789',
  });

  my ($result, $products, $batch_id, $product_id);

  # get account auth info (merchantId)
  $result = $google->get(
    resource => 'accounts',
    method   => 'authinfo'
  );
  print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
  print "authinfo: \n". Dumper $result;

  # get status of your merchant center account
  $result = $google->get(
      resource => 'accountstatuses',
      method   => 'get',
      id => $google->{merchant_id} # your merchant ID unless working with multi-client account
  );
  print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
  print "Account status: \n". Dumper $result;

  # list status of multi-client accounts (MCA)
  # This will fail with response code 403 if the account is not a multi-client account.
  $result = $google->get(



( run in 2.095 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )