Why Dropbox as a file backend
<form.io>, a platform for building form-based AngularJS and React apps, often needs embedded file upload and download capabilities. Rather than building a file storage system, the team integrated Dropbox directly, using its API v2 HTTP endpoints. While Dropbox provides SDKs for API v2 in several languages, the JavaScript SDK is still under development, so a direct HTTP integration was the practical route.
Client-side apps need to be cautious here: an OAuth 2 access token should only be exposed to its owner, never to other users.
Upload flow: bypassing multipart/form-data
The upload begins with a standard OAuth 2 flow to obtain an access token (see Dropbox's OAuth guide for details). After that, a file selection field with an onchange handler kicks off the upload:
<form>
<input type="file" name="file" accept="image/*" onchange="uploadFile">
</form>
Early attempts used an Angular file upload service and $http, but both send multipart/form-data. The Dropbox API, by contrast, expects the raw file data as application/octet-stream. The working solution calls XMLHttpRequest directly:
/**
* Two variables should already be set.
* dropboxToken = OAuth access token, specific to the user.
* file = file object selected in the file widget.
*/
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(evt) {
var percentComplete = parseInt(100.0 * evt.loaded / evt.total);
// Upload in progress. Do something here with the percent complete.
};
xhr.onload = function() {
if (xhr.status === 200) {
var fileInfo = JSON.parse(xhr.response);
// Upload succeeded. Do something here with the file info.
}
else {
var errorMessage = xhr.response || 'Unable to upload file';
// Upload failed. Do something here with the error.
}
};
xhr.open('POST', 'https://content.dropboxapi.com/2/files/upload');
xhr.setRequestHeader('Authorization', 'Bearer ' + dropboxToken);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.setRequestHeader('Dropbox-API-Arg', JSON.stringify({
path: '/' + file.name,
mode: 'add',
autorename: true,
mute: false
}));
xhr.send(file);
Once a user picks a file, it is uploaded straight to Dropbox and a reference is stored on the server.
Download flow: intercepting clicks, saving with Blob
Stored Dropbox files aren't publicly accessible like ordinary web assets. Attempting to link directly yields an authentication failure. The solution is to intercept the click event on the file link, fetch the file contents via Dropbox's /download endpoint, and save the result locally.
Modern browsers support the HTML5 Blob constructor and FileSaver, which make this possible entirely on the client. The Angular click handler looks like this:
downloadFile: function(evt, file) {
evt.preventDefault();
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (xhr.status === 200) {
var blob = new Blob([xhr.response], {type: ’application/octet-stream’});
FileSaver.saveAs(blob, file.name, true);
}
else {
var errorMessage = xhr.response || 'Unable to download file';
// Upload failed. Do something here with the error.
}
};
xhr.open('POST', 'https://content.dropboxapi.com/2/files/download');
xhr.setRequestHeader('Authorization', 'Bearer ' + dropboxToken);
xhr.setRequestHeader('Dropbox-API-Arg', JSON.stringify({
path: file.path_lower
}));
xhr.send();
}
This intercepts the file click, authenticates with Dropbox, pulls down the file's contents, and triggers a browser save. The complete implementation is available in the open source ngFormio repository on GitHub.
Using the Dropbox HTTP API directly, <form.io> gained a working file uploader and viewer without waiting on the JavaScript SDK. Any app built on the platform can now adopt Dropbox as its file backend without duplicating that integration work.



