+ Start a Discussion
Alok_NagarroAlok_Nagarro 

Web service callout failed: String length exceeds maximum: 1000000

Hi All,

 

We are facing a strange issue while trying to make webservice callout and getting file content as response. Issue is that if file size is greater than 200Kb then callout is failed and throwing the exception as given below ---

 

"Web service callout failed: String length exceeds maximum: 1000000"

 

Also wondering ,it's mentioned in SF doc that max Payload size limit is 3MB for callout request as well as response.

And i am able to send data in request upto 3 MB but not able to get data as response if it's >200KB.

 

Can anyone suggest what need to do, or am i missing something.?

 

Plz help, Its URGENT.

AmitSahuAmitSahu

You are using REST API, right ?

Alok_NagarroAlok_Nagarro

No, we are using SOAP API......

rajjjjrajjjj

I am also facing the same issue....As far as i read through different posts....you can upload a maximum size of 3MB but u cannot download a file greater than 1 MB....

If you know a way to do it...plz post it here.

AmitSahuAmitSahu

You are correct Rajjjj . You can donwload only 1 MB file. You can limit your return result , while making a callout. for example If your current query returns all the data from the object you can use some filters to limit those return results.

 

If you can post sample code, it will be helpfull.

Alok_NagarroAlok_Nagarro

Hi Rajjjj,

 

You can try it with HTTP callout rather than SOAP callout as i did. Using HTTP callout i was able to download/upload up to 3MB data.

 

 

 

rajjjjrajjjj
@future(callout=true)
  public static void updateAccounts(List<Id> accountIds)
  {
  // get the custom city, state and country fields from account
    //List<Account> accounts = [select Id, Name, BillingCity, BillingState, BillingCountry
      //from Account where Id in :accountIds ];
    for(Account theAccount: [select Id, Name, BillingCity, BillingState, BillingCountry from Account where Id in :accountIds ]) { 
      
      List<String> address = new List<String>();
      address.add('');// empty street
      address.add(theAccount.BillingCity);
      address.add(theAccount.BillingState);
      address.add(theAccount.BillingCountry);
      String[] coordinates = GeoUtilities.getCoordinates(address);
      if(coordinates != null)
      {
        Decimal pos1 = Decimal.valueOf(coordinates[0].trim());
        theAccount.Latitude__c = pos1;
        Decimal pos2 = Decimal.valueOf(coordinates[1].trim());
        theAccount.Longitude__c = pos2;
        system.debug(Logginglevel.ERROR,'GeoUtilities coordinates ' + pos1 + ' ' + pos2 );    
      }
      else
      {
        system.debug(Logginglevel.ERROR,'GeoUtilities no coordinates!!! for address' );          
      }
      update theAccount; 
    }
    
  }

   
   public static String[] getCoordinates(String[] addressParts)
    { 
      String[] Coordinates; 
      String address = '';
      boolean needComma = false;
      system.debug(''+address);
      system.debug(''+address.length());
      
      for(Integer i = 0; i<10; i++)
        {
          if(needComma)
            address = address + ',';
          address = address + EncodingUtil.urlEncode(address,'UTF-8');
          needComma = true;
        }
    
	  if(address.length() == 0)
	  {
	    system.debug(Logginglevel.ERROR,
	      'GeoUtilities getCoordinates no address provided. Return null');    
	    return null; 
	  }
      system.debug(''+address);
      system.debug(''+address.length());
      
	  String url = 'http://geocoder.us/member/service/csv/geocode?q=street=701+First+Ave&city=Sunnyvale&state=CA&country...
	  
	  //url += 'q=' + address; 
	  //url += '&output=csv'; 
	  
	  system.debug(Logginglevel.ERROR,'GeoUtilities getCoordinates url: ' + url);    
	  
	  Http h = new Http(); 
	  HttpRequest req = new HttpRequest();
	  
	  req.setHeader('Content-type', 'application/x-www-form-urlencoded'); 
	  req.setHeader('Content-length', '0'); 
	  req.setEndpoint(url); 
	  req.setMethod('POST');
	  String responseBody;
	  if (!Test.isRunningTest())
	  { 
	  // Methods defined as TestMethod do not support Web service callouts
	    HttpResponse res = h.send(req); 
	    responseBody = res.getBody();
	  }
	  else 
	  {
	    // dummy data
	    responseBody = '200,4,48.5,-123.67';
	  } 
	  String[] responseParts = responseBody.split(',',0); 
	  // the response has four parts: 
	  // status code, quality code, latitude and longitude
	  Coordinates = new String[2];
	  Coordinates[0] = responseParts[2];
	  Coordinates[1] = responseParts[3];
	    
	  return Coordinates; 
	 
	  }
  
  static testMethod void  testGetGeo()
  {
    String[] addressParts;
    String[] coordinates;
    
    addressParts = new List<String>();
    addressParts.add('');
    addressParts.add('San Diego');
    addressParts.add('CA');
    addressParts.add('USA');
    
    coordinates = GeoUtilities.getCoordinates(addressParts);
    System.assert(coordinates != null);
    System.assertEquals(2, coordinates.size()); 
  }
}

 I am trying Http callout only...I donno how to parse HTML response...

