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
Varun17Varun17 

Multipart form data from Salesforce to External System

Hi , 
I am able to post a file using form-data from postman to an external system and when I am trying to replicate the same from apex I am getting a 400 BAD REQUEST Error.

There is no difference in the request body being sent from Postman or Salesforce apex. Below is my postfile code . Any help is appreciated : 

Original code : 
 // assemble the body payload
   String boundary = '----------' + String.valueOf(System.currentTimeMillis());
        String header = '--' + 
                        boundary +
                        '\nContent-Disposition: form-data; name="profile"; \nContent-Type=application/json' +
                        '\n'+ jsonString + '\n' +
                        '--' +
                        boundary + 
                        '\nContent-Disposition: form-data; name="file"; filename="alternate name"' +
                        '\nContent-Type: application/octet-stream';
        String body = getFileContent(cdl) + '\n';
        System.debug('encodedbody'+body);
        String footer = '--' + boundary + '--';
        String bodyPayload = header + body + footer;
        
        
        HttpRequest req = new HttpRequest(); 
        //req.setHeader('Content-Type', 'application/json');
        req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
        req.setHeader('Content-Length',String.valueof(bodyPayload.length()));
        req.setHeader('X-Auth-Token', accessToken);
        req.setEndpoint(uploadUrl);
        req.setMethod('POST');
        req.setBody(bodyPayload);
        Http http = new Http();
        HTTPResponse res = http.send(req);

        String logoutUrl = credential.Server_URL__c + '/login/terminate';
        terminateSession(logoutUrl);

        System.debug('Request Endpoint: ' + req.getEndpoint());
        System.debug('Request Header: Content-Type ' + req.getHeader('Content-Type'));
        System.debug('Request Body: ' + req.getBody());

        System.debug('Status: '+res.getStatus());
        System.debug('Status Code : ' + res.getStatusCode());
        System.debug('Response Body: '+ res.getBody());
        
        if(customerId != '' || customerId != NULL){
            return TRUE;
        }
        else {
            return FALSE;
        }
    }
=================================================

I also followed below post to send base64 data - http://enreeco.blogspot.com/2013/01/salesforce-apex-post-mutipartform-data.html

I then updated my code to below. : 

String boundary = '----------' + String.valueOf(System.currentTimeMillis());
          String header = '--'+boundary+'\nContent-Disposition: form-data; name="profile"\nContent-Type=application/json'+'\n'+ jsonString + '\n' +'--'+boundary+'\nContent-Disposition: form-data; name="file"; filename= "hello_world.doc"\nContent-Type: application/octet-stream';
          //String header = '--'+boundary+'\nContent-Disposition: form-data; name="profile"; filename="DocUploadMetadata.json"'+'\n'+ jsonString + '\n' +'--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="Test Document.docx";';
         
          String footer = '--'+boundary+'--';             
                   
          String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
          while(headerEncoded.endsWith('='))
          {
           header+=' ';
           headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
          }
          
          String bodyEncoded = getFileContent(cdl);
     
          Blob bodyBlob = null;
          String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
 
          // GW: replacement section to get rid of padding without corrupting data
     if(last4Bytes.endsWith('==')) {
        // The '==' sequence indicates that the last group contained only one 8 bit byte
        // 8 digit binary representation of CR is 00001101
        // 8 digit binary representation of LF is 00001010
        // Stitch them together and then from the right split them into 6 bit chunks
        // 0000110100001010 becomes 0000 110100 001010
        // Note the first 4 bits 0000 are identical to the padding used to encode the
        // second original 6 bit chunk, this is handy it means we can hard code the response in
        // The decimal values of 110100 001010 are 52 10
        // The base64 mapping values of 52 10 are 0 K
        // See http://en.wikipedia.org/wiki/Base64 for base64 mapping table
        // Therefore, we replace == with 0K
        // Note: if using \n\n instead of \r\n replace == with 'oK'
        last4Bytes = last4Bytes.substring(0,2) + '0K';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the \r\n to the Blob, so leave footer as it is.
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
      } else if(last4Bytes.endsWith('=')) {
        // '=' indicates that encoded data already contained two out of 3x 8 bit bytes
        // We replace final 8 bit byte with a CR e.g. \r
        // 8 digit binary representation of CR is 00001101
        // Ignore the first 2 bits of 00 001101 they have already been used up as padding
        // for the existing data.
        // The Decimal value of 001101 is 13
        // The base64 value of 13 is N
        // Therefore, we replace = with N
        // Note: if using \n instead of \r replace = with 'K'
        last4Bytes = last4Bytes.substring(0,3) + 'N';
        bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
        // We have appended the CR e.g. \r, still need to prepend the line feed to the footer
        footer = '\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);              
      } else {
        // Prepend the CR LF to the footer
        footer = '\r\n' + footer;
        String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);  
        System.debug('bodyBlob: ' + bodyBlob);
      }
          
      HttpRequest req = new HttpRequest();
      req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
      req.setHeader('X-Auth-Token', accessToken);
      req.setMethod('POST');
      req.setEndpoint(uploadUrl);
      req.setBodyAsBlob(bodyBlob);
      req.setTimeout(120000);
 
      Http http = new Http();
      HTTPResponse res = http.send(req);

 
In both the above code I am getting below error. : 
{
"error": {
"code": "NRC_INVALID_PARAM",
"code_message": "Invalid parameter for request",
"details": "No JSON object could be decoded",
"message": "Invalid parameter for request"
}
}
AbhishekAbhishek (Salesforce Developers) 
https://salesforce.stackexchange.com/questions/122861/rest-api-working-well-from-postman-doesnt-work-from-salesforce

Try the suggestion as above mentioned.