You need to sign in to do that
Don't have an account?
Varun17
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"
}
}
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"
}
}
Try the suggestion as above mentioned.