Do u have any idea of how to do it???????

rajjjjrajjjj

This is the response i am getting...

I need to parse that response and get back only latitude and longitude.

14:17:46.320 (320263000)|USER_DEBUG|[97]|DEBUG|printing responseBody-----------><html>
<head>
    <title>geocoder.us: a free US geocoder</title>
    <link rel="stylesheet" href="/style.css" />
</head>
<body>
<!-- this div is opened here, closed in the footer or somewhere else -->
<div align="center">
<script type="text/javascript"><!--
google_ad_client = "pub-1219510847949987";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = ["336699","B4D0DC","DDB7BA","FDEFD2"];
google_color_bg = ["FFFFFF","ECF8FF","FFF5F6","FDEFD2"];
google_color_link = ["0000FF","0000CC","0000CC","0000CC"];
google_color_url = "008000";
google_color_text = ["000000","6F6F6F","6F6F6F","000000"];
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

<!--
<h2><a href="/blog">Read the Geocoder.US Blog</a></h2>
-->
 <hr>

  <div id="header"
  <a href="/"><h1>geocoder.us</a>
  find the latitude &amp; longitude of any US address - for <em>free</em></h1>
  </div>


<!-- you have to manually import the navigation.html file here -->
  <div id="navi">

			<a href="http://geocoder.us/"><div class="naviitem" id="naviactive">HOME</div></a>
			<a href="http://geocoder.us/help/"><div class="naviitem" >Documentation/Help</div></a>
			<a href="http://geocoder.us/help/faq.shtml"><div class="naviitem" >FAQ</div></a>
			<a href="http://geocoder.us/help/member.shtml"><div class="naviitem" >Member Info</div></a>
			<a href="http://geocoderus.blogspot.com" target=top><div class="naviitem" >Geocoder Blog</div></a>
			<a href="http://geocoder.us/about_us.shtml" target=top><div class="naviitem" >About us/looking foward</div></a>
			<!-- a href="./about.html"><div class="naviitem" >About</div></a -->
		</div>


<div align="center">
    <h2>Authorization Required</h2>
</div>

<div style="font-size: 10pt; width: 50%">
<p>A valid user account is required to access this feature. You can <a
href="/user/signup">sign up for a new account</a>, <a
href="/member/account">log in to an existing account</a> or <a
href="/user/reset">request a new password</a> for your account.</p> </div>

<p>
If you want to use the web services interface to the free service use these URL's, and do not add your username and password.
<p>

The service URLs are as follows:
<pre>
    http://geocoder.us/service/xmlrpc
    http://geocoder.us/service/soap
    http://geocoder.us/service/rest/...
    http://geocoder.us/service/csv/...
</pre>

