Salesforce and Box integration using Apex

by Rijwan Mohmmed
34 comments
salesforce-and-box-integration-using-apex-techdicer

Hello friends, today we are going to discuss Salesforce and Box integration using Apex via Rest API. Mainly we use the Box platform to store files. We also create folders, share folders/files with the team, create team in Box is a cloud content management system.

How to integrate Box with Salesforce.

check this: Send SMS Via Twilio In Apex Rest API

Using Box, you can store your files in the cloud, decide who can view/edit your files, access them on the go. They secure storage of your data and advanced collaboration possibilities.

salesforce-and-box-integrations-using-apex-techdicer2

Highlights Points :

  1. We can eailsy upload the files upto 50MB above this use chunk api
  2. Use Rest API.
  3. We will do Authetication by grant_type=client_credentials, i mean username , password.
  4. We also share the files/folder by using email id.

Let’s start with an example.

Step 1: In this step, we will create a box account. You can also log in with Gmail.

salesforce-and-box-integration-using-apex-signin-techdicer

Step 2: In this, we will set up the app, so we can get the client id and password for auth. if you can’t see the below screen then click here. Create a new app and select a custom app, also select grant_type=client_credentials for authentication.

salesforce-and-box-integration-using-apex-create-app-techdicer
salesforce-and-box-integration-using-apex-create-app-techdicer
salesforce-and-box-integration-using-apex-create-app-Auth-type-techdicer
salesforce-and-box-integration-using-apex-create-app-Auth-type-techdicer

Step 3: In this we will set two-step verification, by going account setting. click here . after this Authorize the app for this click here.

salesforce-and-box-integration-using-apex-authorize-app-techdicer
salesforce-and-box-integration-using-apex-authorize-app-techdicer

Step 4: In this step, we will create an apex class in which we will write the logic for getting access tokens, create a folder, upload files, and share folder/file. you can also do more things with Box API. In apex class, we can’t upload blob direct on Box so we will convert this to binary data and upload it in Box Storage.

BoxCtrl.cls :

public class BoxCtrl {

    @AuraEnabled
    public static String createFolder(String parentFolderId, String folderName){
        String accessToken = getAccessToken();
        System.debug(accessToken);
        String body = '{ "name": "' + folderName + '", "parent": { "id": "' + parentFolderId + '" } }';
        String endpoint = 'https://api.box.com/2.0/folders'; 
        // define transaction variables
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http h = new Http();

        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type','application/json');
        req.setHeader('Authorization', 'Bearer ' + accessToken);
        req.setHeader('Accept', 'application/json');
        req.setBody(body);
        System.debug(req.getBody());
        //req.setTimeout(120000);
        res = h.send(req);
        if ((res.getStatusCode() == 200 || res.getStatusCode() == 201) && res.getBody() != null && res.getBody() != null) {
            Map<String, Object> untypedMap = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
            System.debug(untypedMap);
            return 'Folder created successfully!';
        }else{
            throw newMessageException('Error while creating folder');
        }
    }

    public static void moveFolder(String parentFolderId, String folderId){
        String accessToken = getAccessToken();
        System.debug(accessToken);
        String body = '{ "parent": { "id": "' + parentFolderId + '" } }';
        String endpoint = 'https://api.box.com/2.0/folders'; 
        // define transaction variables
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http h = new Http();

        req.setEndpoint(endpoint + '/' + folderId);
        req.setMethod('PUT');
        req.setHeader('Content-Type','application/json');
        req.setHeader('Authorization', 'Bearer ' + accessToken);
        req.setHeader('Accept', 'application/json');
        req.setBody(body);
        System.debug(req.getBody());
        res = h.send(req);
        if ((res.getStatusCode() == 200 || res.getStatusCode() == 201) && res.getBody() != null && res.getBody() != null) {
            Map<String, Object> untypedMap = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
            System.debug(untypedMap);
        }
    }

