2

Setup: Pardot (3rd Party services I'm using) requires you to request an API_Key by submitting your email, password, and user_key so that you can then use the api_key with the user_key to do any API calls. At the moment I have a Pardot class like this.

public class Pardot {

    public static void createProspectsByLead (Lead[] leads){
        String api_key = getAPIKey();
        // More HttpGetRequest using pardot api endpoint (https://pi.pardot.com/api/) with user_key + api_key body parameters
    }

    public static String getAPIKey (){
        /* Found out my credentials were correct but I needed to urlEncode them */
        String Connector_Email = EncodingUtil.urlEncode(Globals.get('Pardot Connector Email', 'Value__c'), 'UTF-8');
        String Connector_Password = EncodingUtil.urlEncode(Globals.get('Pardot Connector Password', 'Value__c'), 'UTF-8');
        String Connector_User_Key = EncodingUtil.urlEncode(Globals.get('Pardot User Key', 'Value__c'), 'UTF-8');

        String body = 'email='+Connector_Email
            +'&password='+Connector_Password
            +'&user_key='+Connector_User_Key;
        String url = 'https://pi.pardot.com/api/login/version/3?'+body;
        System.debug(body);

        /* Request API Key */
        String api_response = HttpGetRequest(url, body);

        /* Generate the HTTP response as an XML stream */
        XmlStreamReader reader = api_response.getXmlStreamReader(); // Need to figure this out next

        // return String API_Key;

    }

    /* HERE COMES THE PROBLEM */
    @future (callout=true) // future method needed to run callouts from Triggers
    static void HttpGetRequest(String url, String body){
        /* Instantiate a new http object */
        Http h = new Http();

        /* Instantiate a new HTTP request, specify the method (GET) as well as the endpoint */
        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('POST');
        req.setBody(body);
        req.setCompressed(true); 

        /* Try to send the request */
        try {
            HttpResponse res = h.send(req);
            System.debug(res.getBody());
            // I want to now return 'res' but I can't
        } catch(System.CalloutException e) {
            System.debug('ERROR: '+ e);
        }

    }

}

The Problems

  1. @future can only return void: As you can see from the code above, I expected with each API call to request the API_Key and then return that key to my method so that I could use it as necessary. But since httpRequest need to be made with @future and it can only return void there is no way to pass api_key directly. I imagine from here I would attempt to store this in my Global__c object in a text field but then I also need to add a timestamp since Pardot only allows that API key for 1 hour.
  2. Handling the Response: I was able to get a response in the debug output but I'm not sure how to handle the response to parse out the API key specifically. Here is the response:

    <?xml version="1.0" encoding="UTF-8"?> <rsp stat="ok" version="1.0"> <api_key>6d800bfaab63274b1b908dacd8544936</api_key> </rsp>

This is all part of my first APEX project and has become quite the task to get to this point including other questions I've already posted:

Really appreciate even some resource that outline the exact process of what I'm attempting because I would think its a common process using 3rd party web services, but up till now I'm having trouble finding any simple working examples. Also I'm completely open to suggestion for better approaches to something like this. Thank you so much in advance for any help you can provide.

Follow Up Question posted here: Verify getChildElement() is not null

2
  • I'm a bit lost about what that "Globals.get(...)" call is -- not having any luck with Google. Where exactly in Salesforce are you storing your Pardot password?
    – k..
    Sep 19, 2018 at 14:09
  • 1
    It's been awhile since I did this and we no longer use Pardot so I'm not 100% but I believe I stored that in a custom Global__c object that I queried from a Globals class at the time. The most secure option (of 3) I believe was to store that detail in a Custom Setting of a managed package, but at the time this was secure enough I believe. Could store in a custom setting within your Org as well, just not the "best/secure" option ;) Also you can review the code I used at that time here: github.com/Xtremefaith/Pardot-API-Example/tree/master/src/… Sep 24, 2018 at 19:46

2 Answers 2

1

The reason why @future returns void is because it's asynchronous. It doesn't start until the calling code's transaction has finished. There's no way to communicate back to the calling code at all. Odds are, you'll want to make createProspectsByLead a @future method instead, so you can authenticate and then perform your action. You can have 100 calls per transaction (as of Winter '15 release), so it's unlikely you'll need more than just a couple of calls. And you should definitely cache the API key so you don't waste calls (if applicable), and perform more efficiently anyways.

For handling the response, see Dom.Document for reading an XML file. A successful load would probably reduce the complexity to:

Dom.Document d = new Dom.Document();
d.load(res.getBody());
String api_key = d.getRootElement().getChildElement('rsp',null).getChildElement('api_key', null).getText();
4
  • Current issue with that is that the List ( Lead[] Leads ) is being passed into that parameter and @future will not allow that parameter type. Here's more information on that: @future method: Unsupported parameter type Oct 21, 2014 at 18:50
  • @Xtremefaith Just pass a list of ID values instead...
    – sfdcfox
    Oct 21, 2014 at 18:59
  • I just made a callout() method to be the @future handler for any other Pardot request I need, I'll pass it the URL and Body parameters and the callout() can get the API_key and then fire the Pardot callouts. So far this seems to be working but the Dom.Document solution you have posted is not working (it doesn't return anything in debug) Oct 21, 2014 at 19:23
  • For reference I posted the complete implementation on github Nov 14, 2014 at 0:08
0

To get the API key, I used

Dom.Document responseBodyDoc = response.getBodyDocument();
Dom.XMLNode rootNode = responseBodyDoc.getRootElement();
Dom.XMLNode apiNode = rootNode.getChildElement('api_key', null);
String apiKey = apiNode.getText();

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .