Find your people. Pick a challenge. Ship something real. The CreatorCon Hackathon is coming to the Community Pavilion for one epic night. Every skill level, every role welcome. Join us on May 5th and learn more here.

How to upload a file in form-data format?

梦李
Tera Contributor

Hello all!

I've encountered a very challenging issue where I need to upload a file along with several field information to a third-party system from ServiceNow. I chose the content type as multipart/form-data, used JSON format for the field information part, and utilized ServiceNow's getContentStream() method for the file part. However, the third-party system receives only com.glide.communications.GlideScriptableInputStream@ for the file part instead of the actual file content. Below is my code. Could anyone suggest a way to resolve this? This has been confusing me for a long time. Thank you very much.

 

 var request = new sn_ws.RESTMessageV2();

   request.setHttpMethod('POST');

   request.setEndpoint('http://xxxx.xxx.xxxx/upload');

   request.setRequestHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"); 

   var boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; 

   var requestBody = [];

   var jsonData = {

       P_NO: "tre123",

       P_Num: "6"

   };

   requestBody.push("--"+ boundary);

   requestBody.push('Content-Disposition: form-data; name="jsonData"');

   requestBody.push('Content-Type: application/json');

   requestBody.push('');

   requestBody.push(JSON.stringify(jsonData));

   requestBody.push("--"+ boundary);

   requestBody.push('Content-Disposition: form-data; name="P_FILE"; filename="'+ fileName + '"');

   requestBody.push('Content-Type: application/octet-stream');

   requestBody.push('');

   requestBody.push(fileContentStream);

   requestBody.push("--"+ boundary + "--");

   request.setRequestBody(requestBody.join('\r\n'));

3 REPLIES 3

Sreeram Nair
Tera Guru

The issue arises because ServiceNow's getContentStream() method returns a GlideScriptableInputStream, which needs to be properly converted into binary data to be included in the request body. Unfortunately, directly appending fileContentStream to the requestBody array won't work as expected for a multipart/form-data request.

Hopefully the following steps will help correct the code:

 

  • Use Base64 encoding to convert the file's content into a transferable format since ServiceNow doesn't natively support streaming raw binary data in the request body for multipart requests.
  • Include the Base64-encoded file data in the request body.
  • Use the appropriate Content-Transfer-Encoding for the file part.

 


ɪꜰ ᴍʏ ᴀɴꜱᴡᴇʀ ʜᴀꜱ ʜᴇʟᴘᴇᴅ ᴡɪᴛʜ ʏᴏᴜʀ Qᴜᴇꜱᴛɪᴏɴ, ᴘʟᴇᴀꜱᴇ ᴍᴀʀᴋ ᴍʏ ᴀɴꜱᴡᴇʀ ᴀꜱ ᴛʜᴇ ᴀᴄᴄᴇᴘᴛᴇᴅ ꜱᴏʟᴜᴛɪᴏɴ ᴀɴᴅ ɢɪᴠᴇ ᴀ ᴛʜᴜᴍʙꜱ ᴜᴘ.




ʙᴇꜱᴛ ʀᴇɢᴀʀᴅꜱ


ꜱʀᴇᴇʀᴀᴍ

Runjay Patel
Giga Sage

Hi @梦李 ,

 

Try below code.

var request = new sn_ws.RESTMessageV2();
request.setHttpMethod('POST');
request.setEndpoint('http://xxxx.xxx.xxxx/upload');

// Define the boundary for multipart data
var boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
request.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); 

// Prepare JSON data for the request
var jsonData = {
    P_NO: "tre123",
    P_Num: "6"
};

// Read file content as a byte array
var attachmentSysId = '<attachment_sys_id>'; // Replace with your file's sys_id
var attachmentTableName = '<table_name>'; // Replace with the table associated with the file
var attachmentFileName = '<file_name>'; // Replace with the file name

var attachmentGR = new GlideSysAttachment().getContentStream(attachmentSysId);

// Convert file stream to Base64 encoded string
var fileContent = new GlideSysAttachment().getBase64Content(attachmentTableName, attachmentSysId);

// Build the multipart request body
var requestBody = [];

// JSON Part
requestBody.push("--" + boundary);
requestBody.push('Content-Disposition: form-data; name="jsonData"');
requestBody.push('Content-Type: application/json');
requestBody.push('');
requestBody.push(JSON.stringify(jsonData));

// File Part
requestBody.push("--" + boundary);
requestBody.push('Content-Disposition: form-data; name="P_FILE"; filename="' + attachmentFileName + '"');
requestBody.push('Content-Type: application/octet-stream');
requestBody.push('');
requestBody.push(fileContent); // Add the file content as Base64-encoded data

// End boundary
requestBody.push("--" + boundary + "--");

// Set the request body
request.setRequestBody(requestBody.join('\r\n'));

// Execute the request
try {
    var response = request.execute();
    var responseBody = response.getBody();
    var httpStatus = response.getStatusCode();
    gs.print("Response: " + responseBody);
    gs.print("HTTP Status: " + httpStatus);
} catch (ex) {
    gs.print("Error: " + ex.message);
}

 

-------------------------------------------------------------------------

If you found my response helpful, please consider selecting "Accept as Solution" and marking it as "Helpful." This not only supports me but also benefits the community.


Regards
Runjay Patel - ServiceNow Solution Architect
YouTube: https://www.youtube.com/@RunjayP
LinkedIn: https://www.linkedin.com/in/runjay

-------------------------------------------------------------------------

@Runjay Patel  Hi Runjay, Is there any way to send an attachment with setRequestBodyFromAttachment() method with multipart/form-data in scoped app ? 3rd Party app is expecting 'input_file' with attachment hence asking (Please refer attached screenshot from Postman).

 

var resultGr = new GlideRecord("sn_customerservice_case");
resultGr.addQuery("sys_id", current.table_sys_id);
resultGr.addQuery("account", '<account sys id>'); // running for specific account
resultGr.query();
if (resultGr.next()) {
var caseid = resultGr.sys_id.toString();
gs.info("Case sys id : " + caseid);
try {
var r = new sn_ws.RESTMessageV2('New Integration', 'UploadAttachment');
r.setRequestBodyFromAttachment(current.sys_id);
r.setRequestHeader("Content-Type", resultGr.content_type);
r.setStringParameterNoEscape('request_id', resultGr.correlation_id);

 

var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
gs.info("The value of the POST Response is " + httpStatus + "Body : " + responseBody);
} catch (ex) {
var message = ex.message;
}
}

 

Screenshot 2025-03-05 220953.png