A non-blocking Salesforce API client using Mojolicious. It may one day replace WWW::Salesforce.
It is EXTREMELY experimental at this point. Use it at your own risk. You've been warned.
# via soap
my $sf_soap = WWW::Salesforce->new(
login_type => 'soap',
login_url => Mojo::URL->new('https://login.salesforce.com'),
version => '34.0',
username => '[email protected]',
password => 'mypassword',
pass_token => 'mypasswordtoken123214123521345',
);
# via OAuth2 username and password
my $sf_oauth2 = WWW::Salesforce->new(
login_type => 'oauth2_up', # this is the default
login_url => Mojo::URL->new('https://login.salesforce.com'),
version => '34.0',
consumer_key => 'alksdlkj3hasdg;jlaksghajdhgaghasdg.asdgfasodihgaopih.asdf',
consumer_secret => 'asdfasdjkfh234123513245',
username => '[email protected]',
password => 'mypassword',
pass_token => 'mypasswordtoken123214123521345',
);
# blocking method
# calling login() will happen automatically.
try {
my $res_soap = $sf_soap->query('Select Id, Name, Phone from Account');
say "found ", scalar(@{$res_soap}), " results via SOAP then RESTful API.";
my $res_oauth = $sf_oauth2->query('Select Id, Name, Phone from Account');
say "found ", scalar(@{$res_oauth}), " results via OAuth2 then RESTful API.";
}
catch {
die "Couldn't query the service: $_";
};
# non-blocking method
# calling login() will happen automatically
Mojo::IOLoop->delay(
sub {
my $delay = shift;
$sf_soap->query('select Id from Account', $delay->begin);
$sf_oauth2->query('select Id from Account', $delay->begin);
},
sub {
my ($delay, $err,$soap,$err2,$oauth) = @_;
Carp::croak( $err ) if $err; # make it fatal
Carp::croak( $err2 ) if $err2; # make it fatal
say scalar(@$soap), " from soap";
say scalar(@$oauth), " from oauth2";
},
)->catch(sub {say "uh oh, ",pop;})->wait;
WWW::Salesforce allows us to connect to Salesforce's service to access our data using their RESTful API.
Creation of a new WWW::Salesforce instance will not actually hit the server. The first communication with the Salesforce API occurs when you specifically call the login
method or when you make another call.
All API calls using this library will first make sure you are properly logged in.
oauth2_up
OAuth2 using the username and password (up) method:soap
Alternately, you can use the soap login method:
WWW::Salesforce makes the following attributes available.
my $key = $sf->consumer_key;
$sf = $sf->consumer_key( 'alksdlksdf' ); # method-chaining
The Consumer Key (also referred to as the client_id in the Saleforce documentation) is part of your Connected App. It is a required field to be able to login.
Note, this attribute is only used to generate the access token during login. You may want to logout before changing this setting.
my $secret = $sf->consumer_secret;
$sf = $sf->consumer_secret( 'asdfas123513245' ); # method-chaining
The Consumer Secret (also referred to as the client_secret in the Saleforce documentation) is part of your Connected App. It is a required field to be able to login.
Note, this attribute is only used to generate the access token during login. You may want to logout before changing this setting.
my $type = $sf->login_type;
$sf = $sf->login_type( 'oauth2_up' ); # method-chaining
This is what will determine our login method of choice. No matter which login method you choose, we're going to communicate to the Salesforce services using an Authorization: Bearer token
header. The login method just dictates how we will request that token from Salesforce. Different methods of login require slightly different sets of data in order for the login to take place.
You may want to logout before changing this setting.
Available types are:
This login type is the default. It will require your consumer_key, consumer_secret, username, password, pass_token and login_url. This method will go through the Salesforce Username-Password OAuth Authentication Flow.
This method will only require your username, password, pass_token and login_url. It will go through the Salesforce SOAP-based username and password login flow.
my $host = $sf->login_url;
$sf = $sf->login_url( Mojo::URL->new('https://test.salesforce.com') ); # method-chaining
This is the base host of the API we're using. This allows you to use any of your sandbox or live data areas easily. You may want to logout before changing this setting.
my $token = $sf->pass_token;
$sf = $sf->pass_token( 'mypasswordtoken145' ); # method-chaining
The password token is a Salesforce-generated token to go along with your password. It is appended to the end of your password and used only during login authentication.
Note, this attribute is only used to generate the access token during login. You may want to logout before changing this setting.
my $password = $sf->password;
$sf = $sf->password( 'mypassword' ); # method-chaining
The password is the password you set for your user account in Salesforce.
Note, this attribute is only used to generate the access token during login. You may want to logout before changing this setting.
my $ua = $sf->ua;
The Mojo::UserAgent is the user agent we use to communicate with the Salesforce services. For proxy
and other needs, see the Mojo::UserAgent documentation.
my $username = $sf->username;
$sf = $sf->username( '[email protected]' ); # method-chaining
The username is the email address you set for your user account in Salesforce. Note, this attribute is only used to generate the access token during login. You may want to logout before changing this setting.
my $version = $sf->version;
$sf = $sf->version( '34.0' ); # method-chaining
Tell us what API version you'd like to use. Leave off the v
from the version number.
WWW::Salesforce makes the following methods available.
# blocking
try {
my $res = $sf->create('Account',{fieldName=>'value'});
if ( $res->{success} ) { # even if the tx succeeds, check the response!
say "Newly entered Account goes by the id: ",$res->{id};
}
else {
die Dumper $res->{errors};
}
} catch {
die "Errors: $_";
};
# non-blocking
$sf->create('Account',{fieldName=>'value'}, sub {
my ($sf, $err, $res) = @_;
die "Got an error trying to create the Account: $err" if $err;
if ( $res->{success} ) { # even if the tx succeeds, check the response!
say "Newly entered Account goes by the id: ",$res->{id};
}
else {
die Dumper $res->{errors};
}
});
This method calls the Salesforce Create method.
On a successful transaction, a JSON response is returned with three fields (id
, success
, and errors
). You should check that response to see if your creation attempt actually succeeded.
# blocking
try {
my $res = $sf->describe('Account');
say Dumper $res; #all the info about the Account SObject
} catch {
die "Errors: $_";
};
# non-blocking
$sf->describe('Account', sub {
my ($sf, $err, $res) = @_;
die "Got an error trying to describe the Account: $err" if $err;
say Dumper $res; #all the info about the Account SObject
});
This method calls the Salesforce Describe method. On a successful transaction, a JSON response is returned with data full of useful information about the SObject.
# blocking
try {
my $results = $sf->limits();
say Dumper $results;
} catch {
die "Errors: $_";
};
# non-blocking
$sf->limits(sub {
my ($sf, $err, $results) = @_;
say Dumper $results;
});
This method calls the Salesforce Limits method.
## blocking
$sf = $sf->login(); # allows for method-chaining
## non-blocking
$sf->login( sub {
my ($sf, $token) = @_;
say "Our auth token is: $token";
});
This method will go through the Salesforce Username-Password OAuth Authentication Flow process if it needs to.
Calling this method on your own is not necessary as any API call will call login
if necessary. This could be helpful if you're changing api_host
s on your instance.
This method will update your access_token
on a successful login.
$sf = $sf->logout(); # allows for method-chaining
This method does not actually make any call to Salesforce. It only removes knowledge of your access token so that you can login again on your next API call.
## blocking
my $results = $sf->query('Select Id, Name, Phone from Account');
say Dumper $results;
## non-blocking
$sf->query('select Id, Name, Phone from Account', sub {
my ($sf, $results) = @_;
say Dumper $results;
});
This method calls the Salesforce Query method. It will keep grabbing and adding the records to your resultant array reference until there are no more records available to your query.
Your query string must be in the form of an SOQL String.
# blocking
try {
my $results = $sf->retrieve('Account','01231ABCDFQ2100002', [qw(Optional FieldName List Here)]);
# can also call as ->retrieve('Account','01231ABCDFQ2100002')
say Dumper $results;
} catch {
die "Errors: $_";
};
# non-blocking
$sf->retrieve('Account','01231ABCDFQ2100002', [qw(Optional FieldName List Here)], sub {
# can also call as ->retrieve('Account','01231ABCDFQ2100002', sub {...});
my ($sf, $err, $results) = @_;
say Dumper $results;
});
This method calls the Salesforce Retrieve method.
# blocking
try {
my $results = $sf->search('FIND{genio*}');
say Dumper $results;
} catch {
die "Errors: $_";
};
# non-blocking
$sf->search('FIND{genio*}', sub {
my ($sf, $err, $results) = @_;
say Dumper $results;
});
This method calls the Salesforce Search method. Your search query must be in the form of an SOSL String.
All blocking method calls will die
on error and thus you should use Try::Tiny a lot.
# blocking call
use Try::Tiny qw(try catch);
try {
my $res = $sf->do_something();
} catch {
die "uh oh: $_";
};
All non-blocking methods will return an error string to the callback if there is one:
# non-blocking call
$sf->do_something(sub {
my ( $instance, $error_string, $results ) = @_;
die "uh oh: $error_string" if $error_string;
});
Chase Whitener -- [email protected]
Please report any bugs or feature requests on GitHub https://github.com/genio/www-salesforce-nb/issues. We appreciate any and all criticism, bug reports, enhancements, or fixes.