0

I'm working a process involving third-party webservices, and have made it past the initial authorization hurdle but am running into a new problem. Regardless of whether the content-type is specified, when I try and send this request I get the following:

System.CalloutException.getMessage() returns 'no protocol: /api/v2/outbound/contactlists/cf1c69e4-dff3-41db-9f5a-39779f53b217/export

System.CalloutException.getCause() returns null

Per the comments, I've updated the request to provide the complete URL in setEndpoint():

        String authHeader = 'Bearer ' + accessToken;
        HttpRequest req2 = new HttpRequest();

        req2.setMethod('POST');            
        req2.setHeader('Authorization', authHeader);
        req2.setEndpoint('https://api.mypurecloud.com/api/v2/outbound/contactlists/' + pureCloudCListId + '/export');                

Http http2 = new Http();

        try{
            HTTPResponse res2 = http2.send(req2);
            updateSuccessful = true;
        } catch(System.CalloutException e){
            Utils.debug('An error initializing Contact list export...' + e.getMessage() + ',\n' + e.getCause() + ',\nLine: ' + e.getLineNumber(), 'REST Callout', 'PureCloudUpdateCampaign[101]');

So now I can see the real problem, which is that I'm not parsing the accessToken successfully :( (I thought I'd fixed that.) I'm using the following code to extract the token, without success:

            JSONParser parser = JSON.createParser(JSONString);
        while (parser.nextToken() != null) 
        {
            if (parser.getCurrentToken() == JSONToken.FIELD_NAME && 
                parser.getText() == 'access_token')
            {
                parser.nextToken();
                accessToken = parser.getText();
                break;
            }
        }

(I added the break; statement in case accessToken was getting cleared out; apparently not.)

accessToken is still an empty string after this, though there is an access_token populated in the JSON:

7/10/2018 11:27 AM JSONString "{\"access_token\":\"8Gof9Ocz7SBITWpG5hKyPqLlBsrdq3hBNe2aygEfs3ZseWl906ciBVFZEEF4w3cYxo3rr347w15DFNIz9ov-jQ\",\"token_type\":\"bearer\",\"expires_in\":86399}\n"

As parser.nextToken() is not working well with this ^, I parsed it manually using String.split() to extract the token. At this point I can assemble the authorizationHeader at least: authHeader (string) = 'Bearer l6IPTvAajf2Ke_bemB2srUfkwl-1asq54ogbiPmKtsEg4rd_fffX9Qxuh5KEjYc-WZ_vDAL9zL1F6RDv6c0JUA'

