Facebook Graph API - upload photo using JavaScript

Is it possible to upload a file using the Facebook Graph API using javascript, I feel like I'm close. I'm using the following JavaScript

var params = {};
params['message'] = 'PicRolled';
params['source'] = '@'+path;
params['access_token'] = access_token;
params['upload file'] = true;

function saveImage() {
    FB.api('/me/photos', 'post', params, function(response) {
        if (!response || response.error) {
            alert(response);
        } else {
            alert('Published to stream - you might want to delete it now!');
        }
    }); 
}

Upon running this I receive the following error...

"OAuthException" - "(#324) Requires upload file"

When I try and research this method all I can find out about is a php method that apears to solve this

$facebook->setFileUploadSupport(true);

However, I am using JavaScript, it looks like this method might be to do with Facebook Graph permissions, but I already have set the permissions user_photos and publish_stream, which I believed are the only ones I should need to perform this operation.

I have seen a couple of unanswered questions regarding this on stackoverflow, hopefully I can explained myself enough. Thanks guys.


Solution 1:

Yes, this is possible, i find 2 solutions how to do that and they are very similar to each other, u need just define url parameter to external image url

FIRST one using Javascript SDk:

var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
FB.api('/album_id/photos', 'post', {
    message:'photo description',
    url:imgURL        
}, function(response){

    if (!response || response.error) {
        alert('Error occured');
    } else {
        alert('Post ID: ' + response.id);
    }

});

and SECOND one using jQuery Post request and FormData:

 var postMSG="Your message";
 var url='https://graph.facebook.com/albumID/photos?access_token='+accessToken+"&message="+postMSG;
 var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
 var formData = new FormData();
 formData.append("url",imgURL);

  $.ajax({
                    url: url,
                    data: formData,
                    cache: false,
                    contentType: false,
                    processData: false,
                    type: 'POST',

                    success: function(data){
                        alert("POST SUCCESSFUL");
                    }
                });

Solution 2:

EDIT: this answer is (now) largely irrelevant. If your image is on the web, just specify the url param as per the API (and see examples in other answers). If you would like to POST the image content to facebook directly, you may want to read this answer to gain understanding. Also see HTML5's Canvas.toDataUrl().

The API says: "To publish a photo, issue a POST request with the photo file attachment as multipart/form-data."

FB is expecting that the bytes of the image to be uploaded are in the body of the HTTP request, but they're not there. Or to look at it another way - where in the FB.api() call are you supplying the actual contents of the image itself?

The FB.api() API is poorly documented, and doesn't supply an example of an HTTP POST which includes a body. One might infer from the absence of such an example that it doesn't support this.

That's probably OK - FB.api() is using something called XmlHttpRequest under the covers which does support including a body ... look it up in your favourite JavaScript reference.

However, you'll still have 2 sub-problems to solve:

  1. how to prepare the image bytes (and rest of the request) as multipart/form-data; and
  2. getting the bytes of the image itself

(incidentally, the need to encode the message body is probably what the PHP setFileUploadSupport(true) method is for - tell the facebook object to encode the message body as multipart/form-data before sending)

But it's a bit meessier than that

Unfortunately, sub-problem '2' may bite you - there is no way (last time I looked) to extract the bytes of an image from the browser-supplied Image object.

If the image to be uploaded is accessible via a URL, you could fetch the bytes with XmlHttpRequest. Not too bad.

If the image is coming from the user's desktop, your probable recourse is to offer the user a:

 <form enctype="multipart/form-data">
     <input type="filename" name="myfile.jpg" />
     <input type="hidden" name="source" value="@myfile.jpg"/>
     <input type="hidden" name="message" value="My Message"/>
     <input type="hidden" name="access_token" value="..."/> 
 </form> 

(notice that source references the name given to the file-upload widget)

... and hope that FB anticipated receiving the data in this manner (try it with a static HTML form first, before coding it up dynamically in JS). One might infer that in fact it would, since they don't offer another means of doing it.