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
Devid JohnDevid John 

How to upload more than 20MB File from salesforce(HTTP Request) to dropbox?

This below code is working perfect with 10 mb but when I try to upload more than 10mb file then it throws an error.
private string TOKEN = 'access_token_of_dropbox_app';//
string folderPathWithFileName;
for(ContentVersion contentVersionRec : [SELECT PathOnClient, VersionData FROM contentversion
										   WHERE contentdocumentId IN : contentDocumentIdSet){
	folderPathWithFileName = '/Root/'+PathOnClient;//PathOnClient contains file name with extension like imagefile.png
	system.debug('###folderPathWithFileName=>'+folderPathWithFileName);
	Http http = new Http();
	HttpRequest httpReq = new HttpRequest();
	httpReq.setEndpoint('https://content.dropboxapi.com/2/files/upload');
	httpReq.setMethod('POST');
	httpReq.setHeader('Authorization','Bearer ' + TOKEN);
	httpReq.setHeader('Content-Type','application/octet-stream');
	httpReq.setHeader('Dropbox-API-Arg','{"path":"'+folderPath+'","mode":{".tag":"add"}}');
	httpReq.setBodyAsBlob(contentVersionRec.VersionData);
	HttpResponse httpResponse = http.send(httpReq);
	System.debug('res###' + httpResponse);
	System.debug('res.getBody()###'+httpResponse.getBody());
	if (httpResponse.getStatusCode() == 200) {
		System.debug('##Congratulations File Uploaded successfully :) =>'+httpResponse.getBody());
	}else{
		//Handle code here when file not uploaded. 
	}
}

The error is : System.CalloutException: Exceeded max size limit of 12000000 with request size 12001280

I know(limit while sending http request) reason of this error but there should be a way to send more than 10mb file. Actually I need to upload up to 100 mb file from http request(Salesoforce) to dropbox.

If anyone have any idea please help.
Best Answer chosen by Devid John
Devid JohnDevid John
Hi Developers,
Finally got a solution to this. fortunately, Dropbox provides (https://api.dropboxapi.com/2/files/save_url) Save_URL (https://www.dropbox.com/developers/documentation/http/documentation#files-save_url) endpoint to use it we just need to pass file URL and path and dropbox will take over it automatically.
So I need a public file URL to upload a file from salesforce to dropbox to get file URL I created content distribution records first and then using contentdistribution.contenturl we can upload file to dropbox below is my code.
 
//first need to create contentdistrbution records temporarily for every contentversion because I need public url for file to upload in dropbox throug save_url endpoint.
List<ContentDistribution> contentDistributionList = new List<ContentDistribution>();
for(ContentVersion contentVersionRec : [SELECT PathOnClient 
                                        FROM contentversion
                                        WHERE contentdocumentId IN : contentDocumentIdSet]){
    contentDistributionList.add(
        new ContentDistribution(
            Name = contentVersionRec.PathOnClient,
            ContentVersionId = contentVersionRec.Id
        )
    );
}
if(contentDistributionList.size()>0){
    insert contentDistributionList;//after inserting content distribution salesforce internally generates contentDocumentURL. 
}

private string TOKEN = 'access_token_of_dropbox_app';
List<ContentDistribution> contentDistributionListToDel = new List<ContentDistribution>();
Http h;                                         
for(ContentDistribution cd : [SELECT ContentDownloadUrl, ContentVersion.PathOnClient FROM ContentDistribution WHERE Id IN :contentDistributionList]){
    system.debug('####File Name # ' + cd.ContentDownloadUrl);
    String jsonBody = '{"path": "/Root/Save_URL/'+cd.ContentVersion.PathOnClient+'","url": "'+cd.ContentDownloadUrl+'"}';
    h = new Http();
    HttpRequest httpReq = new HttpRequest();
    httpReq.setEndpoint('https://api.dropboxapi.com/2/files/save_url');
    httpReq.setMethod('POST');
    httpReq.setHeader('Authorization','Bearer ' + TOKEN); 
    httpReq.setHeader('Content-Type','application/json');  
    httpReq.setBody(jsonBody);
    HttpResponse res = h.send(httpReq);
    System.debug('res###'+res);
    System.debug('res.getBody()###'+res.getBody());
    if (httpResponse.getStatusCode() == 200) {
        System.debug('##Congratulations File Uploaded successfully :)');
        contentDistributionListToDel.add(
            new ContentDistribution(
                 Id = cd.Id
            )
        );
    }else{
        //Handle code here when file not uploaded. 
    }
}
//delete temporarily created content distribution records list.
if(contentDistributionListToDel.size()>0){
    delete contentDistributionListToDel; 
}

BTW Thansk Abhishek for your help.

All Answers

AbhishekAbhishek (Salesforce Developers) 
Hi,

This error message is due to a maximum size of call out response which is 6MB. This error is typical because of the following issue 

              a) (Maximum size of callout request or response) 
              b) maximum allowed heap size (6MB sync / 12MB async).
 
