Skip to content

Instantly share code, notes, and snippets.

@hughbris
Last active February 8, 2024 20:00
Show Gist options
  • Save hughbris/65b3baa55b58acb7beaaad885a63a458 to your computer and use it in GitHub Desktop.
Save hughbris/65b3baa55b58acb7beaaad885a63a458 to your computer and use it in GitHub Desktop.
Javascript Imgur API uploading example using type=file

This Gist shows an otherwise (AFAICT) undocumented way to upload images using the Imgur API with type=file.

I did not want to base64 encode (type=base64) the file contents because my use case was within a Cordova app where resources may limited.

The file is taken from the device file system, so no URL is accessible for file=url.

I was unable to find any guidance or examples in online documentation using this method in Javascript (or any language, AFAIR). I emailed(!) the suggested support contact laying out the problem and stressing that I had not found examples in the documentation. The reply came a month later, pointing me to the very docs in which I had told them I found no satisfactory answer or example! Gee, thanks.

It wasn't too hard, playing with cURL, to get a working call from command line:

curl -i -d type=file --data-urlencode [email protected] -H "Authorization: Bearer $IMGUR_ACCESS_TOKEN" https://api.imgur.com/3/image

and a --trace on that allowed me to see exactly what was being submitted successfully.

"Neat", I thought, I just need to write an $.ajax call in jQuery. Being within a cordova app where the camera module would not load in any real-time development environment, my choices for tracing when this didn't work seemed very limited. I just had to read the jQuery docs very carefully and keep trying.

Several days and much less hair later, I'd read a few examples using plain old XMLHttpRequest. I decided, in part thanks to the unnecessarily negative "You Don't Need jQuery!" to try submitting using a FormData object, which jQuery seemed to have to no harness for.

Well, shit!

Just in case you doubt how important documentation is, I had to tell this story. It was a chunk of my life for sure. I don't see any reason anyone else should go through this crap because docs weren't developed completely (yes, it's a free product - see below, I did desperately look for alternatives)

Some of the rabbit holes I went down (just the major ones):

  • Absolutely double-checking that there were no other free options that had private storage areas and a resizing API. Unless you count Flickr as somehow viable in 2017 and can be arsed with their auth and auth docs, you're out of luck.
  • Producing and deploying a proxy PHP script to manage the API call with its cURL functions. This included being open to the Base64 option, since I was on a server here. The script worked with type=file, and then I was able to make my local machine cURL post files to it, but hit the same wall with jQuery.

What I learned:

  • jQuery.ajax at best isn't particularly intuitive for complex calls and/or binary data, and at worst is buggy or undocumentedly incomplete. If you don't need cross-browser support, it's really only providing (a little) syntactic sugar.

Using the script

This was written as a method in my capturedMedia class for the Sensibel project. I've adapted from that.

Some of the variables that are in scope have been included as funciton parameters to hopefully help you recreate this easily.

If you are looking at a day 0 commit of this Gist, I haven't tested this properly because it's an adapted version of what I've used and I don't really have time set up a test yet.

I hope you or someone near or dear to you finds this useful. May the doc force be with you.

var example = function(fileObject, fileName, config, onUploadSuccess, onUploadFail){ // filename isn't strictly necessary, just useful for console logging
var target = config.capturedMedia.REMOTE_API.endpoint + '/image';
console.log('Uploading image ' + fileName + ' to ' + target);
if(typeof(fileObject) !== undefined) {
console.log('File object: ' + JSON.stringify(fileObject));
var rdr = new FileReader();
rdr.onloadend = function(evt) {
var imageBlob = new Blob([new Uint8Array(evt.target.result)], {
'type': 'image/jpeg', // you might want to parameterise (or omit?) this, I've already tried deriving from Blob to no avail
});
// https://blog.garstasio.com/you-dont-need-jquery/ajax/ - thank you!!
var dataFields = new FormData();
dataFields.append('image', imageBlob);
dataFields.append('type', 'file');
if (config.capturedMedia.hasOwnProperty('album')) {
dataFields.append('album', config.capturedMedia.album);
}
var post = new XMLHttpRequest();
post.open('POST', target);
post.setRequestHeader('Authorization', 'Bearer ' + config.capturedMedia.REMOTE_API.OAuth.access_token);
post.send(dataFields);
post.onloadend = function(evt) {
onUploadSuccess.call(evt) || function(evt) {
console.log('Uploaded image from ' + fileName + ' to ' + target);
var responseJSON = JSON.parse(post.responseText);
console.log(JSON.stringify(responseJSON.data));
// do someting with responseJSON
}();
};
post.onerror = function(err) { // untested
onUploadFail || function(err) {
console.log('Failed uploading image from ' + fileName + ': ' + JSON.stringify(err));
console.log('Output: ' + post.responseText);
}();
};
};
// rdr.error = function {} // TODO
rdr.readAsArrayBuffer(fileObject);
}
else {
console.log("Upload won't work without file system stuff, maybe implement a fix later");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment