Facebook Graph API publish picture with Javascript - javascript

I'm using the Facebook Javascript SDK in my react app and I want to make a post with multiple photos. I know that that means I have to first post the pictures unpublished and then use the returned ids to make the post.
However, I'm having trouble finding good documentation and running into issues figuring out how to allow a user select and post a local picture (not from a url). The code is a bit difficult to put all here, but here are the steps I'm taking and the errors I'm getting:
Get file the user selected using a file input.
Encode the picture as a blob and put that and the access token into FormData to use in the api request.
var reader = new FileReader();
reader.onload = function(e) {
var arrayBuffer = e.target.result;
var blob = new Blob([arrayBuffer], { type: photo.type });
var pictureData = new FormData();
pictureData.append('access_token:', this.state.FBaccessToken);
pictureData.append('source', blob);
return pictureData;
}.bind(this)
return reader.readAsArrayBuffer(photo);
Do a post request
var encodedRequest = this.encodePhoto(photo);
FB.api(
"/me/photos?published=false",
"POST",
encodedRequest,
function (response) {
if (response && !response.error) {
//once successfully gotten the photos add them to the array of photo ids
temp.push({"media_fbid": response.id});
console.log(response);
}
else {
alert(response.error.message);
}
}.bind(this)
);
The error when I run it this way is that it doesn't seem to recognize the access token, but when I remove the access token from pictureData in step 2, and change the api encodedRequest part to this:
{
access_token: this.state.FBaccessToken,
source: encodedRequest,
},
I get the error "(#324) Requires upload file". I tried adding fileUpload: true, to the SDK init code but that also didn't seem to do anything. Posting simple text only statuses and reading from feed is all working fine.
Sorry for the long post, but I'd be really grateful if anyone has any insight! Thanks.

