3

I am following through Dan's interesting blog (http://www.fishofprey.com/2017/04/steps-required-to-support-posting.html) which has proved to make the impossible possible on salesforce apex for lot Salesforce developer for POSTing multipart/form-data Content-Type (No Native Salesforce support for this at the moment).

I have tested the REST Endpoint using curl/Postman and it works without any issues. But when try from salesforce's HTTP callout, service responds with the below error.

502 - Kong Error: An invalid response was received from the upstream server.

It will immensely be appreciable if someone can correct me and point me in the right direction. Below is the Code that I am sharing with you.

public static void fileUploadCallout(string idStr) 
{
 string Endpoint = 'https:********';
 string xAPIKey = '***********';
 string verticalId = '*******';
 string callbackURL = '**************';

 List<contentversion> cvList = new List<contentversion>();
 cvList = [select id, title, ContentDocumentId, FileExtension, versionData, CMS_SEI_AV_Scan_Status__c, CMS_SEI_Scan_Status_Log__c from contentversion where Id = :idStr limit 1];
 System.debug('Callout Log 1:' + cvList);
 if(!cvList.isEmpty())     
 {
  //form fileName with cv ID
  string fileName = cvList[0].Id;
  if(cvList[0].FileExtension!=null && cvList[0].FileExtension!='')
  {
   fileName = fileName + '.' + cvList[0].FileExtension;  
  }         
  System.debug('Callout Log 2:' + fileName);

  //callout ePOR service
  string contentType = EinsteinVision_HttpBodyPart.GetContentType();

  //  Compose the form
  string form64 = '';

  form64 += EinsteinVision_HttpBodyPart.WriteBoundary();
  //form64 += EinsteinVision_HttpBodyPart.WriteBodyParameter('labelId', EncodingUtil.urlEncode(labelId, 'UTF-8'));
  //form64 += EinsteinVision_HttpBodyPart.WriteBoundary();
  form64 += EinsteinVision_HttpBodyPart.WriteBodyParameter('name', EncodingUtil.urlEncode(fileName, 'UTF-8'));
  form64 += EinsteinVision_HttpBodyPart.WriteBoundary();
  form64 += EinsteinVision_HttpBodyPart.WriteBodyParameter('data', EncodingUtil.base64Encode(cvList[0].versionData));
  form64 += EinsteinVision_HttpBodyPart.WriteBoundary(EinsteinVision_HttpBodyPart.EndingType.CrLf);

  blob formBlob = EncodingUtil.base64Decode(form64);
  string contentLength = string.valueOf(formBlob.size());

  System.debug('Callout Log 3:' + formBlob.size());

  if(formBlob.size()>12000000)
  {
   //this a "public class CustomException extends Exception{}"
   throw new CustomException('File size limit is 12 MBytes');
  }
  else
  {
     HttpRequest req = new HttpRequest();
     req.setMethod('POST');
     req.setEndpoint(Endpoint);
     req.setBodyAsBlob(formBlob);
     req.setHeader('apiKey', xAPIKey);
     req.setHeader('vertid', verticalId);
     req.setHeader('callback', callbackURL);
     req.setHeader('Connection', 'keep-alive');
     req.setHeader('Content-Length', contentLength);
     req.setHeader('Content-Type', contentType);
     req.setTimeout(120000);
     Http http =new Http();
     HTTPResponse res = http.send(req);
     System.debug('Callout Log 4:' + res.getStatusCode());
     System.debug('Callout Log 5:' + String.valueof(res.getbody()));

     string responseStatusCode = String.valueof(res.getStatusCode()); 
     string responseBody = String.valueof(res.getbody()); 

  }

http://www.fishofprey.com/2017/04/steps-required-to-support-posting.html

3
5

Rather than using EinsteinVision_HttpBodyPart.WriteBodyParameter to append the blob data you need to use EinsteinVision_HttpBodyPart.WriteBlobBodyParameter.

The latter performs extra steps to handle the encoding of the last bytes before the Boundary is added. Note that it will also write it's own boundary.


Final solution provided by @user2662369

@future(callout=true)
public static void fileUploadCallout(string idStr) 
{
 string Endpoint = 'https:********';
 string xAPIKey = '***********';
 string verticalId = '*******';
 string callbackURL = '**************';

 List<contentversion> cvList = new List<contentversion>();
 cvList = [select id, title, ContentDocumentId, FileExtension, versionData from contentversion where Id = :idStr limit 1];
 System.debug('Callout Log 1:' + cvList);
 if(!cvList.isEmpty())     
 {
  //form fileName with cv ID
  string fileName = cvList[0].Id;
  if(cvList[0].FileExtension!=null && cvList[0].FileExtension!='')
  {
   fileName = fileName + '.' + cvList[0].FileExtension;  
  }         
  System.debug('Callout Log 2:' + fileName);

  //callout ePOR service
  string contentType = EinsteinVision_HttpBodyPart.GetContentType();

  //  Compose the form
  string form64 = '';
  //******This was the boundary I was missing****
  form64 += EinsteinVision_HttpBodyPart.WriteBoundary();
  form64 += EinsteinVision_HttpBodyPart.WriteBlobBodyParameter('file', EncodingUtil.base64Encode(cvList[0].versionData), fileName);

  blob formBlob = EncodingUtil.base64Decode(form64);
  string contentLength = string.valueOf(formBlob.size());

  System.debug('Callout Log 3:' + formBlob.size());

  if(formBlob.size()>12000000)
  {
   //this a "public class CustomException extends Exception{}"
   throw new CustomException('File size limit is 12 MBytes');
  }
  else
  {
     HttpRequest req = new HttpRequest();
     req.setMethod('POST');
     req.setEndpoint(Endpoint);
     req.setBodyAsBlob(formBlob);
     req.setHeader('apiKey', xAPIKey);
     req.setHeader('vertid', verticalId);
     req.setHeader('callback', callbackURL);
     req.setHeader('Connection', 'keep-alive');
     req.setHeader('Content-Length', contentLength);
     req.setHeader('Content-Type', contentType);
     req.setTimeout(120000);
     Http http =new Http();
     HTTPResponse res = http.send(req);
     System.debug('Callout Log 4:' + res.getStatusCode());
     System.debug('Callout Log 5:' + String.valueof(res.getbody()));

     string responseStatusCode = String.valueof(res.getStatusCode()); 
     string responseBody = String.valueof(res.getbody()); 

  }
 }
}
14
  • Sure, will try that now. – Arif Jun 22 '17 at 4:36
  • curl -vk -X POST -F "file=@C:/Users/mrasheed/Desktop/Test.png" https://********.***.***/***/v2/objects/ -H "APIkey: ******************************" -H "verticalId: ************" -H "callbackurl: https://*********************************" – Arif Jun 22 '17 at 4:37
  • As per your suggestion, I changed it to EinsteinVision_HttpBodyPart.WriteBlobBodyParameter and the Service is still returning "502 - Kong Error: An invalid response was received from the upstream server." Thanks for the help. – Arif Jun 22 '17 at 5:07
  • 1
    I was missing the boundary before the line EinsteinVision_HttpBodyPart.WriteBlobBodyParameter. Thank you so much, Dan! I can't express this joy in words!!!!! Let me know if I need to do anything more than marking this answer!!!!! – Arif Jun 23 '17 at 0:58
  • 1
    @DanielBallinger I have posted question with examples and hosted a rest endpoint for you to try. Please have look, I am stuck here. salesforce.stackexchange.com/questions/299234/… Anonymous apex example has also been given. – Nagendra Singh Mar 26 '20 at 19:15

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.