On my quest for a fancy upload-form to meet a customer requirement I found a nice looking HTML5-Solution on tehnrd.com.
It gave me a nice “quick-start”. But at the end we couldn’t live with the combination of overhead-data and memory-limitations.
Later on I found an article about using binary data with REST, which for me, seems to be a better approach than using a standard controller and Base64-encoded strings.
Sadly I’m not able to upload more than ~5MB still, but that will do it for now.
(I haven’t tested for the maximum possible file size using this approach yet; when I try to upload 10MB I get this error though:
https://xxx.visual.force.com/services/proxy 400 Unable to forward request due to: Request timedout after: 30189 )
Lets dive into Code
The Controller is pretty simple. Since our Request-Body is the pure binary,
we use a “custom” HTTP-header to transfer the filename and the Id of the record we want to attach the file to.
@RestResource(urlMapping='/attach')
global class cmAttachmentResource {
@HttpPost
global static String attach(){
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
if( req.headers.get('upload_pid') == null || req.headers.get('upload_filename') == null){
res.statusCode = 400;
return 'missing upload headers';
}
Blob bin = req.requestBody;
Attachment myAttachment = new Attachment();
myAttachment.Body = bin;
myAttachment.Name = req.headers.get('upload_filename');
myAttachment.ParentId = req.headers.get('upload_pid');
insert myAttachment;
return ' id = '+myAttachment.Id;
}
}
On the client side, it gets a bit more complicated since you may not able to use XmlHttpRequest directly, due to the same origin policy. But there already is code to solve this problem on github:
Force.com-JavaScript-REST-Toolkit
After getting thru the “Configuration” and “Using the Toolkit” -Part of the Documentation, you can use this script for a nice “drag and drop”-Box. It is pretty raw and straightforward, therefore it should be easy to customize it for your needs.
It will let you upload attachments for any object you desire, and even allow the user to drop multiple Documents at once.
Usage:
var client = new forcetk.Client();
client.setSessionToken('{!$Api.Session_ID}');
// Setup the dropzone
var dropZone = document.getElementById('drop_zone');
bindDropBox('{!yourObject.id}',dropZone,client);