Wednesday, June 8, 2011

Using Salesforce.com's REST API from Perl

Introduction

Here's a simple way to access Salesforce data even from behind a firewall, using Perl and the REST API.

If you're not familiar with the details of the Salesforce REST API, have a look at the developer docs.

I'm using Perl 5.12.1 with modules WWW::Mechanize, and WWW::Salesforce.

The firewall settings (optional)

Since I'm behind a firewall, I have to define the necessary variables so the various Perl packages can route the requests properly.  Here's what's needed:
 #!/usr/bin/perl
use warnings;
use strict;
use WWW::Mechanize;
use WWW::Salesforce;

# The firewall proxy variables:
$ENV{HTTPS_PROXY} = 'http://proxy.org.com:80';
$ENV{HTTPS_PROXY_USERNAME} = "proxy_user";
$ENV{HTTPS_PROXY_PASSWORD} = "proxy_pass";
my $mech = WWW::Mechanize->new();
$mech->agent('Mozilla/5.0');
$mech->proxy('http', 'http://proxy_user:proxy_pass@proxy.org.com:80');
$mech->proxy('https', undef);

If you don't need to go through a firewall, you can skip all of these proxy settings, but you'll still need the $mech definition, as it will be used to make the REST requests later.

Authorization

The most difficult part (and it wasn't difficult) was setting up the authorization.  Salesforce offers two options:
  1. OAuth 2.0
  2. Session ID
The Sesion ID is far easier than the first option, so I'm using it here.

The first step is to log-in via the SOAP API (since that is a way to get a session ID):

# Authenticate first via SOAP interface to get a session ID:
my $sforce = eval { WWW::Salesforce->login(
                    username => 'sfdc_user@org.com',
                    password => 'sfdc_pass' ); };
die "Could not login to SFDC: $@" if $@;

Session ID

Now that we've logged-in via the SOAP API, we have a session ID as part of the $sforce variable, which we can get as follows:
 # Get the session ID:
my $hdr = $sforce->get_session_header();
my $sid = ${$hdr->{_value}->[0]}->{_value}->[0];

This SID will need to be sent as part of our request header when using the REST API.

A REST Request

Here's a simple request for all available SObjects:
# Now get some data (using the session ID from above):
$mech->add_header( "Authorization" => "OAuth $sid" );
$mech->add_header( "X-PrettyPrint" => '1' );
$mech->get("https://na1.salesforce.com/services/data/v20.0/sobjects/
");
# ...and write it out to the screen:
print $mech->content;

Going further

 The developer doc mentioned above lists lots of examples for requests that can be made this way, including SOQL queries.

4 comments:

  1. Miguel,

    Great article, many thanks for posting it. I am doing some work with Salesforce and would like to automate the load process using the module however I am at a loss in understanding how or where you specify the environment you need to connect to. Mine is https://test.salesforce.com. If you could help out it would be greatly appreciated.

    Paul

    ReplyDelete
    Replies
    1. Hi Paul,

      Sorry for the delayed reply. Unfortunately, the target URL is hard-coded into WWW::Salesforce, so you'd need to tweak the module code. Have a look at the source here: http://cpansearch.perl.org/src/PHRED/WWW-Salesforce-0.20/lib/WWW/Salesforce.pm.

      The $SF_PROXY variable defines the target URL. You'd need to try changing the "www" to "test", and see if it works. I successfully ran the code shown above from the production side of SFDC, and did not try a test URL as you suggested.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. You can simply override the package variable because it's exposed (it's not a "my" variable). Just set it with

    $WWW::Salesforce::SF_PROXY = "https://$salesforce_domain/services/Soap/u/8.0";

    ReplyDelete