    public static void shareFolder(String folderId, String shareToUserEmail){
        String accessToken = getAccessToken();
        String body = '{ "item": { "type": "folder", "id": "' + folderId + '" }, "accessible_by": { "type": "user", "login": "' + shareToUserEmail + '" }, "role": "editor" }';
        String endpoint = 'https://api.box.com/2.0/collaborations'; 
        // define transaction variables
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http h = new Http();

        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type','application/json');
        req.setHeader('Authorization', 'Bearer ' + accessToken);
        req.setHeader('Accept', 'application/json');
        req.setBody(body);
        res = h.send(req);

        if ((res.getStatusCode() == 200 || res.getStatusCode() == 201) && res.getBody() != null && res.getBody() != null) {
            Map<String, Object> untypedMap = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
            System.debug(untypedMap);
        }
    }

    public static String getAccessToken(){
        String username = 'xxxxxxxxxxxxxxxx';
        String password = 'xxxxxxxxxxxxxxxx';
        String endpoint = 'https://api.box.com/oauth2/token'; // be sure this is configured in "Remote Site Settings"
        String boxSubjectId = '17943781903';
        // define transaction variables
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http h = new Http();

        // Configure the request
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type','application/x-www-form-urlencoded');
        req.setTimeout(120000);
        string payload = 'client_id=' + username + '&client_secret=' + password + '&grant_type=client_credentials&box_subject_type=user&box_subject_id=' + boxSubjectId;
        req.setBody(payload);
        res = h.send(req);
        if ((res.getStatusCode() == 200 || res.getStatusCode() == 201) && res.getBody() != null && res.getBody() != null) {
            Map<String, Object> untypedMap = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
            if(untypedMap.containsKey('access_token')){
                return (String) untypedMap.get('access_token');
            }
            return '';
        }else{
            return '';
        }
    }

   //code to upload files to BOX.COM
    @AuraEnabled
   public static String uploadFile(String base64, String filename, String folderId){
        String accessToken = getAccessToken();
        if(base64!=null){
            blob base64EncodeFile = base64EncodeFileContent(EncodingUtil.base64Decode(base64), filename);
            String uploadEndPointURL='https://upload.box.com/api/2.0/files/content?parent_id='+folderId;
            String boundary = '----------------------------741e90d31eff';
            String body = '{"name":"' + filename + '", "parent":{"id":"' + folderId + '"}}';
            HttpRequest req = new HttpRequest();
            req.setBody(body);
            req.setBodyAsBlob(base64EncodeFile);
            req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
            //req.setHeader('Content-Length',String.valueof(req.getBodyAsBlob().size()));
            req.setHeader('Authorization', 'Bearer ' + accessToken);
            req.setMethod('POST');
            req.setEndpoint(uploadEndPointURL);
            req.setTimeout(120000);
            //Send request to Box
            Http ht = new Http();
            HTTPResponse res = ht.send(req);
           
            System.debug('**Files upload Response: ' + res.getBody());
            Integer uploadStatusCode=res.getStatusCode();
            if(uploadStatusCode==201){
                return 'File uploaded successfully.';
            }else{
              throw newMessageException('Error encountered. Status Code: ' + uploadStatusCode);                
            }
        }else{
            throw newMessageException('Please select file.');
        }
   }

    private static AuraHandledException newMessageException(String message) {
        AuraHandledException e = new AuraHandledException(message);
        e.setMessage(message);
        return e;
    }

    public static blob base64EncodeFileContent(Blob file_body, String file_name){
        String boundary = '----------------------------741e90d31eff';
        String header = '--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="'+file_name+'";\nContent-Type: application/octet-stream';
        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 = EncodingUtil.base64Encode(file_body);
        Blob bodyBlob = null;
        String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
 
        if(last4Bytes.endsWith('==')) {
            last4Bytes = last4Bytes.substring(0,2) + '0K';
            bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
            String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
        } else if(last4Bytes.endsWith('=')) {
            last4Bytes = last4Bytes.substring(0,3) + 'N';
            bodyEncoded = bodyEncoded.substring(0,bodyEncoded.length()-4) + last4Bytes;
            footer = '\n' + footer;
            String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);              
        } else {
            footer = '\r\n' + footer;
            String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
            bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);  
        }
 
        return bodyBlob;
    }
}

Step 5: In this step, we will create LWC Component for the user interface. I create 2 Card here so first you can create a folder and in the second one you can upload files. We will upload files to the apex In LWC by the custom way.

BoxAPILWC.HTML:

