Skip to Content

SAPUI5 and Twitter API

Hi,

This blog will show how to use the Twitter REST API in a SAPUI5 application.  In this example I will use the Twitter Search API (search/tweets.json).

All other API services can be found here: API Console Tool | Twitter Developers. (Log on with your twitter account)

Prerequisites:

– create a Twitter application (Twitter Application Management)

– retrieve: Customer Key, Customer Secret, Access Token and Access Token secret.

Creating a signature

This explains how to generate an OAuth 1.0a HMAC-SHA1 signature for a HTTPS request. This signature will be suitable for passing to the Twitter API as part of an authorized request.

 

first we have to declare some variables:

var customer_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
var customer_secret = "xxxxxxxxxxxxxxxxxxxxxxxxx";
var access_token= "xxxxxxxxx";
var access_token_secret = "xxxxxxxxxxx";
                               
var signing_key = customer_secret + "&" + access_token_secret;
                               
var signature_method = "HMAC-SHA1";
var authorization_version = "1.0";
var method = "GET";
var protocol = "https";
var server = "api.twitter.com";
var version = "1.1";
var service = "search/tweets.json";

 

STEP 1: Create base url:

The base URL is the URL to which the request is directed, minus any query string or hash parameters.

var BaseURL = protocol + "://" + server + "/" + version + "/" + service;


 

STEP 2: Collect your parameters:

Next, gather all of the parameters included in the request.

 

var callback = "callback=twitterCallback";
var count = "count=" + this.count;
var language = "lang=" + this.lang;
var oauth_consumer_key = "oauth_consumer_key=" + customer_key + "&";
var oauth_nonce = "oauth_nonce=" + this.makeid() + "&";
var oauth_signature_method = "oauth_signature_method=" + signature_method + "&";
var oauth_timestamp = "oauth_timestamp=" + Math.floor(Date.now() / 1000) + "&";
var oauth_token = "oauth_token=" + access_token + "&";
var oauth_version = "oauth_version=" + authorization_version + "&";
var query = "q=" + encodeURIComponent(oEvent.getParameter("query"));
var result_type = "result_type=" + this.resultType;

 

oauth_nonce must be a generated string. this.makeid() is a method that generates a string of 10 characters.

 

STEP 3: create authorization parameter string and search options:

var oauth_parameters = oauth_consumer_key + oauth_nonce + oauth_signature_method + oauth_timestamp + oauth_token + oauth_version;
var searchOption = query + "&" + count + "&" + result_type;

 

STEP 4: Create parameterstring:

this is a very important step: concatenate all parameters alphabetically:

var parametersString = callback + "&" + count + "&" + language + "&" + oauth_parameters + query + "&" + result_type;

 

STEP 5: Create signature string:

  1. encode the complete parameter string
  2. encode the base url
  3. append the method. (method in upper case!!!)
var signatureBaseString = method + "&" + encodeURIComponent(BaseURL) + "&" + encodeURIComponent(parametersString);

it should look like this:

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&callback%3DtwitterCallback%26count%3D100%26lang%3Dnl%26oauth_consumer_key%3Da5IGWlSrrLyI7GEPV5ZMY1MiP%26oauth_nonce%3DoJV2FF2PtC%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1453384662%26oauth_token%3D2744465306-RGKnQQl5l5p1bZBNlUqbYrEROBqvZx6ij5ZIOos%26oauth_version%3D1.0%26q%3Datos%26result_type%3Dmixed

 

 

STEP 6: Calculating the signature:

 

In this step we create the authorization signature. The signature is calculated, based on the encoded signatureBaseString and the signing_key.

You can find a lot of HMAC SHA1 hashing algoritms on the internet, but I used the algoritms from CryptoJS ( crypto-js –   JavaScript implementations of standard and secure cryptographic algorithms – Google Project Hosting )

these 2 are needed:

I downloaded them to my project folder.

jQuery.sap.require("TwitterSearch_v002.util.HMACsha1");
jQuery.sap.require("TwitterSearch_v002.util.EncodeBase64");

First I used:

jQuery.sap.includeScript("http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js");
jQuery.sap.includeScript("http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js");

