+ Start a Discussion
Kenji775Kenji775 

Facebook Integration

Hey I was just wondering if anyone out there has managed to get Apex to call any of the functions available in the Facebook API. I know there are all kinds of connectors and such to pull data out of facebook, but I need to publish some stuff using the "Stream.publish" method (here are the docs for it Steam Docs).

I tried to roll my own post request using the @Future(callout=true) but no good, and since it's async I can't see any of the feedback.

 

Here was the request I built.

 

System.debug('Making future call to update Facebook Profile'); //construct an HTTP request HttpRequest req = new HttpRequest(); HttpResponse res = new HttpResponse(); Http http = new Http(); req.setEndpoint('http://api.new.facebook.com/restserver.php'); req.setMethod('POST'); req.setBody('method=stream.publish&api_key=[MY KEY WAS HERE]&target_id=1769004737&message=TEST&uid=1769004737'); req.setCompressed(true); // otherwise we hit a limit of 32000 res = http.send(req);

 

If anyone has any idea why that didn't work, or how i can even capture the results of what happened (I don't get any Apex errors, but it doensn't do what it is supposed to either) please let me know. Thanks.

 

Chirag MehtaChirag Mehta

Hi friend,

 

Any idea on http://community.salesforce.com/sforce/board/message?board.id=apex&message.id=16000 Even smallest help will be of great use.

 

 

santhanamsanthanam

Hi Kenji775,

 

Even I hit a problem while integrating with facebook.

 

While using stream.publish, the response message i got is: <error_msg>This API version is deprecated</error_msg>

 

I am trying to post a message in my "wall" in facebook. Can anyone help me out here?

 

I have posted a similar post here: http://community.salesforce.com/sforce/board/message?board.id=apex&thread.id=16903

 

Thanks.

Message Edited by santhanam on 06-15-2009 05:57 AM
Kenji775Kenji775

Hey Guys, I did eventually solve my problem, however it may not be the fix for everyone. I ended up having Salesforce call a page on my web server that actually does the integration. I have a workflow rule that sends an outbound message to a Cold Fusion page, and that does the work. With that said, the principals for connecting to the facebook API are the same across all languages, so the following tips should at least help a little.

 

As far as I can tell that error normally means you are not passing all required information for the function. Some functions for facebook require a sig, and version number, and a session key, some of them don't need any of those, so first step is read the Facebook API wiki docs.

 

Second thing is that you have to make sure you are POSTing the data, not GETting it. I know with the language I was using you can specify how you want to send the data (I was rolling my own HTTP request, not using a regular form submit action) so just make sure that any data you send goes in a POST formatted string. 

 

Last thing is that I used a pre built library to take care of some of the grunt work for putting together the request (generating the signature and such), I ended up using that after failing to create my own. It looks very very similar to the one I tried to build, but there must be some small difference that I was missing (I suspect I was generating the key incorrectly).

 

If you would like I can post my source code here that works, it is written in Cold Fusion, so it may or not be of use to you (CF is extremely easy to read, so it might at least help you get the gist of things).

 

Oh yeah, and remember stream.publish is still in beta last i checked, so only developers can use it for now. So any app you write using it, will be somewhat useless until it is out of beta. Unless you are using publishtemplatizedaction to try and post to their wall.  

Message Edited by Kenji775 on 06-15-2009 07:20 AM
Chirag MehtaChirag Mehta

Hi Kenji,

 

Can you pls post snippet of your code for easy understanding. Thanks

Kenji775Kenji775

Sure, here we go.

 

First I call my stream publish funtion, passing in the message, the target profile, and the Id of the poster.

 

<cfset MakeMyCall = server.apiClient.streampublish('#SFDATA.Message#','#SFDATA.Target#','1769004737')>

 

So that goes to my function which looks like

 

 

<cffunction name="StreamPublish" access="public" output="false" returntype="any"> <cfargument name="message" type="string" required="true" hint="What to publish"> <cfargument name="target" type="string" required="true" hint="What to to who's profile"> <cfargument name="uid" type="string" required="true" hint="the current session key"> <!--- local vars ---> <cfset var xmlResponse = "" /> <cfset var params = StructNew() /> <!--- the api call ---> <cfset params["uid"] = arguments.uid> <cfset params["message"] = arguments.message> <cfset params["target_id"] = arguments.target> <cfset xmlResponse = callMethod("facebook.Stream.publish", params) /> <cfreturn xmlResponse> </cffunction>

 

 All that function does really is package the data in a structure, and then hand that off to the callMethod function. I could have formatted the data correct to begin with, but i went with this approach for some reason.

 

So now we are at the CallMethod, which looks like this.

 