<template>
	  <!-- loader -->
    <div if:true={showSpinner}>
        <lightning-spinner
            alternative-text="Loading..." variant="brand" class="slds-is-fixed">
        </lightning-spinner>
    </div>
    <!------------->
    <div class="slds-tabs_card">
		<div class="slds-page-header">
			<div class="slds-page-header__row">
				<div class="slds-page-header__col-title">
					<div class="slds-media">
						<div class="slds-media__figure">
							<span class="slds-icon_container slds-icon-standard-opportunity">
								 <lightning-icon icon-name="standard:recipe" alternative-text="recipe" title="recipe"></lightning-icon>
                            </span>
						</div>
						<div class="slds-media__body">
							<div class="slds-page-header__name">
								<div class="slds-page-header__name-title">
									<h1>
										<span>Box API Call From Apex</span>
										<span class="slds-page-header__title slds-truncate" title="Recently Viewed">TechDicer</span>
									</h1>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div> <br/>
    <!-- create folder card -->
    <lightning-card  variant="Narrow"  title="Box API For Create Folder" icon-name="standard:folder">
        <div class="slds-var-p-around_small">
            <lightning-layout multiple-rows>
				<lightning-layout-item padding="around-small" size="12" medium-device-size="12" large-device-size="12">
                    <lightning-input name="newFolderName" class="fieldvalidate" type="text"
                                     label="Folder Name" required>
                    </lightning-input>
				</lightning-layout-item>

                <lightning-layout-item size="12" class="slds-var-p-top_small">
					<lightning-button class="slds-align_absolute-center" variant="brand" label="Create Folder"
						onclick={handleCreateFolder}>
                    </lightning-button>
				</lightning-layout-item>
            </lightning-layout>
        </div>
    </lightning-card><br/>

    <!-- Upload files card -->
    <lightning-card  variant="Narrow"  title="Box API For Upload Files" icon-name="standard:file">
        <div class="slds-var-p-around_small">
            <lightning-layout multiple-rows>
				<lightning-layout-item padding="around-small" size="12" medium-device-size="12" large-device-size="12">
                    <lightning-input name="folderName" class="fieldvalidateFile" type="tel"
                                     label="Folder Id" onchange={handleFolderName}>
                    </lightning-input><br/>
                    <lightning-input label="File" name="file uploader" 
                                     onchange={handleFilesChange} type="file">
                    </lightning-input>
				</lightning-layout-item>

                <lightning-layout-item size="12" class="slds-var-p-top_small">
					<lightning-button class="slds-align_absolute-center" variant="brand" label="Upload Files"
						onclick={uploadFileToBox}>
                    </lightning-button>
				</lightning-layout-item>
            </lightning-layout>
        </div>
    </lightning-card>
    
</template>

BoxAPILWC.JS:

import { LightningElement, track } from 'lwc';
import createFolder from "@salesforce/apex/BoxCtrl.createFolder";
import uploadFile from '@salesforce/apex/BoxCtrl.uploadFile';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';

export default class BoxAPILWC extends LightningElement {
    @track fileName = '';
    @track showSpinner = false;
    content;
    fileData;
    newFolderName;
    folderId;


    handleCreateFolder(event){
        const inputValidation = [...this.template.querySelectorAll('.fieldvalidate')]
            .reduce((validSoFar, inputField) => {
                inputField.reportValidity();
                return validSoFar && inputField.checkValidity();
            }, true);
        if (inputValidation) {
         //perform success logic
          let inputFields = this.template.querySelectorAll('.fieldvalidate');
          inputFields.forEach(inputField => {
            if(inputField.name == "newFolderName"){
                this.newFolderName = inputField.value;
            }
           });
           this.handleApexCallCreateFolder();
        }
    }

    handleApexCallCreateFolder(){
        this.handleSpinner();
        console.log(this.newFolderName);
        createFolder({parentFolderId : '0', folderName : this.newFolderName})
        .then(res=>{
            this.ShowToast('Success!', 'Folder Create Successfully', 'success', 'dismissable');
        }).catch(err=>{
            this.ShowToast('Error!!', err.body.message, 'error', 'dismissable');
        }).finally(() => {
            this.handleSpinner();
        })
    }