... whoa. Looks like it worked. At least I have a download URL. Here's the 'finished' product (to the point where I've generated an export file):

        PureCloud_Config__c pureCloudConfig = PureCloud_Config__c.getOrgDefaults();
    string clientId = pureCloudConfig.clientId__c;
    string clientSecret = pureCloudConfig.clientSecret__c;

    Boolean updateSuccessful = false;

    HttpRequest req = new HttpRequest();

    req.setMethod('POST');        
    req.setHeader('Authorization', 'Basic ' +
      EncodingUtil.base64Encode(Blob.valueOf(clientId + ':' + clientSecret)));
    req.setHeader('Host','https://login.mypurecloud.com/oauth');
    req.setHeader('content-type', 'application/x-www-form-urlencoded');
    req.setEndpoint('https://login.mypurecloud.com/oauth/token');
    req.setBody('grant_type=client_credentials');

    Http http = new Http();
    String JSONString = null;
    try{
        HTTPResponse res = http.send(req);
        JSONString = JSON.serialize(res.getBody());
        updateSuccessful = true;
    } catch(System.CalloutException e){
        Utils.debug(e.getMessage() + ',\n' + e.getCause() + ',\nLine: ' + e.getLineNumber(), 'REST Callout', 'PureCloudUpdateCampaign[63]');
    }

    if(updateSuccessful){

        String accessToken = '';
        String issuedAt = '';

        //Parse JSON for Bearer Token
        JSONParser parser = JSON.createParser(JSONString);
        while (parser.nextToken() != null) 
        {               
            if (parser.getCurrentToken() == JSONToken.VALUE_STRING && //JSONToken.FIELD_NAME && 
                parser.getText().contains('access_token')) // == 'access_token')
            {
               accessToken = parser.getText();
            }
        }

        String[] stringParts = accessToken.split('"');
        accessToken = stringParts[3];
        String authHeader = 'Bearer ' + accessToken;

        HttpRequest req2 = new HttpRequest();

        req2.setMethod('POST');            
        req2.setHeader('Authorization', authHeader);
        req2.setEndpoint('https://api.mypurecloud.com/api/v2/outbound/contactlists/' + pureCloudCListId + '/export');                

        Http http2 = new Http();

        try{
            HTTPResponse res2 = http2.send(req2);
            updateSuccessful = true;
        } catch(System.CalloutException e){
            Utils.debug('An error occurred initializing Contact list export...' + e.getMessage() + ',\n' + e.getCause() + ',\nLine: ' + e.getLineNumber(), 'REST Callout', 'PureCloudUpdateCampaignList_queueable[102]');
            updateSuccessful = false;
        }

        if(updateSuccessful){
            String sNext = getContactListURL(authHeader, pureCloudCListId);
            Utils.debug('Contact List URL = ' + sNext);
        }

    }
    public String getContactListURL(String authHeader, String cListId){        

    String result = 'I got nothing.';
    HttpRequest req = new HttpRequest();

    req.setMethod('GET');            
    req.setHeader('Authorization', authHeader);
    req.setHeader('content-type', 'application/json');
    req.setEndpoint('https://api.mypurecloud.com/api/v2/outbound/contactlists/' + cListId + '/export');                

    Http http = new Http();

    try{
        HTTPResponse res = http.send(req);
        String sBody = res.getBody();
        result = sBody;

    } catch(System.CalloutException e){
        Utils.debug('An error occurred retrieving the Contact list download URL...' + e.getMessage() + ',\n' + e.getCause() + ',\nLine: ' + e.getLineNumber(), 'REST Callout', 'PureCloudUpdateCampaign[137]');

    }

    return result;        
}

With result being: 7/10/2018 4:21 PM Contact List URL = {"uri":"https://api.mypurecloud.com/api/v2/downloads/download_location__shhhh","exportTimestamp":"2018-07-10T20:12:48.909Z"}

  • 1
    You say you got past the initial authorization issues. Perhaps you've authenticated (step 1), but not received an access token (step 2) by sending the authentication token to an oath/token url to obtain what might be a jwt bearer token based on what I see from looking at your code. – crmprogdev Jul 10 '18 at 14:31
  • 4
    Pretty sure that your issue is the relative url you're providing to setEndpoint() (which currently does not specify a protocol). I haven't come across any documentation that says that Salesforce does something with the "host" header. Try adding the host string to your relative endpoint, and see if that works. I'd also remove the host header entirely unless your service specifically needs it to be included. – Derek F Jul 10 '18 at 14:35
  • Thanks! I was getting a token before, but now I'm not, so I'll be tracking that down. I removed the host header & combined the Host/Endpoint URLs and am now getting a response back! Granted, the response is telling me my credentials are invalid (which wasn't the case before, but I'll roll with it.) So now I'm off to see whether there's something that needs to be addressed/refreshed about the clientId and clientSecret. – Duncan Stewart Jul 10 '18 at 15:21
  • I've updated the post, including the part about seeing the access token but not getting the access token. parser.getText() returning null. – Duncan Stewart Jul 10 '18 at 16:53
  • As parser.nextToken() has been returning null (possibly due to an unexpected format of the access_token response), I parsed it manually and end up with something like this (the token changes each time, as you might expect): String authHeader = 'Bearer l6IPTvAajf2Ke_bemB2srUfkwl-1asq54ogbiPmKtsEg4rd_fffX9Qxuh5KEjYc-WZ_vDAL9zL1F6RDv6c0JUA' – Duncan Stewart Jul 10 '18 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.