4

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

1 Answer 1

8

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
    Commented Jun 22, 2017 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
    Commented Jun 22, 2017 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
    Commented Jun 22, 2017 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
    Commented Jun 23, 2017 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. Commented Mar 26, 2020 at 19:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .