The easiest way to use Twitter API 1.1+ in JavaScript code

The easy way to implement Twitters API 1.1+ in pure JavaScript?

Create a simple proxy API.



The problem

When Twitter turned off verison 1.0 of their API, on millions of websites Twitter functionality stopped working overnight -- whereever it had been implemented with client-side code. The current version of Twitter API (from 1.1 onwards) requires oAuth authentication, which is not well supported by JavaScript.


The solution: use a proxy API instead

However, it's possible to make your old client-side Twitter API code work again, simply by creating a Twitter API proxy to your website, and updating the URL of the API in your code accordingly. Your JavaScript code can then call the proxy API instead of the real Twitter API. The proxy service is merely a wrapper around the Twitter API, handling all the hassle of oAuth etc under the hood. Now you can just use simple JavaScript, e.g. the standard JQuery Ajax/json methods. You'll probably also need to make a couple of minor tweaks to your code to accommodate the slight differences in the structure of data returned by Twitter API 1.1 compared to Twitter API 1.0.

Proxying can be an efficient way to utilise a third-party API like Twitter's. In fact, even with the original version of Twitter's API, I tended to use my own code to mediate between the web application and Twitter's API. This strategy can add resilience, e.g. when Twitter's API is down, as it frequently was in the old days, your intermediary application can gracefully serve its latest cache of the same data. Of course, there may be other important architectural/infrastructural considerations --performance, scalability, etc.


Alternatives

Alternatives to using the Twitter API include Embedded Tweets and related features, as well as widgets.js. Indeed, the official options can work nicely alongside an API proxy, e.g. using Embeded Tweets to properly display tweets obtained from the API. I've praised YQL in the past -- YQL along with the YQL Console is one of the coolest and most powerful web techologies you'll ever encounter.

I strongly reccomend trying the awesome YQL platform as a third-party proxy for any API including Twitter, and there are some good examples of the YQL approach.


Conclusion

In conclusion, there are numerous to use the Twitter API in your client side web applications -- it's just a case of ensuring your solution does not expose your secret authentication credentials to the web.

 


Source code:

using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json.Linq;
 
namespace TwitterApiClient
{
    /// <summary>
    /// Provides the simplest possible access to Twitter API.
    /// Website: http://www.timacheson.com/blog/2013/jul/twitter_api_proxy
    /// </summary>
    public class Client
    {
        private const string ApiBaseUrl = "https://api.twitter.com";
 
        #region Authentication
 
        /// <summary>
        /// Gets bearer token for application-only authentication from Twitter API 1.1, obtaining key and  
        
/// secret from web.config/app.config.
        /// * NOTE: This token should be cached by the application -- for up to 15 mins.
        /// * Dependant on web.config appSettings params twitterConsumerKey and twitterConsumerSecret.
        /// * Twitter API client oAuth settings: https://dev.twitter.com/app
        /// * Application-only authentication: https://dev.twitter.com/docs/auth/application-only-auth
        /// * API endpoint oauth2/token: https://dev.twitter.com/docs/api/1.1/post/oauth2/token
        /// </summary>
        /// <returns>oAuth bearer token for Twitter API authentication.</returns>
        public string GetBearerToken()
        {
            JToken token = JObject.Parse(
                GetBearerTokenJson(
                    ConfigurationManager.AppSettings["twitterConsumerKey"],
                    ConfigurationManager.AppSettings["twitterConsumerSecret"]));
 
            return token.SelectToken("access_token").Value<string>();
        }
 
        /// <summary>
        /// Gets bearer token for application-only authentication from Twitter API 1.1.
        /// * NOTE: This token should be cached by the application -- for up to 15 mins.
        /// * Twitter API client oAuth settings: https://dev.twitter.com/app
        /// * Application-only authentication: https://dev.twitter.com/docs/auth/application-only-auth
        /// * API endpoint oauth2/token: https://dev.twitter.com/docs/api/1.1/post/oauth2/token
        /// </summary>
        /// <param name="consumerKey">Token obtained from authentication.</param>
        /// <param name="consumerSecret">Token obtained from authentication.</param>
        /// <returns>oAuth bearer token for Twitter API authentication.</returns>
        public string GetBearerToken(string consumerKey, string consumerSecret)
        {
            JToken token = JObject.Parse(
                GetBearerTokenJson(consumerKey, consumerSecret));
 
            return token.SelectToken("access_token").Value<string>();
        }
 