Is it the extra colon you have after access_token in your first pictureData.append() call?
pictureData.append('access_token:', this.state.FBaccessToken);
versus
pictureData.append('access_token', this.state.FBaccessToken);
Edit: Below is output from postman to post images referencing a file on my laptop
var form = new FormData();
form.append("source", "/Users/patricklambe/images/test.jpg");
form.append("access_token", "PAGEACCESSTOKEN");
form.append("caption", "check this photo");
var settings = {
"async": true,
"crossDomain": true,
"url": "https://graph.facebook.com/v2.11/444873272561515/photos",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"postman-token": "1d786fec-c9b1-2494-1b5c-8fd0e2ea5ade"
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
$.ajax(settings).done(function (response) {
console.log(response);
});

Related

I'm sending a json object via the post method to my sendy database. It seems to work fine on desktop but does not send on mobile

I'm sending the json object userInfoRedCourses to my sendy database via the post method. This json object is sent from the previous page contains user details like email, name, address etc..If the user ticks the box the data is sent. I'm also changing some of the values in the object before the data is sent.
This works fine on desktop, but doesn't work at all on mobile. Please can anyone explain why?
I thought it might be a CORS error, but when I added dataType: 'jsonp',I stopped getting the CORS error, however the data is still not sent when using a mobile device. I see no other errors.
var userInfoRedCourses = <%- JSON.stringify(userInfo) %>;
var redCourseTickYes = document.getElementById("redcoursetickyes");
var redLicence = $("#Redlicence").val();
var drivingBan = $("#drivingBan").val();
var penPoints = $("#penaltyPoints").val();
userInfoRedCourses.redcoursetickyes = $("#redcoursetickyes").val();
userInfoRedCourses.Redlicence = redLicence;
userInfoRedCourses.DrivingBan = drivingBan;
userInfoRedCourses.penaltyPoints = penPoints;
if(redCourseTickYes.checked){
var redCourses = {
method: "POST",
"data": userInfoRedCourses,
crossDomain: true,
url: "https://example.com/sendy/subscribe",
dataType: 'jsonp',
"headers": {
"Host": "example.com",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
}
};
$.ajax(redCourses).done(function (response) {
console.log(JSON.stringify(response));
});
}

Google Cloud Functions HTTP unable to successfully POST content type application/octet-stream

I'm trying to write a Google Cloud Functions HTTP handler to upload audio files constructed as blobs to Google Cloud Storage from a webpage. Based on the documentation linked above I want the body of my POST request to be handled as a Node.js Buffer and I can achieve this with Content-Type: application/octet-stream. I'm sending the request from a webpage that has this xhr request:
// where `var blob` is a Blob of type "audio/wav"
// and size of > 0 generated from the
// WebAudioAPI
var fileReader = new FileReader();
fileReader.onloadend = function() {
$.ajax({
type: 'POST',
url: GOOGLE_CLOUD_FUNCTION_URL,
data: this.result,
dataType: 'json',
processData: false,
contentType: 'application/octet-stream',
success: function(resp) {
},
error: function(err) {
}
});
};
fileReader.readAsArrayBuffer(blob);
and my Google Cloud Functions module looks like this:
exports.upload = function(req, resp) {
resp.header('Content-Type','application/json');
resp.header('Access-Control-Allow-Origin', req.get('origin'));
resp.header('Access-Control-Allow-Headers', 'Content-Type');
switch (req.method) {
case 'POST':
response.status(200).send({
contentType: request.get('content-type'),
body: request.body,
rawBody: request.rawBody
});
break;
}
};
The request header shows that that there is data being attached. But, the content-type is not set as `application/octet-stream'. In addition the response returns:
{
body: {}
}
What is the JavaScript type of data to pass to an ajax body for the Google Cloud Functions HTTP handler accept the body as a Buffer?
Blob, File, Typed Array, Array Buffer?

Posting multiple Photos to one post

I have been trying to create an application which needs multiple photos to be attached to one post. These are the following attempts i tried,
First i used facebook-node-sdk which JS SDK to achieve different functionality, but Official Js Sdk does't have option for file to upload, when then i moved to attaching/inserting photo itself to HTTP POST with the help of form-data, with the following code-
var form = new FormData();
form.append('file', fs.createReadStream(picPaths[0]));
form.append('message', "Hello"); //Put message
var ACCESS_TOKEN = "ACCESS_TOKEN";
var options = {
method: 'post',
host: 'graph.facebook.com',
path: '{Object-ID}/photos' + '?access_token=' + ACCESS_TOKEN,
headers: form.getHeaders(),
}
var request = https.request(options, function(res) {
console.log(res, false, null);
});
form.pipe(request);
request.on('error', function(error) {
console.log(error);
});
This works with one photo.
But as you can see in this github.com/Thuzi/facebook-node-sdk/issues/113 which i started, it is not possible to attach more than one photo.
So as mentioned by dantman i stated looking in batch process, which can be found developers.facebook.com/docs/graph-api/making-multiple-requests titled under Uploading binary data. The one thing that hits and give me hope is this one statement.
The attached_files property can take a comma separated list of attachment names in its value.
Note That (batching with photos) also is not possible with this library or JS SDK (Please correct me if i am wrong)
You can do post images with curl like this,
curl -F 'access_token=ACCESS_TOKEN' -F 'batch=[{"method":"POST","relative_url":"{Object-Id}/photos","body":"message=Test Post","attached_files":"file1"}]' -F 'file1=#image1' -F 'file2=#image2' https://graph.facebook.com
The above code posts with one image
So my question is this, it possible to attach multiple images/binary_files to the post with the help of curl, something like ..."attached_files":"file1,file2"... as suggested by docs, please help me with this problem and if you have already done this can you please post the snapshot of your code.
Thanks, Ravi
I finally figured out how.
So first, read the section here titled "Publishing a multi-photo post with uploaded photos": https://developers.facebook.com/docs/graph-api/reference/page/photos/#Creating
What it says is basically correct, however, it is not in JavaScript. Also, they don't emphasize enough an important step: You have to set "published" to "false" for the image you upload, for it to then be attachable to the post that gets created.
So anyway, here is the working code -- in JavaScript, and with "published" correctly set to false:
async function PostImageToFacebook(token, filename, mimeType, imageDataBlob, message) {
var fd = new FormData();
fd.append("access_token", token);
fd.append("source", imageDataBlob);
//fd.append("message", "photo message for " + filename);
fd.append("no_story", "true");
//fd.append("privacy", "SELF");
fd.append("published", "false");
// Upload image to facebook without story(post to feed)
let uploadPhotoResponse = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse);
let uploadPhotoResponse2 = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse2);
let makePostResponse = await $.ajax({
"async": true,
"crossDomain": true,
"url": "https://graph.facebook.com/v2.11/me/feed",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"data": {
"message": "Testing multi-photo post2!",
"attached_media[0]": `{"media_fbid":${uploadPhotoResponse.id}}`,
"attached_media[1]": `{"media_fbid":${uploadPhotoResponse2.id}}`,
"access_token": token
}
});
console.log(`Made post: `, makePostResponse);
}
The code above currently just uploads the same image twice, then attaches both to the new post. Obviously, in real world usage you would replace the data in the second photo-upload with a different image.
Anyway, to use the function, just call it like so:
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(",")[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: "image/png"});
}
let imageDataURI = GetImageDataURIFromSomewhere();
let imageBlob = dataURItoBlob(imageDataURI);
PostImageToFacebook(fbToken, "some_filename", "image/png", imageBlob, window.location.href);
this is possible.
Note: This one is not an efficient way to do this but just for explaining purpose i am doing here,
The first hint that i got that it may be possible is from this post
Steps that i used:
Follow the doc to create custom open graph stories
Let's suppose you four image to attach (pic[1, 2, 3, 4])
First i staged them with the help of new facebook-node-sdk v1.1.0-alpha1 with the code something like this (with batch process).
FB.api( "", "post", {
batch: [
{
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file1",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file2",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file3",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file4",
type:"image/png"
}],
file1: fs.createReadStream(picPaths[0]),
file2: fs.createReadStream(picPaths[1]),
file3: fs.createReadStream(picPaths[2]),
file4: fs.createReadStream(picPaths[3])
},
function(response) {
console.log(response);
});
Now from the response part get the url and dis the post with the same library. With the code something like this.
FB.api(
"me/objects/{app-namespace}:{custom-object}",
"post", {
"object": {
"og:title": "Sample Post",
"og:image[0]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[1]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[2]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[3]": {
"url": "fbstaging:{...}",
"user_generated": true
}
}
},
function(response) {
console.log(response);
}
);
Now, with these two piece of code you will be able to push multiple images/photo to the single post.
Note: this can make more sense or can be done with the help of named batch process which is being described here.
Thanks,
Ravi

JQuery Ajax function not being executed in chrome extension

I am creating a chrome extension which uses simple HTTP POST requests. It's my first javascript code ever. I used POSTMAN to generate this code which fulfills the requirement (POSTMAN worked with the POST request).
var form = new FormData();
form.append("email", "XXX");
form.append("password", "XXX");
var settings = {
"async": true,
"crossDomain": true,
"url": "http://xxx.xxx.in/xxx/",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"postman-token": "fa86846e-4030-d90f-701a-82e36e6117b0"
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
};
chrome.extension.getBackgroundPage().console.log("outside")
try {
chrome.extension.getBackgroundPage().console.log("inside try block")
$.ajax(settings).done(function (response) {
chrome.extension.getBackgroundPage().console.log("inside")
chrome.extension.getBackgroundPage().console.log(response);
});
} catch (e) {
chrome.extension.getBackgroundPage().console.log("Exception caught")
chrome.extension.getBackgroundPage().console.log(e)
} finally {
}
I tried it with a chrome extension but my console does not log after the inside try block. I can't understand what happened in this line
$.ajax(settings).done(function (response) {
The error is not caught anywhere else. I have given appropriate permissions in my manifest.json file.
I have some very specific questions to ask:
What is the best workaround for requests? XmlHttpRequests or JQuery
What are some best ways of debugging javascript applications? That would help a lot, thanks.

Upload files to Dropbox using a Dropbox Core API in Javascript

I am working on a simple chrome-extension that needs to upload files to the user's dropbox folder. I am using the simple AJAX requests as mentioned below to upload files, however it works for files with extensions such as .txt, .json, .c, etc i.e. files whose mime type is of type text/plain or similar type but all other file types such as pdfs, image files etc get corrupted and produce blank contents. What am I missing in uploading the files the correct way.
function startUpload()
{
var folderPath = $(this).closest('tr').attr('path')+'/';
var file = $("#upload_file")[0].files[0];
if (!file){
alert ("No file selected to upload.");
return false;
}
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
uploadFile(folderPath+file.name,evt.target.result,file.size,file.type);
}
}
//function to upload file to folder
function uploadFile(filepath,data,contentLength,contentType){
var url = "https://api-content.dropbox.com/1/files_put/auto"+filepath;
var headers = {
Authorization: 'Bearer ' + getAccessToken(),
contentLength: contentLength,
};
var args = {
url: url,
headers: headers,
crossDomain: true,
crossOrigin: true,
type: 'PUT',
contentType: contentType,
data : data,
dataType: 'json',
success: function(data)
{
getMetadata(filepath.substring(0,filepath.lastIndexOf('/')),createFolderViews);
},
error: function(jqXHR)
{
console.log(jqXHR);
}
};
$.ajax(args);
}
I believe the issue is reader.readAsTextFile(file, "UTF-8"). If the file isn't a text file, this will misinterpret the contents. I think you want reader.readAsBinaryString or reader.readAsArrayBuffer. (I haven't tested it myself.)
EDIT
After testing this myself, I found that readAsArrayBuffer is what you need, but you also need to add processData: false as an option to $.ajax to prevent jQuery from trying to convert the data to fields in a form submission.
Also be sure to use dataType: 'json' to properly parse the response from the server.

Categories

Resources