The absolute simplest way to get a geocode from the free service is to use the csv interface. Entering this in your browser:
<p>
 http://rpc.geocoder.us/service/csv?address=1600+Pennsylvania+Ave,+Washington+DC
<p>
Returns this result:
<p>
38.898748,-77.037684,1600 Pennsylvania Ave NW,Washington,DC,20502
<p>

<hr noshade="1" width="90%" />
<div class="footer">
    = <a href="/">geocoder.us</a> = &copy; 2004-8 <a
href="http://locative.us/">Locative Technologies</a> = <a
href="/terms.shtml">terms &amp; conditions</a> = <a
href="mailto:contact@geocoder.us">contact us</a> = 
</div>
<div class="footer">

<!-- Open Knowledge Link -->
<a href="http://okd.okfn.org/"> <img alt="This material is Open Knowlege" border="0" src="http://m.okfn.org/images/ok_buttons/ok_80x23_blue.png" height="31" vspace="5" /></a> <!-- /Open Knowledge Link -->
<a href="http://www.perl.org"><img src="/img/rectangle_power_perl.png" width="88" height="31" hspace="5" vspace="5" border="0" /></a>
<a href="http://creativecommons.org/licenses/by-nc-sa/2.0/"><img src="/img/somerights20.png" width="88" height="31" hspace="5" vspace="5" border="0" /></a>
<!-- PayPal Logo --><table border="0" cellpadding="10" cellspacing="0" align="center"><tr><td align="center">

<tr><td align="center"><a href="#" onclick="javascript&colon;window.open('https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/popup/OLCWhatIsPayPal-outside','olcwhatispaypal','t... location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, width=400, height=350');"><img  src="https://www.paypal.com/en_US/i/logo/PayPal_mark_60x38.gif" border="0" alt="Acceptance Mark"></a></td></tr></table><!-- PayPal Logo -->

</td></tr>
</div>
</div> 
</body>

</html>
Starz26Starz26

