According to Facebook's Graph documentation on the user photos edge, it's possible to post a photo from javascript using multipart/form-data encoded binary image. https://developers.facebook.com/docs/graph-api/reference/v2.2/user/photos
/* make the API call */
FB.api(
"/me/photos",
"POST",
{
"source": "{image-data}"
},
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
The problem is there doesn't appear to be any sample documentation anywhere on the net on how exactly this is supposed to work. There is a method where you bypass FB.api and post directly to the edge via an xhr request. I've gotten this to work, but I'd really like to know how to do this using the FB.api command. Here is my code (FB app has been registered properly and all javascript sdk included elsewhere in the file):
function postImageToFacebook(authToken) {
//Capture the image from a canvas
var filename = "samplepic.png",
mimeType = "image/png",
message = "test comment",
data = canvas.toDataURL("image/png"),
encodedPng = data.substring(data.indexOf(',') + 1, data.length),
imageData = Base64Binary.decode(encodedPng);
// build the multipart/form-data
var boundary = '----ThisIsTheBoundary1234567890';
var formData = '--' + boundary + '\r\n'
formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
for (var i = 0; i < imageData.length; ++i) {
formData += String.fromCharCode(imageData[i] & 0xff);
}
formData += '\r\n';
formData += '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
formData += message + '\r\n'
formData += '--' + boundary + '--\r\n';
//METHOD #1: send the data using xhr request
var xhr = new XMLHttpRequest();
xhr.open( 'POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true );
xhr.onload = xhr.onerror = function() {
console.log( xhr.responseText );
};
//vvv This right here seems to be key, being able to add a header vvv
xhr.setRequestHeader( "Content-Type", "multipart/form-data; boundary=" + boundary );
xhr.sendAsBinary( formData );
//METHOD #2: send the data using FB.api
FB.api("/me/photos", "POST", {
"source": formData
}, function(response) {
console.log(response)
});
};
Method #1: works. I've used it numerous times to successfully share an image. When watching the network console in Chrome you can see content-type:multipart/form-data
header being set to which it then puts all of the data into a "Request Payload" and the return response is a successful post ID.
Method #2: does not work. The error returned from Facebook is (#324) Requires upload file
. Looking at network console, you can see that content-type:application/x-www-form-urlencoded
header is set (which is what we don't want). The form gets put under the "source" post parameter under Form Data which is why I'm assuming it gets rejected by Facebook.
What is the magic required to make FB.api work properly here? The only clue they give in their docs is a link to W3's spec on multipart/form-data which I know my formData is conforming to since it works with xhr in method #1. Outside of the mention in facebook docs, I can't find any example of this javascript method actually working. Help?