        private static string GetBearerTokenJson(string consumerKey, string consumerSecret)
        {
            var webrequest = CreateRequest("/oauth2/token");
            webrequest.Headers.Add("Authorization", "Basic " +
                GetBasicAuthToken(consumerKey, consumerSecret));
 
            WriteRequest(webrequest, "grant_type=client_credentials");
 
            return ReadResponse(webrequest);
        }
 
        #endregion
 
        #region UserTimeline
 
        /// <summary>
        /// Gets a user timeline.
        /// * API endpoint user_timeline: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
        /// </summary>
        /// <param name="bearerToken">Token obtained from authentication.</param>
        /// <param name="screenName">username of user whose timeline will be returned.</param>
        /// <param name="count">Number of tweets to return</param>
        /// <param name="excludeReplies">Whether to exclude replies. False is reccomended because API
        /// removes replies after obtaining requested number of tweets, leading to unpredictable result
        /// counts.</param>
        /// <param name="includeRTs">Whether to include retweets. True is reccomended because API removes
        /// retweets after obtaining requested number of tweets, leading to unpredictable result
        /// counts.</param>
        /// <returns>Raw JSON response from API.</returns>
        public string GetUserTimelineJson(string bearerToken, string screenName, int count = 10,
            bool excludeReplies = false, bool includeRTs = true)

        {
            var webrequest = CreateRequest(
                "/1.1/statuses/user_timeline.json"
                + "?screen_name=" + screenName + "&count=" + count + "&exclude_replies="
                + excludeReplies.ToString().ToLower() + "&include_rts=" + includeRTs.ToString().ToLower());

 
            webrequest.Headers.Add("Authorization", "Bearer " + bearerToken);
 
            webrequest.Method = WebRequestMethods.Http.Get;
 
            return ReadResponse(webrequest);
        }
 
        #endregion
 
        #region Search
 
        /// <summary>
        /// Gets a user timeline.
        /// * API endpoint search: https://dev.twitter.com/docs/api/1.1/get/search/tweets
        /// </summary>
        /// <param name="bearerToken">Token obtained from authentication.</param>
        /// <param name="parameters">Search parameters in raw query string format,
        /// e.g. "q=from:BritishVogue, e.g. "q=#FNO".</param>
        /// <returns>Raw JSON response from API.</returns>
        public string GetSearchJson(string bearerToken, string parameters)
        {
            var webrequest = CreateRequest("/1.1/search/tweets.json" + parameters); 
            webrequest.Headers.Add("Authorization", "Bearer " + bearerToken); 
            webrequest.Method = WebRequestMethods.Http.Get;
 
            return ReadResponse(webrequest);
        }
 
        #endregion
 
        #region Helper methods
 
        private static WebRequest CreateRequest(string url)
        {
            var webrequest = WebRequest.Create(ApiBaseUrl + url);
            ((HttpWebRequest)webrequest).UserAgent = "timacheson.com";
            return webrequest;
        }
 
        private static string GetBasicAuthToken(string consumerKey, string consumerSecret)
        {
            return Base64Encode(consumerKey + ":" + consumerSecret);
        }
 
        private static void WriteRequest(WebRequest webrequest, string postData)
        {
            webrequest.Method = WebRequestMethods.Http.Post;
            webrequest.ContentType = "application/x-www-form-urlencoded";
 
            byte[] postDataBytes = Encoding.UTF8.GetBytes(postData);
 
            webrequest.ContentLength = postDataBytes.Length;
 
            using (var requestStream = webrequest.GetRequestStream())
            {
                requestStream.Write(postDataBytes, 0, postDataBytes.Length);
                requestStream.Close();
            }
        }
 