You may also try to set up the debug logs and check for the Apex heap size error to confirm. 

I would like to mention that the limit for both max sizes of call out (request and response ) and heap size is 6MB. 

Best practices for running within the Apex heap size 
https://help.salesforce.com/apex/HTViewSolution?urlname=Apex-Heap-Size-Best-Practices&language=en_US  (https://help.salesforce.com/apex/HTViewSolution?urlname=Apex-Heap-Size-Best-Practices&language=en_US )

https://help.salesforce.com/apex/HTViewSolution?urlname=How-to-avoid-the-Apex-heap-limit-error&language=en_US

(https://help.salesforce.com/apex/HTViewSolution?urlname=How-to-avoid-the-Apex-heap-limit-error&language=en_US )


Even if you contact Salesforce support the limit can not get increased permanently.


For further reference, you can check the below blog too,

https://www.forcetalks.com/blog/what-to-do-when-salesforce-apex-heap-size-increases/

I hope you find the above information is helpful. If it does, please mark as Best Answer to help others too.


Thanks.
Devid JohnDevid John
Hi Abhishek,
Thanks for help and explanation error in detail. I am using this code in "Queueable Apex" class means heap size is 12 MB. but as you mention httprequest , response and apex head size is only 12 mb in async process.
I just want to know is there any way to upload more than 10 MB file using HttpRequest becuase here you can see it throws limit error.
One possible solution for this to chunk the content version data and do multiple request within limit size. but the main thing here is how to chunk the data.

Assume, I am using base64 encode and decode to create for smaller files (4-5mb or 7-8 MB) chunks but while creating chunk of 20mb file it won't be able to store encoded data in apex to create multiple chunks cause it may throw error of heap size.

So I just want to know is there any salesforce expert who have done this king of tricky thing.
AbhishekAbhishek (Salesforce Developers) 
David, This a Governor Limit so I don't there is any another way in my knowledge.

 
Devid JohnDevid John
Hi Developers,
Finally got a solution to this. fortunately, Dropbox provides (https://api.dropboxapi.com/2/files/save_url) Save_URL (https://www.dropbox.com/developers/documentation/http/documentation#files-save_url) endpoint to use it we just need to pass file URL and path and dropbox will take over it automatically.
So I need a public file URL to upload a file from salesforce to dropbox to get file URL I created content distribution records first and then using contentdistribution.contenturl we can upload file to dropbox below is my code.
 
//first need to create contentdistrbution records temporarily for every contentversion because I need public url for file to upload in dropbox throug save_url endpoint.
List<ContentDistribution> contentDistributionList = new List<ContentDistribution>();
for(ContentVersion contentVersionRec : [SELECT PathOnClient 
                                        FROM contentversion
                                        WHERE contentdocumentId IN : contentDocumentIdSet]){
    contentDistributionList.add(
        new ContentDistribution(
            Name = contentVersionRec.PathOnClient,
            ContentVersionId = contentVersionRec.Id
        )
    );
}
if(contentDistributionList.size()>0){
    insert contentDistributionList;//after inserting content distribution salesforce internally generates contentDocumentURL. 
}

private string TOKEN = 'access_token_of_dropbox_app';
List<ContentDistribution> contentDistributionListToDel = new List<ContentDistribution>();
Http h;                                         
for(ContentDistribution cd : [SELECT ContentDownloadUrl, ContentVersion.PathOnClient FROM ContentDistribution WHERE Id IN :contentDistributionList]){
    system.debug('####File Name # ' + cd.ContentDownloadUrl);
    String jsonBody = '{"path": "/Root/Save_URL/'+cd.ContentVersion.PathOnClient+'","url": "'+cd.ContentDownloadUrl+'"}';
    h = new Http();
    HttpRequest httpReq = new HttpRequest();
    httpReq.setEndpoint('https://api.dropboxapi.com/2/files/save_url');
    httpReq.setMethod('POST');
    httpReq.setHeader('Authorization','Bearer ' + TOKEN); 
    httpReq.setHeader('Content-Type','application/json');  
    httpReq.setBody(jsonBody);
    HttpResponse res = h.send(httpReq);
    System.debug('res###'+res);
    System.debug('res.getBody()###'+res.getBody());
    if (httpResponse.getStatusCode() == 200) {
        System.debug('##Congratulations File Uploaded successfully :)');
        contentDistributionListToDel.add(
            new ContentDistribution(
                 Id = cd.Id
            )
        );
    }else{
        //Handle code here when file not uploaded. 
    }
}
//delete temporarily created content distribution records list.
if(contentDistributionListToDel.size()>0){
    delete contentDistributionListToDel; 
}

BTW Thansk Abhishek for your help.
This was selected as the best answer
Michael PlunkettMichael Plunkett
@Devid John -- Great idea to get around the heap/callout size issue. In your code example, you have callouts right after DML statement -- it is my understanding that this will throw a CalloutException error. Can't see the rest of your code but thought I would mention.