If all you need is a LatLong from an address, add the google url to the security settings and use this to return the lat long. Modify as needed to store the results. The attached code is called when a SINGLE account is updated. The section starting at Account a = [Select....... is where I grab the account and populate. this is what you will need to change to store on the appropriate object.

 

I have a version for mapquest to as they do not have a limit on the number of calls but you have to request an API key (very easy)

 

public class geocodeAddress{

    @future(callout=true)
    public static void getLatLng(ID acctID, String addy){
    
        HttpRequest req = new HttpRequest();
        Http http = new Http();
        
        req.setMethod('GET');
        addy = addy.replace(' ','+');
        
        String url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + addy + '&sensor=false';
        
        system.debug('URL is = ' + url);    

        req.setEndPoint(url);
        
        HTTPResponse resp = http.send(req);
        

        try{        
            geocodeInformation results = (geocodeInformation)JSON.deserialize(resp.getBody(), geocodeInformation.class);
            
            Account[] a = [Select Latitude__c, Longitude__c From Account Where ID = :acctID];
            
            if(results.status == 'OK'){
               
                if(!a.isEmpty()){
                    a[0].Latitude__c = results.results[0].geometry.location.get('lat');
                    a[0].Longitude__c = results.results[0].geometry.location.get('lng') ;
                    a[0].Latitude_Longitude_Status__c = 'OK: ' + a[0].Latitude__c + ' : ' + a[0].Longitude__c;
                    update a;
                }
            
            }else{
                a[0].Latitude__c = null;
                a[0].Longitude__c = null;
                a[0].Latitude_Longitude_Status__c = results.status;
                update a;   
            }
             
        }catch (exception e){
            system.debug(e.getMessage());
        }
        


    }
    
    
    private class geocodeInformation{
    
        data[] results;
        String status;
           
    
    }
    
    private class data{
    
        address_components[] address_components;
        String formatted_address;
        geometry geometry;
        
        
    }
    
    private class address_components{
    
        String long_name;
        String short_name;
        String[] types;
    
    }
    
    private class geometry{
    
        Map<String,decimal> location;
        String location_type;
        Map<String,Map<String,decimal>> viewport;
        String[] types;
    
    }
       


}
rajjjjrajjjj
trigger AccountBeforeUpsert1 on Account (after insert, after update) {
 
 Account a = [Select Id,Name From Account Where ID IN: Trigger.new];
//calling getLatLng method........from trigger
 geocodeAddress.getLatLng(a.Id,'123 4th Ave N,Seattle,WA,98109');
}

I am doing this trigger on account.

I am passing that account Id and an address for now.

For now i am trying to update any value and execute that trigger.

When i am calling that future method which u have specified it is throwing me an exception that "Future method cannot be called from another future or batch method."

Here is the debug log.

17:46:54.360 (360978000)|CODE_UNIT_STARTED|[EXTERNAL]|01qU0000000Lc7l|AccountBeforeUpsert1 on Account trigger event AfterUpdate for [001U0000003cUd6]
17:46:54.361 (361352000)|SYSTEM_METHOD_ENTRY|[2]|System.debug(APEX_OBJECT, ANY)
17:46:54.361 (361389000)|USER_DEBUG|[2]|ERROR|AccountBeforeUpsert geo updates
17:46:54.361 (361402000)|SYSTEM_METHOD_EXIT|[2]|System.debug(APEX_OBJECT, ANY)
17:46:54.361 (361708000)|SOQL_EXECUTE_BEGIN|[30]|Aggregations:0|select Id, Name from Account where ID IN :tmpVar1
17:46:54.363 (363774000)|SOQL_EXECUTE_END|[30]|Rows:1
17:46:54.363 (363927000)|CONSTRUCTOR_ENTRY|[31]|01pU00000016Y46|<init>(Id,String)
17:46:54.363 (363985000)|CONSTRUCTOR_EXIT|[31]|01pU00000016Y46|<init>(Id,String)
17:46:54.364 (364026000)|SYSTEM_CONSTRUCTOR_ENTRY|[33]|<init>()
17:46:54.364 (364053000)|SYSTEM_CONSTRUCTOR_EXIT|[33]|<init>()
17:46:54.364 (364090000)|SYSTEM_METHOD_ENTRY|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364109000)|SYSTEM_METHOD_EXIT|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364125000)|SYSTEM_METHOD_ENTRY|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364143000)|SYSTEM_METHOD_EXIT|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364154000)|SYSTEM_CONSTRUCTOR_ENTRY|[33]|<init>()
17:46:54.364 (364162000)|SYSTEM_CONSTRUCTOR_EXIT|[33]|<init>()
17:46:54.364 (364180000)|SYSTEM_METHOD_ENTRY|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364196000)|SYSTEM_METHOD_EXIT|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364213000)|SYSTEM_METHOD_ENTRY|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364228000)|SYSTEM_METHOD_EXIT|[33]|LIST<ANY>.add(Object)
17:46:54.364 (364335000)|EXCEPTION_THROWN|[33]|System.AsyncException: Future method cannot be called from a future or batch method: geocodeAddress.getLatLng(Id, String)
17:46:54.364 (364510000)|FATAL_ERROR|System.AsyncException: Future method cannot be called from a future or batch method: geocodeAddress.getLatLng(Id, String)

Trigger.AccountBeforeUpsert1: line 33, column 1
17:46:54.364 (364533000)|FATAL_ERROR|System.AsyncException: Future method cannot be called from a future or batch method: geocodeAddress.getLatLng(Id, String)

 

Starz26Starz26

It would appear that you have a natch or future method in your org that is updating the accounts and thus calling the geocode. You need to add a check int he trigger. Use the system.isFuture() == false && system.isBatch() == false to only run the geocode when the trigger is ran as a result of a non future or non-batch method

 

UPDATE - In my case I am only running the code if the address changes and thus when I update the account with the geocode information the @future is not called again. I see that you are running the @future each time the trigger is called. Either use the method above to not run on the update or only run in the trigger if specific conditions are met.