    handleFolderName(event){
        this.folderId = event.target.value;
    }

     // getting file 
    handleFilesChange(event) {
        if(event.target.files.length > 0) {
            const file = event.target.files[0]
            var reader = new FileReader()
            reader.onload = () => {
                var base64 = reader.result.split(',')[1]
                this.fileData = {
                    'filename': file.name,
                    'base64': base64,
                    'recordId': this.folderId
                }
                console.log(this.fileData)
            }
            reader.readAsDataURL(file)
        }
    } 

    // Calling apex class to upload the file to box storage
    uploadFileToBox() {
        this.handleSpinner();
        const {base64, filename, recordId} = this.fileData
        uploadFile({ base64 : base64, filename:filename, folderId:recordId }).then(result=>{
            this.fileData = null
            let title = `${filename} uploaded successfully!!`;
            this.ShowToast('Success!', title, 'success', 'dismissable');
        }).catch(err=>{
            this.ShowToast('Error!!', err.body.message, 'error', 'dismissable');
        }).finally(() => {
            this.handleSpinner();
        })
    }

    handleSpinner(){
        this.showSpinner = !this.showSpinner;
    }

    ShowToast(title, message, variant, mode){
        const evt = new ShowToastEvent({
            title: title,
            message:message,
            variant: variant,
            mode: mode
        });
        this.dispatchEvent(evt);
    }
}

Output :

salesforce-and-box-integrations-using-apex-techdicer-Output

What’s your Reaction?
+1
1
+1
2
+1
0
+1
0
+1
1
+1
1

You may also like

34 comments

Ram July 11, 2022 - 8:15 am

Not Working

Reply
Rijwan Mohmmed July 11, 2022 - 11:03 am

Hi Ram, Can you please explain your issue.

Reply
raj July 19, 2022 - 4:48 pm

CreateFolder not working

Reply
Rijwan Mohmmed July 20, 2022 - 5:25 am

Can you please share me error? And are you giving correct parentFolderId. You can copy this folder Id by Box Admin

Reply
Hussnain Ali July 19, 2022 - 7:12 pm

Not Working
“error”: “invalid_grant”,
“error_description”: “Grant credentials are invalid”

Reply
Rijwan Mohmmed July 20, 2022 - 5:25 am

Check your username and password and also check is this authorized in Box

Reply
anonymous July 21, 2022 - 11:37 am

Hey Rijwan, Could you please tell me where are you authorizing the user?

Reply
Rijwan Mohmmed July 21, 2022 - 6:54 pm

I have authorized the user by Box Sandbox and you can check my all steps. Check steps 2 and 3. Can you please Share error?

Reply
anonymous July 22, 2022 - 11:23 am

I used the same code which you have shared above. I have created one app but that app is not authorized yet by the Box Admin. While hitting endpoint I am getting “System.HttpResponse[Status=Bad Request, StatusCode=400]”. Could you please let me know what mistake I am making here. Thanks

Reply
Rijwan Mohmmed July 23, 2022 - 5:34 am

Read the document of box api app setup, search the issue what you are getting

Reply
anonymous July 26, 2022 - 1:10 pm