but I get the message:

Mixed Content: The page at ‘https://webidetesting1208672-s0009219687trial.dispatcher.hanatrial.ondemand…onentPreload=off&origional-url=index.html&sap-ui-appCacheBuster=..%2F..%2F‘ was loaded over HTTPS, but requested an insecure script ‘http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js‘. This request has been blocked; the content must be served over HTTPS.t @ sap-ui-core.js:88

sap-ui-core.js:88 Mixed Content: The page at ‘https://webidetesting1208672-s0009219687trial.dispatcher.hanatrial.ondemand…onentPreload=off&origional-url=index.html&sap-ui-appCacheBuster=..%2F..%2F‘ was loaded over HTTPS, but requested an insecure script ‘http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js‘. This request has been blocked; the content must be served over HTTPS.

getting the signature:

var hash = CryptoJS.HmacSHA1(signatureBaseString, signing_key);
var base64String = hash.toString(CryptoJS.enc.Base64);
var oauth_signature = encodeURIComponent(base64String);

 

STEP 7: Build the url

ok, so now we have everything to build our url, to call the API:

concatenate as follow:

var URL = BaseURL + "?" + searchOption + "&" + oauth_parameters + "oauth_signature=" + oauth_signature + "&" + language + "&" + callback;

So now we have the url to retrieve the data.

Getting the data

I use JSONP to retrieve the data via a callback function. You can also use an xmlhttprequest (in JQuery or Ajax) but I got an access-control-allow-origin error due to CORS problems…(I am running my app on the HANA Cloud Platform) But luckily Twitter supports the use of JSONP. In step 4 ,the parameter “callback” was added to the parameter string. The name of the function can be chosen.  In this example I use “twitterCallback”. Don’t forget to add this parameter in the parameter string!!

So, JSONP: first you have to inject the script in the header of the page:

var socialGetter = (function() {
  /* just a utility to do the script injection */
  function addScript(url) {
  var script = document.createElement('script');
  script.async = true;
  script.src = url;
  document.body.appendChild(script);
  }
  return {
  getTwitterTweets: function(url) {
  addScript(url);
  }
  };
  })();

then, you have to define the callback function:

                                                window.twitterCallback = function(data) {
                                                                if (data) {
                                                                                var twitterResult = new sap.ui.model.json.JSONModel();
                                                                                twitterResult.setData(data);
                                                                                sap.ui.getCore().byId("__xmlview0").setModel(twitterResult, "twitterResult");
                                                                }
                                                };

The output format is JSON, so I use sap.ui.model.json.JSONModel.

notice that I use “window.twitterCallback”. this is because a callback method is always a global function, so you have to declare a global function.

with this code:

sap.ui.getCore().byId("__xmlview0").setModel(twitterResult, "twitterResult")

;

I retrieve the search view and set the model “twitterResult”.

ok, so now we can call the url:

socialGetter.getTwitterTweets(URL);

View

In the view I use a list of objectListItems:

<List busyIndicatorDelay="{masterView>/delay}" growing="true" growingScrollToLoad="true" id="list"
  items="{ path: 'twitterResult>/statuses', sorter: { path: 'accountID', descending: false }, groupHeaderFactory: '.createGroupHeader' }"
  mode="{= ${device>/system/phone} ? 'None' : 'SingleSelectMaster'}" noDataText="{masterView>/noDataText}" selectionChange="onSelectionChange"
  updateFinished="onUpdateFinished">
  <infoToolbar>
  <Toolbar active="true" id="filterBar" press="onOpenViewSettings" visible="{masterView>/isFilterBarVisible}">
  <Title id="filterBarLabel" text="{masterView>/filterBarLabel}"/>
  </Toolbar>
  </infoToolbar>
  <items>
  <ObjectListItem icon="{twitterResult>user/profile_image_url}"
  intro="{twitterResult>user/name} - {twitterResult>created_at} - {twitterResult>user/location}" press="onSelectionChange"
  title="{twitterResult>text}" type="{= ${device>/system/phone} ? 'Active' : 'Inactive'}"></ObjectListItem>
  </items>
  </List>

