Using box API [Upload file] from Servicenow

Amane1
Giga Guru

Hi Community.

I am trying to connect to box from ServiceNow using background script.

Here is my code.

 

var table_name = "x_common_center";
var sys_id = "01da168d834d5250e3d896b6feaad333";

var attachment = new GlideSysAttachment();
var agr = attachment.getAttachments(table_name, sys_id); // create attachment GlideRecord

while (agr.next()) {
    // for each attachment on the incident record
    var file_name = agr.getValue('file_name');
    var content_type = agr.getValue('content_type');
    gs.info('File Name: ' + file_name);
    gs.info('Content Type: ' + content_type);

    // Get the content stream (binary data)
    var is = attachment.getContentStream(agr.getUniqueValue());
    if (!is) {
        gs.error('No file content found for attachment: ' + file_name);
        continue; // Skip if no file content is found
    }

    // Define boundary and metadata
    var folder_id = "287704293536"; // Replace with actual folder ID in Box
    var date = new GlideDateTime();
    var formattedDate = date.getValue().replace(" ", "T") + "Z"; // Convert to RFC 3339 format
    var boundary = '----WebKitFormBoundary' + date.getNumericValue(); // Define unique boundary
    gs.info("Boundary: " + boundary);

    var request = new sn_ws.RESTMessageV2('global.Box Test', 'file upload to box');
    request.setHttpMethod('POST'); 
    request.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

    // Use getStreamWriter() to add boundaries and parameters
    var writer = request.getStreamWriter();

    // Write attributes part (metadata)
    writer.writeString("--" + boundary + "\r\n");
    writer.writeString('Content-Disposition: form-data; name="attributes"\r\n\r\n');
    writer.writeString('{"name":"' + file_name + '","parent":{"id":"' + folder_id + '"}, "content_created_at": "' + formattedDate + '", "content_modified_at": "' + formattedDate + '"}\r\n');

    // Write file part (binary content)
    writer.writeString("--" + boundary + "\r\n");
    writer.writeString('Content-Disposition: form-data; name="file"; filename="' + file_name + '"\r\n');
    writer.writeString('Content-Type: ' + content_type + '\r\n\r\n');
    writer.writeStream(is); // Write binary content (file)
    writer.writeString("\r\n--" + boundary + "--\r\n");

    // Execute the request
    var response = request.execute();
    var response_body = response.getBody();
    var response_code = response.getStatusCode();

    // Log the response
    gs.info("Response Code: " + response_code);
    gs.info("Response Body: " + response_body);
}

 

According to this source
it should work fine but response always returns: {"message": "API upload did not contain a file part","type":"error"}

 

Is there any other way to set binary data to reqeuest body?

I would be grateful if anyone has used the Box file upload API before. I have searched every single website I could find, but I still haven't figured out how.
 

13 REPLIES 13

Amane1
Giga Guru

I have tried a different approach as well. 

 

// Function to fetch the attachment from ServiceNow using GlideRecord
function getAttachmentContent(attachmentSysId) {
    var attachmentGR = new GlideRecord('sys_attachment');
    if (attachmentGR.get(attachmentSysId)) {
        var attachmentContentGR = new GlideRecord('sys_attachment_doc');
        attachmentContentGR.addQuery('sys_attachment', attachmentSysId);
        attachmentContentGR.query();

        var fileContent = '';
        while (attachmentContentGR.next()) {
            fileContent += attachmentContentGR.getValue('data'); // Attachment data is stored as base64 encoded string
        }

        var decodedContent = GlideStringUtil.base64Decode(fileContent); // Decode the base64 data
        return {
            fileName: attachmentGR.getValue('file_name'),
            fileData: decodedContent
        };
    } else {
        gs.error("Attachment with sys_id: " + attachmentSysId + " not found.");
        return null;
    }
}

// Function to construct multipart body content
function createMultipartBody(attributes, fileName, fileData) {
    var boundary = "----WebKitFormBoundary" + gs.generateGUID(); // Create a random boundary string

    // Build the multipart request body with attributes first and file content second
    var body = "";
    body += "--" + boundary + "\r\n";
    body += 'Content-Disposition: form-data; name="attributes"\r\n\r\n';
    body += attributes + "\r\n";
    body += "--" + boundary + "\r\n";
    body += 'Content-Disposition: form-data; name="file"; filename="' + fileName + '"\r\n';
    body += 'Content-Type: application/octet-stream\r\n\r\n';
    body += fileData + "\r\n";
    body += "--" + boundary + "--\r\n";

    return {
        body: body,
        boundary: boundary
    };
}

// Function to upload the file to Box
function uploadFileToBox(fileName, fileData) {
    var boxApiUrl = 'https://upload.box.com/api/2.0/files/content';
    var accessToken = 'YOUR_BOX_ACCESS_TOKEN';
    var parentFolderId = '0'; // Use '0' for root folder or specify a folder ID

    var attributes = JSON.stringify({
        name: fileName,
        parent: {
            id: parentFolderId
        }
    });

    var multipart = createMultipartBody(attributes, fileName, fileData);

     var request = new sn_ws.RESTMessageV2('global.Box Test', 'file upload to box');
    request.setHttpMethod('POST'); 
    request.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + multipart.boundary);

    // Set the body of the request
    request.setRequestBody(multipart.body);

    try {
        var response = request.execute();
        var responseBody = response.getBody();
        var httpStatus = response.getStatusCode();

        if (httpStatus === 201) {
            gs.info("File uploaded successfully to Box: " + responseBody);
        } else {
            gs.error("Failed to upload file to Box. Status: " + httpStatus + ", Response: " + responseBody);
        }
    } catch (ex) {
        gs.error("Error uploading file to Box: " + ex.message);
    }
}

// Main function to fetch the attachment from ServiceNow and upload it to Box
function uploadAttachmentToBox(attachmentSysId) {
    var attachment = getAttachmentContent(attachmentSysId);

    if (attachment) {
        gs.info("Successfully fetched attachment '" + attachment.fileName + "' from ServiceNow.");
        uploadFileToBox(attachment.fileName, attachment.fileData);
    }
}

uploadAttachmentToBox('305bd6cd834d5250e3d896b6feaad370');

 

The upload succeeds, but the file content is corrupted and unreadable.

 

Omkar Mone
Mega Sage

Do you get proper logs of the file content or do you get null?

Thank you for your message. It contains a decoded value, not null at least.
image.png

Plus, the thing is box API accepts string (binary) as file, so using [base64Decode] does not make sense.

 

Screenshot 2024-10-16 at 2.53.03 PM.png