public static string getAccessToken(){
String clientid = ‘*****’;
String clientpassword = ‘*****’;
string username = ‘*****’;
string password = ‘*****’;
String endpoint = ‘https://api.box.com/oauth2/token’;
String boxSubjectId = ‘19487182152’;

HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http h = new Http();

// Configure the request
req.setEndpoint(endpoint);
req.setMethod(‘POST’);
req.setHeader(‘Content-Type’,’application/x-www-form-urlencoded’);
string payload = ‘grant_type=client_credentials&client_id=’+clientid+’&client_secret=’+clientpassword+’&username=’+username+’&password=’+password;
system.debug(‘payload–‘+payload);
req.setBody(payload);
res = h.send(req);
system.debug(‘res–‘+res);
if ((res.getStatusCode() == 200 || res.getStatusCode() == 201) && res.getBody() != null && res.getBody() != null) {
Map untypedMap = (Map)JSON.deserializeUntyped(res.getBody());
if(untypedMap.containsKey(‘access_token’)){
return (String) untypedMap.get(‘access_token’);
}
return ”;
}else{
return ”;
}

This code I am using, but getting “error”:”invalid_grant”,”error_description”:”Grant credentials are invalid”.

Reply
Rijwan Mohmmed July 28, 2022 - 11:52 am

Can you please check your App in Box dashboard

Reply
anonymous August 5, 2022 - 5:21 pm

What is this String boundary = ‘—————————-741e90d31eff’? From where you got this value?

Reply
Rijwan Mohmmed August 6, 2022 - 5:56 pm

I got this from a document

Reply
anonymous August 8, 2022 - 10:53 am

Could you please tell me will this code upload any file in readable format like png, csv, pdf, mov etc or only text file?

Reply
Rijwan Mohmmed August 8, 2022 - 6:16 pm

All files. is your box integrations working?

Reply
anonymous August 9, 2022 - 2:18 pm

Yes, It is working, but I am not able to upload files larger than 7mb to box. How can we overcome this issue?

Reply
Rijwan Mohmmed August 11, 2022 - 2:31 pm

what is the error?

Reply
Rijwan Mohmmed August 12, 2022 - 7:22 pm

Hi can you share your error

Reply
anonymous August 14, 2022 - 8:04 am

string length exceeds maximum: 12000000.

Reply
Rijwan Mohmmed August 15, 2022 - 2:23 pm

Hi I think you need to use direct upload By LWC without the use of Apex class, Below is the link please check
https://techdicer.com/upload-image-by-http-callout-in-lwc/

Reply
anonymous September 7, 2022 - 7:20 am

Hi, Do you have any idea that how can I upload file to BOX directly from js by using fetch API or XMLHTTP. Thanks

Reply
Rijwan Mohmmed September 8, 2022 - 1:25 pm

Hi,
You can check my blog for upload images directly from JS
https://techdicer.com/upload-image-by-http-callout-in-lwc/

Reply
baccaratcommunity September 13, 2022 - 7:47 am

The assignment submission period was over and I was nervous, baccaratcommunity and I am very happy to see your post just in time and it was a great help. Thank you ! Leave your blog address below. Please visit me anytime.

Reply
Reina.U September 26, 2022 - 7:35 am

Hi,
Thank you for your useful information.
I can not able to upload files larger to box. (10MB)
Error ‘Apex heap size too large’
Do you have any good solutions ?
Thanks

Reply
Rijwan Mohmmed September 27, 2022 - 5:35 pm

Hi Reinu, Apex has some limit but you can directly upload the images Via. LWC without the use of Apex,
https://techdicer.com/upload-image-by-http-callout-in-lwc/

Reply
Ajaay Karthik December 16, 2022 - 9:51 am

Hey Rijwan.
I have two doubts
1) from the Apex code you posted , I just need to upload a file to Box folder
I have the folder id with me.
I have changed clientSecret clientId and BoxSubjectId as per your instructions
Now If I try to upload a file into the folder using its folder id , I am getting 400 bad request

2)Then I tried to upload file to its root folder by setting the parent id to 0 , I am getting “Files Uploaded Successfully” message , but the file is not shown in my Box Folder. Even if I upload the same file again , I am getting a 409 code with a message like “File name already exists” kind of message

Please help me dude!!!

Reply
Rijwan Mohmmed December 16, 2022 - 12:28 pm

Check Box setting , if file is uploading then file will be there.

Reply
Ajaay Karthik December 19, 2022 - 5:53 am

By Box Setting , do you mean Account Settings or some other Settings?

Reply
Ajaay Karthik December 20, 2022 - 9:31 am

Rijwan,
If possible could you please upload another version of this code where Authorization is done using JWT . I tried but I have some issues regarding Certificate Uploading in Salesforce

Reply
Minerva January 10, 2024 - 2:48 pm

I want to upload multiple files, can you give me code for this functionality.

Reply
Rijwan Mohmmed January 10, 2024 - 3:18 pm

Hi @Minerva, you can do this call apex method in for loop in lwc

Reply
Rania September 26, 2024 - 9:01 pm

I have followed the same steps I worked for but after a few days, it is giving me invalid_grant.

Reply
Rijwan Mohmmed September 27, 2024 - 3:45 am

Check box app , is this active or not .

Reply

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.