        private static string ReadResponse(WebRequest webrequest)
        {
            using (var responseStream = webrequest.GetResponse().GetResponseStream())
            {
                if (responseStream != null)
                {
                    using (var responseReader = new StreamReader(responseStream))
                    {
                        return responseReader.ReadToEnd();
                    }
                }
            }
 
            return null;
        }
 
        private static string Base64Encode(string s)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(s);
            return Convert.ToBase64String(bytes);
        }
 
        private static string Base64Decode(string s)
        {
            byte[] bytes = Convert.FromBase64String(s);
            return Encoding.ASCII.GetString(bytes);
        }
 
        #endregion
    }
}

 

04 July 2013

Share the love:

Comments: 22

Add Comment


Its really working awesome :) Thanks a ton


Thanks Tim, hoping this will save me a ton of work. just having trouble opening the sample asp.net solution in VS2010. Installed SP1 and MVC3, still getting "The project type is not supported by this installation." from VS for the TwitterAPIProxy project. Just wanted to see if you have any thoughts off top of your head what requirement i might be missing? Thanks again!

Tim Acheson (18 Jul 13, 12:13)

If the project doesn't load you probably just need .NET 4.0 installed if you already have VS2010 with up to date service packs and all versions of MVC.

But my Twitter proxy class is just one .cs file, so no need to load the whole project, just create your own and add the file and DLL references -- easy. :)

Erin Millard (22 Jul 13, 01:49)

You might also want to check out Mooch (https://github.com/eloquent/mooch). It's designed specifically to solve the problem of client-side API 1.1 access.


Can u please post the code for how to load twitter feeds for asp.net website.Please help me

Tim Acheson (16 Aug 13, 08:41)

@Greeshma see above! Or contact me.


Hi Tim,
Just wondering if you could post the code to access this Twitter API Client on an ASP.NET Weforms page. Would be useful thanks.

Tim Acheson (24 Aug 13, 14:37)

This is the simplest way to use my Twitter API class:

var query = "@timacheson";

var twitterApiClient = new TwitterApiClient.Client();

var bearerToken = twitterApiClient.GetBearerToken();

var tweets = twitterApi.GetSearchJson(bearerToken, query);

I wanted to make this clear, because couple of people have asked now. Obviously you'll need your own Twitter account details set in your own project's config file. Obviously in your own code you'll want to cache the bearer token and ideally also the tweets -- as done and commented in my working demo code! ;)


Hi! Thanks a lot for this. Cheers!


To get started with using the Twitter Api class, here's example code that works.

var query = "timacheson";

var twitterApiClient = new TwitterApiClient.Client();

var bearerToken = twitterApiClient.GetBearerToken();

var tweets = twitterApiClient.GetUserTimelineJson(bearerToken, query);

Debug.WriteLine(tweets);


Tim Can you provide me the code for getting the results/data of a hashtag in twitter plz....


Working great! Thanks!


Hi Tim, How do we show the user's Avatar?


Works perfectly and saved me plenty of time. I rolled it into a servicestack service w/o problems. Thank you!


Charles, you read my mind! Going to do the same later today.


ITs working great but i am getting only top 15 results how can i get all results. and how many results can we get in a single call


I got a error message at runtime :(
Invalid API response -- ensure the Twitter API credentials in web.config are the correct values for your own Twitter account.


I got a error message at runtime :(
Invalid API response -- ensure the Twitter API credentials in web.config are the correct values for your own Twitter account.


hello, what should I write in ascx file to show a user timeline? beacuse your code only get a timeline but no display

Mangesh Late (22 Oct 14, 09:04)

The remote server returned an error: (401) Unauthorized.

It will take Bearer value and after next request it show the error


when i use below request...
https://api.twitter.com/1.1/direct_messages.json
https://api.twitter.com/1.1/statuses/mentions_timeline.json
I'm getting Error as
The remote server returned an error: (403) Forbidden...
please help me out...

Tags:


  • Twitter
  • LinkedIn
  • Facebook
  • Windows Live / Messenger
  • Xbox Live
  • RSS
  • Email