0

I'm new to working with API's and code in general, I have been challenged to create an invocable Apex class that calls a rest API to collect data to input into the Salesforce record that invoked the Apex class.

I have the code where I have predefined the Account Id (AccId) & the Account City (accountCity) (Lines 12 - 13) Going forward I would need this setting upon being invoked by the process builder.

Currently, I'm doing the tests on the Open Weather Map

I'm doing the callout as a 'GET' Method and returning the response which I deserialize into variables that retain the values I would like to put into the Account record.

Code Example

public with sharing class WeatherAPI 
{
    public String Location{get;set;}
    public String Temp{get;set;}
    public String Pressure{get;set;}
    public String Humidity{get;set;}
    public String TempMin{get;set;}
    public String TempMax{get;set;}
    public String Main{get;set;}

    public void Weather() {
        String AccId='0012500001EtLsJAAV';
        String accountCity='Ulverston';
        String apiKey='6a4199d8698bb67cc604e3fb8082599d';

        String RequestEndPoint='Http://api.openweathermap.org/data/2.5/weather';
        RequestEndPoint+='?q='+accountCity;
        RequestEndPoint+='&units=metric';
        RequestEndPoint+='&APPID='+apiKey;

        Http http=new Http();
        HttpRequest request=new HttpRequest();
        request.setEndPoint(RequestEndPoint);
        request.setMethod('GET');
        HttpResponse response=http.send(request);

        if(response.getStatusCode()==200)
        {
         Map<String,Object> results=(Map<String,Object>)JSON.deserializeUntyped(response.getBody());
            Location=String.valueOf(results.get('name'));
            Main=String.valueOf(results.get('weather'));

         Map<String,Object> Mainresults=(Map<String,Object>)(results.get('main'));
            temp=String.valueOf(Mainresults.get('temp'));
            Pressure=String.valueOf(Mainresults.get('pressure'));
            Humidity=String.valueOf(Mainresults.get('humidity'));
            TempMin=String.valueOf(Mainresults.get('temp_min'));
            TempMax=String.valueOf(Mainresults.get('temp_max'));
            Account Values = 
    [SELECT value1__c FROM Account 
    WHERE Id = '0012500001EtLsJAAV' LIMIT 1];

    Values.value1__c = temp;
    update Values;
    system.debug(Values);
        }
        else
        {
            system.debug('Error');
        }

    }

This doesn't work when testing in the debugger and I can't seem to invoke it from the process builder. Any and all help will be greatly appreciated as I have bee stuck at this for a while with no solution. I used this video Weather API to get it into VF page but I want it inserted into Account records to report against and for use in future criteria with BKSB.

EDIT:- Thank you for the help I did some changes and it now shows in the Process builder but when I run it I receive the error 'An Apex error occurred: System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out'

Heres the updated code:-

public class Development {
@InvocableMethod(label='Development' description='To be called in a process')
public static List<String> calloutMethod(List<ID> ids){
    List<String> accountNames = new List<String>();
    //Http requests
    Http http=new Http();
    HttpRequest request=new HttpRequest();
    request.setEndPoint('https://api.openweathermap.org/data/2.5/weather?q=Ulverston&APPID=6a4199d8698bb67cc604e3fb8082599d');
    request.setMethod('GET');
    HttpResponse response=http.send(request);
    System.debug(response.getStatusCode());
    System.debug(response.getBody());
    if(response.getStatusCode()==200)
    {
     Map<String,Object> results=(Map<String,Object>)JSON.deserializeUntyped(response.getBody());
        system.debug(results);
    }

    return accountNames;
}

@future(callout=true)
public static void makeDMLOperation(){
    Account Values = 
    [SELECT value1__c FROM Account 
    WHERE Id = '0012500001EtLsJAAV' LIMIT 1];
    Values.value1__c = 'Test';
    update Values;
}

}

I'm struggling to wrap my head around Invocable methods and future methods. So the formatting might be completely off.

The process is triggered by a checkbox : Process And this is the immediate action where the apex is called: immediate action

Once again thank you for any and all help.

Edit 2 - Most Recent

 public class Development {
    Static String GatheredResult;
    @InvocableMethod(label='Development' description='To be called in a process')

   public static void calloutMethod(){
    Account Values = 
    [SELECT value1__c FROM Account 
    WHERE Id = '0012500001EtLsJAAV' LIMIT 1];
    Values.value1__c = GatheredResult;
       {
            Development.makeDMLOperation();
       }
    update Values;
}
    @future(callout=true)
public static void makeDMLOperation(){
    //Http requests
    Http http=new Http();
    HttpRequest request=new HttpRequest();
    request.setEndPoint('https://api.openweathermap.org/data/2.5/weather?q=Ulverston&APPID=6a4199d8698bb67cc604e3fb8082599d');
    request.setMethod('GET');
    HttpResponse response=http.send(request);
    System.debug(response.getStatusCode());
    System.debug(response.getBody());
    if(response.getStatusCode()==200)
    {
     Map<String,Object> results=(Map<String,Object>)JSON.deserializeUntyped(response.getBody());
     GatheredResult=String.valueOf(results.get('weather'));
     system.debug(results);
    }
}   
}
  • 1
    Not quite sure, but normally you need to decouple your trigger (aka process builder) from your apex callout (it's a platform limit). Perhaps try to capture what exception you are getting via developer console/ sfdx tail. – dzh Oct 15 '19 at 11:13
  • 1
    This seems very close to what you are trying to do: medium.com/devsys/… – dzh Oct 15 '19 at 11:15
  • 1
    to invoke the method from process builder you must add the annotation @InvocableMethod(label='method name' description='...'), you must do a System.debug(response.getStatusCode()) and a System.debug(response.getBody()) to see the actual error details – toufik_at Oct 15 '19 at 11:55
  • invocable classes should do the callout in an async transaction (Future/queueable) – cropredy Oct 15 '19 at 18:31
  • 1
    1) Since you've written this much Apex, you might as well drop the process builder and write a trigger instead. It's a lot easier to debug. 2) Will these updates be initiated by users ticking the checkbox or or by an automated process? If through user interaction, it will be easier to make a custom button to execute your code, that way you don't have to deal with an initial DML. – David Cheng Oct 18 '19 at 0:46

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.