The Post Excerpt

Recently, I had to find a solution to query Twitter’s Search API with my Ionic and Cordova app.

I had found some great posts by @nraboy and @saimon24 on very similar topics, so I expanded on them and I specifically modified the code found in saimon24’s post: http://blog.ionic.io/displaying-the-twitter-feed-within-your-ionic-app/

His code allows you to query Twitter’s API to return a timeline, with this link: https://api.twitter.com/1.1/statuses/home_timeline.json. I think his code will work for any of the static end points, but it doesn’t allow you to query the search API with additional parameters, such as this link:

https://api.twitter.com/1.1/search/tweets.json?q=yoga&result_type=recent

Notice the two extra parameters: q & result_type. The search api accepts a few other parameters, and the whole trick to it is in creating a signature hash that includes all params, including the oAuth parameters generated by ngCordova’s createSignature function.

Otherwise you’ll get this error:

{"errors":[{"code":32,"message":"Could not authenticate you."}]}

The end goal is to produce a url string that looks something like this, with the right signature!:

https://api.twitter.com/1.1/search/tweets.json?q=yoga&result_type=recent&oauth_consumer_key=7MrHtnETWM57mF6lKHskujPe7&oauth_token=583492865-A0EakIORoKNv7wYPIwwKNahO2tTOXmnuAH6Wq7uv&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1435852245&oauth_nonce=75Mk8T&oauth_version=1.0&oauth_signature=qq5z1PiiXB6u7pcGBCkblnpBBw%3D

Notice that it includes the two twitter API parameters, along with 6 oAuth parameters.

So let’s say you’re building an angular service that queries Twitter’s API and stores the resulting tweets. You’ll need to include $q, $cordovaOauth and $cordovaOauthUtility as dependencies and set up the following code:

if (window.cordova) {

        var q = $q.defer();

        //This could be any API Endpoint on Twitter that accepts params
        var search_tweets_url = 'https://api.twitter.com/1.1/search/tweets.json';

        //Use saimon's createTwitterSignature Function
        var oauthObj = createTwitterSignature('GET', search_tweets_url, buildParamObj(keywordObj));

        //Save and Delete the oAuth signature object because $.param screws it up
        var sigTemp = oauthObj.oauth_signature;
        delete oauthObj.oauth_signature;

        //Convert OAuth object to params, adjust for signature
        //Using $http because $resource gives me config errors for action query. Callback instead of promise :(
        //Make sure to include the $q library

        $http.get( search_tweets_url +'?' + buildParamString(keywordObj) + '&' + $.param(oauthObj) + '&oauth_signature=' + sigTemp )
        .success(function(data, status, headers, config) {
        console.log('Successul HTTP Request', data);
        tweets = data.statuses;
        q.resolve(tweets);
        })
        .error(function(data, status, headers, config) {
        console.log('Rejected HTTP Request ', status, headers);
        q.reject(reject);
        });

        return q.promise;

}

To start you’ll some sort of object with all your search parameters. I’ve only included 3 of them here, but there are several more you can use.

{
  q: 'Yoga',
  result_type: 'recent',
  count: 50
}

You can create the object above from another object (keywordFormObj) generated by your own custom input form (not covered in this post):

function buildParamObj(keywordFormObj) {

        var paramObject = {};

        paramObject.q = keywordFormObj.query;
        paramObject.result_type = "recent";

        if (keywordFormObj.lang) {
            paramObject.lang = keywordFormObj.lang;
        }

        //Count
        paramObject.count = 50;

        return paramObject;

    }

Now this new object has to be sent into the createTwitterSignature function as a third parameter, like so:

var oauthObj = createTwitterSignature('GET', search_tweets_url, buildParamObj(keywordObj));

And here is saimon’s slightly modified createTwitterSignature function (that still works with his prior post/code)

function createTwitterSignature(method, url, paramObj) {

        if (!paramObj) {
            paramObj = {};
        }

        var oauthObject = {
            oauth_consumer_key: clientId,
            oauth_nonce: $cordovaOauthUtility.createNonce(10),
            oauth_signature_method: "HMAC-SHA1",
            oauth_token: accessToken,
            oauth_timestamp: Math.round((new Date()).getTime() / 1000.0),
            oauth_version: "1.0"
        };

        var signatureObj = $cordovaOauthUtility.createSignature(method, url, oauthObject, paramObj, clientSecret, accessTokenSecret);
        $http.defaults.headers.common.Authorization = signatureObj.authorization_header;
        console.log('created Headers', $http.defaults.headers, signatureObj);
        return oauthObject;

    }

That function will return an oAuthObject with all the extra params you need to build your final search URL for twitter.

I then use jQuery to turn that object into a param string using $.param()

But there’s a slight problem because that function will re-encode any % chars, ruining the oauth_signature property, so I temporarily save the oauth_signature property from the object, delete it, and go ahead and create the parameter string. I then reattach the oauth_signature to the end of it.

search_tweets_url +'?' + $.param(buildParamObj(keywordObj)) + '&' + $.param(oauthObj) + '&oauth_signature=' + sigTemp

Notice how I also have to convert the buildParamObj into a string as well and attach it to the url. Be careful though, if you have special characters in your object, jquery might re-encode them, so you might want to build your param string manually, without using $.param().

$http is another dependency that you have to add to your service. In saimon24’s post he uses $resource, however I found it troublesome with complex queries, and decided to switch to $http. Instead of using promises it uses callbacks, so I wrapped the whole thing in a $q promise and I only return the result when the callback is completed, forcing my program to wait for the result from the service.

And here’s a bit of extra code that returns the same data, however I use it when I’m testing in the browser where ngCordova doesn’t work. You’ll need to include CodeBird to your project though!

if (!window.cordova) {

                var cb = new Codebird;
                cb.setConsumerKey(clientId, clientSecret);
                cb.setToken(accessToken, accessTokenSecret);

                cb.__call(
                    "search_tweets",
                    buildParamString(keywordObj),
                    function(reply, rate_limit_status) {
                        console.log('Codebird ', reply, rate_limit_status);

                        tweets = reply.statuses;

                        q.resolve(tweets);
                    }
                );

}

Good luck!


Next |

NEWSLETTER

Join

© 2016 ENGAGE Inc.

Do or do not. There is no try.

Subscribe to our newsletter

Sign up to our awesome newsletter and get the latest updates on web marketing and development. Guaranteed to be worth a read.

Subscribe
We promise to never share your information or spam your inbox.

Short Link

Use our free URL redirection service. Turns a long URL into a much shorter one.