function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
VenkataRajaVenkataRaja 

System.HttpResponse[Status=Unauthorized, StatusCode=401]

Hi,

I am Calling future method from schedule apex, getting an error: System.HttpResponse[Status=Unauthorized, StatusCode=401]
I think we are getting because of UserInfo.getSessionId() null, If I comment hilighted line also I am getting same error. Is there any solution for this. or Can I schedule the callouts?

public class Sample
{
      @future(Callout = true)
      public static void getCoverageforClasses()
      {
           String objectIdQuery = 'SELECT ApexClassorTriggerId, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate';

           String environmentURL = URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v28.0/tooling/query/?q=' +      EncodingUtil.urlEncode(objectIdQuery, 'UTF-8');
     
        HttpRequest req = new HttpRequest();
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type', 'application/json');
        req.setEndpoint(environmentURL);
        req.setMethod('GET');
     
        Http h = new Http();
        return h.send(req).getBody();             
      }
}



Thanks
Venkat
Ramesh KallooriRamesh Kalloori
The endpoint is returning 401 Unauthorized. Possible reasons:

1.Bad request URL. Copy-pasting URL from your code to a browser may validate.
2.Wrong protocol. If the endpoint requires HTTPS and your URL uses HTTP.
3.Bad IP. You said that the provider has whitelisted the SFDC IPs, but perhaps they made an error. If you are able to test from a browser from a non-4.whitelisted IP (e.g., from home), you can determine if you get the same error.
5.Some other error at the endpoint. If everything else fails, you may need to ask the provider to check their logs.


Future Method Considerations

• Remember that any method using the future annotation requires special consideration because the method does not
necessarily execute in the same order it is called.

• Methods with the future annotation cannot be used in Visualforce controllers in either getMethodName or
setMethodName methods, nor in the constructor.

• You cannot call a method annotated with future from a method that also has the future annotation. Nor can you call
a trigger from an annotated method that calls another annotated method.

• The getContent and getContentAsPDF PageReference methods cannot be used in methods with the future
annotation

and we can schedule the callouts from scheduler class.

Thanks,
RAmesh
VenkataRajaVenkataRaja
Hi Ramesh,

Thanks!

Can you please send me the sample code to schedule the callouts from scheduler class.


Thanks 
Venkat.
VenkataRajaVenkataRaja
Hi Rames,

Please send any code on Tooling API objects for scheduling http callouts.

Thanks 
Venkat
Ramesh KallooriRamesh Kalloori
Please go through the below code.

global class LocationCalloutsSchedule implements Schedulable {
    global Set<ID> AccIDs;
    global LocationCalloutsSchedule(Set<ID> AccIDs)
    {
        this.AccIDs=AccIDs;
    }
global void execute(SchedulableContext ctx) {  
  LocationCallouts.getLocation(AccIDs);
  } 
}
public class LocationCallouts{
 public static transient Savepoint sp;
 //public accoount ac;
 //public ID testAccID;
 public static List<Account> accountId;
 //public List<ID> accIds;
    public LocationCallouts(List<Account> accountList)
    {
        accountId=accountList;
    }
 /*public void go(id accountid)
 {
     Account ac = [SELECT BillingCity,BillingCountry,BillingPostalCode,BillingState,BillingStreet FROM Account WHERE Name='Genpact' Limit 1];
 }*/
     @future (callout=true)
      // future method needed to run callouts from Triggers
     public static void getLocation(Set<ID> accIds)
     {
        // gather account info
        //sp = Database.setSavepoint();
       //for(integer i=0;i<accIds.size();i++)
       {
           //this.accIds=accIds;
           System.debug('List Of IDS=======?????'+accIds);
           List<Account> aa=new List<Account>();
           //String AID= accIds[i];
       List<Account> Lacc= [SELECT ID,BillingCity,BillingCountry,BillingPostalCode,BillingState,BillingStreet FROM Account WHERE id in:accIds];
          for(Account a:Lacc)
          {
        System.debug('++++++'+a);
        // create an address string
        String address = '';
        if (a.BillingStreet != null)
            address += a.BillingStreet +', ';
        if (a.BillingCity != null)
            address += a.BillingCity +', ';
        if (a.BillingState != null)
            address += a.BillingState +' ';
        if (a.BillingPostalCode != null)
            address += a.BillingPostalCode +', ';
        if (a.BillingCountry != null)
            address += a.BillingCountry;
         System.debug('=======>>>'+address);
        address = EncodingUtil.urlEncode(address, 'UTF-8');
 
        // build callout
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?key=XXXXX&address='+address+'&sensor=false');
        req.setMethod('GET');
        req.setTimeout(60000);
 
       
            // callout
            HttpResponse res = h.send(req);
 
            // parse coordinates from response
           double lat = null;
            double lon = null;   
         JSONParser parser =System.JSON.createParser(res.getBody());
 while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                    (parser.getText() == 'location')){
                       parser.nextToken(); // object start
                       while (parser.nextToken() != JSONToken.END_OBJECT){
                           String txt = parser.getText();
                           parser.nextToken();
                           if (txt == 'lat')
                               lat = parser.getDoubleValue();
                           else if (txt == 'lng')
                               lon = parser.getDoubleValue();
                       }
                       System.debug('====LAT====' +lat);
 
                }
            }
 
            // update coordinates if we get back
            if (lat != null && lon!=null){
                a.BankNameSpace__Latitude__c= String.valueOf(lat);
                a.BankNameSpace__Longitude__c= String.valueOf(lon);
                System.debug('=======>>'+a);
                try
                {
                    
                    aa.add(a);
                //update a;
                }catch (Exception e) {
               //sp = Database.setSavepoint();     
                }
            }
    }   
           LocationControl.inFutureContext = true;
           update aa;
       }
     }
}


the above code will calculate the logitide and latitude values of account address.

Thanks,
Ramesh
ChandraChoukseyChandraChouksey
Hi  Venkata,

Did you get resolution of this issue? I'm also getting exactly same issue with same code lines in one of the org. In other orgs it is working fine.

Thanks 
CP Chouksey