an example of a tweet looks like this (in JSON):

"statuses": [
   {
  "metadata": {
  "iso_language_code": "en",
  "result_type": "recent"
   },
  "created_at": "Thu Jan 21 14:47:27 +0000 2016",
  "id": 690183933741310000,
  "id_str": "690183933741309954",
  "text": "Throwback Thursday    // NYC shoot with elite_e46 for @pbmwmagazine // #meatyflush #bmw #bmwusa… https://t.co/7w1x7293Sf",
  "source": "<a href="http://instagram.com" rel="nofollow">Instagram</a>",
  "truncated": false,
  "in_reply_to_status_id": null,
  "in_reply_to_status_id_str": null,
  "in_reply_to_user_id": null,
  "in_reply_to_user_id_str": null,
  "in_reply_to_screen_name": null,
  "user": {
  "id": 2418867279,
  "id_str": "2418867279",
  "name": "MeatyFlush",
  "screen_name": "MeatyFlush",
  "location": "DMV",
  "description": "We are a photography collective who's sole purpose is to capture the car scene featuring some of the hottest and greatest automobiles in the DMV.",
  "url": "http://t.co/lk0XSiqxNR",
  "entities": {
  "url": {
  "urls": [
   {
  "url": "http://t.co/lk0XSiqxNR",
  "expanded_url": "http://meatyflush.com",
  "display_url": "meatyflush.com",
  "indices": [
  0,
  22
   ]
   }
   ]
   },
  "description": {
  "urls": []
   }
   },
  "protected": false,
  "followers_count": 57,
  "friends_count": 14,
  "listed_count": 14,
  "created_at": "Tue Mar 18 01:02:57 +0000 2014",
  "favourites_count": 19,
  "utc_offset": null,
  "time_zone": null,
  "geo_enabled": false,
  "verified": false,
  "statuses_count": 1552,
  "lang": "en",
  "contributors_enabled": false,
  "is_translator": false,
  "is_translation_enabled": false,
  "profile_background_color": "C0DEED",
  "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
  "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
  "profile_background_tile": false,
  "profile_image_url": "http://pbs.twimg.com/profile_images/519541485772214272/aKA7PMCO_normal.jpeg",
  "profile_image_url_https": "https://pbs.twimg.com/profile_images/519541485772214272/aKA7PMCO_normal.jpeg",
  "profile_banner_url": "https://pbs.twimg.com/profile_banners/2418867279/1395120295",
  "profile_link_color": "0084B4",
  "profile_sidebar_border_color": "C0DEED",
  "profile_sidebar_fill_color": "DDEEF6",
  "profile_text_color": "333333",
  "profile_use_background_image": true,
  "has_extended_profile": false,
  "default_profile": true,
  "default_profile_image": false,
  "following": false,
  "follow_request_sent": false,
  "notifications": false
   },
  "geo": null,
  "coordinates": null,
  "place": null,
  "contributors": null,
  "is_quote_status": false,
  "retweet_count": 0,
  "favorite_count": 0,
  "entities": {
  "hashtags": [
   {
  "text": "meatyflush",
  "indices": [
  70,
  81
   ]
   },
   {
  "text": "bmw",
  "indices": [
  82,
  86
   ]
   },
   {
  "text": "bmwusa",
  "indices": [
  87,
  94
   ]
   }
   ],
  "symbols": [],
  "user_mentions": [
   {
  "screen_name": "PBMWmagazine",
  "name": "PBMW",
  "id": 169887768,
  "id_str": "169887768",
  "indices": [
  53,
  66
   ]
   }
   ],
  "urls": [
   {
  "url": "https://t.co/7w1x7293Sf",
  "expanded_url": "https://www.instagram.com/p/BAzhLBmPkIE/",
  "display_url": "instagram.com/p/BAzhLBmPkIE/",
  "indices": [
  96,
  119
   ]
   }
   ]
   },
  "favorited": false,
  "retweeted": false,
  "possibly_sensitive": false,
  "lang": "en"
   }

the output looks like this:

Clipboard01.jpg

Enjoy!!

bye 😉

7 Comments
You must be Logged on to comment or reply to a post.