<cffunction name="callMethod" access="public" output="false" returntype="any" hint="I act as a raw interface to the Facebook API and return the xml string response from the facebook server."> <cfargument name="method" type="string" required="yes" /> <cfargument name="params" type="struct" required="no" default="#StructNew()#" /> <cfargument name="filepath" type="string" required="no" /> <cfset var result = StructNew() /> <cfset var key = ""> <!--- add params to the param struct ---> <cfset StructInsert(arguments.params, "method", arguments.method) /> <cfset StructInsert(arguments.params, "api_key", variables._apiKey) /> <cfset StructInsert(arguments.params, "v", variables._apiVersion) /> <cfset StructInsert(arguments.params, "call_id", getTickCount()) /> <!--- add the signature ---> <cfset StructInsert(arguments.params, "sig", generateSignature(arguments.params)) /> <cfhttp url="#variables._server#" method="post" charset="utf-8" redirect="no"> <cfloop collection="#arguments.params#" item="key"> <cfhttpparam name="#key#" value="#arguments.params[key]#" type="formfield" /> </cfloop> </cfhttp> <cfset ReturnStruct.cfhttpData = xmlparse(cfhttp.FileContent)> <cfset ReturnStruct.ArgumentsData = arguments.params> <cfreturn ReturnStruct /> </cffunction>

 

 That function just adds the last of the required data, loops over all the keys in the structure and sends it off to the API. You'll notice this function uses another to generate the signature. That function looks like this.

 

 

<cffunction name="generateSignature" access="private" output="true" returntype="string" hint="I generate and return a key."> <cfargument name="params" required="yes" type="struct" /> <cfset var buffer = CreateObject("java","java.lang.StringBuffer").init("") /> <cfset var result = "" /> <cfset var sortedKeys = LCase(ListSort(StructKeyList(arguments.params),"textnocase", "Asc", ",")) /> <cfset var key = "" /> <!--- add key=value to buffer ---> <cfloop list="#sortedKeys#" index="key" delimiters=","> <cfset buffer.append(key & "=" & arguments.params[key]) /> </cfloop> <!--- add the secret ---> <cfset buffer.append( server.secret ) /> <!--- hash buffer ---> <cfset result = hash(buffer.toString()) /> <cfreturn LCase(result) /> </cffunction>

 

 

 

 

 So there ya go, thats it. A little tricky, not to bad. Just gotta make sure you package the data correctly, and have everything that is required.

 

santhanamsanthanam

Thanks Kenji775. But, I could not proceed further even now.

 

 

The code:

 

// create the HTTP Request
HttpRequest req = new HttpRequest();

//set the url to send the request
req.setEndpoint('http://api.facebook.com/restserver.php');


req.setBody('method=stream.publish&message='+subjectLine);
req.setMethod('POST');
system.debug('body of message at req.getEndpoint '+req.getEndpoint());

//create an HTTP object and use it to send the request
Http http = new Http();

//send the request and get the response.
HTTPResponse res = http.send(req);
String resBody = res.getBody();

XmlStreamReader reader = new XmlStreamReader(resBody);

 

system.debug('The response is : '+resBody);

 

Part of Response is below

<error_msg>This API version is deprecated</error_msg>

 

 

Looking for alternative methods, I could not find any alternative for it here, Face book API methods and here, Stream.publish

Also, the possible alternative i found, Feed.publishUserAction does not seem to help much.

 

Is it not working because it is beta or am i passing insufficient paramaters?

 

This is the complete response I got. Note that Error Code is 12. Does that tell something?

 

The response is : <?xml version="1.0" encoding="UTF-8"?>
<error_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
<error_code>12</error_code>
<error_msg>This API version is deprecated</error_msg>
<request_args list="true">
<arg>
<key>method</key>
<value>stream.publish</value>
</arg>
<arg>
<key>message</key>
<value>nokia 3600 slide problem</value>
</arg>
</request_args>
</error_response>

 

 

I am new to this. I have published as many info. possibile. May be some one can guide me in the right direction

 

Kenji775Kenji775

Hey, sorry to hear you are still having problems. I ran into that error myself more times than I care to remember. I have only a few more ideas.

 

1) In the Facebook API they do mention this:

"In addition, you should include a Content-Type: header of application/x-www-form-urlencoded."

 

2) You could try the new version of the API which is:

http://api.new.facebook.com/restserver.php

 

3) Do make sure both the posting user id, and the person you are trying to post to are marked as developers of your app. Otherwise you might get that error.

 

4) I just noticed you don't seem to send the target_id or the uid. I think you need those. Those are just the ID's of the proper facebook profiles. I just used my person facebook profile ID for both while I was testing, that seeemd to work fine. So try something like

method=stream.publish&message='+subjectLine&target_id=[your ID]&uid=[your ID]

 Maybe that wil help.

 

5) Last possible thought, the function I use to compose the API requests always includes the api_key, the call_id, the sig, and the v parameters, regardless if they are required or not. I know the docs for stream.publish say you don't need them, but maybe the docs are wrong. You could try including those variables.

v = 1.0

call_id = any number that is guarenteed to be larger than the last call_id you send (I use the process tick count)

api_key = your api key

sig =  an MD5 encrypted string of all your paremters you are passing (might have to be alphabetically sorted) with your secret key as the key. This might be next to impossible to generate with Apex, if it can be done, I have no idea how. Maybe an Apex guru can help you there, if the sig is required at all that is.

 

Hopefully something there will help ya out. Let me know. Especially if you get it working, I wouldn't mind moving back to an all Apex solution for this, I just moved to CF cause i had such problems with Apex.

Prathap I am :)Prathap I am :)
Hi Guys,
I am working on salesforce to facebook integration using REST API . we need to pull all the data from the facebook .

So can you please share your code so that i ll refer it

I really need help guys