Overview

Elektron WebSocket API enables easy integration into a multitude of client technology environments such as scripting and web. This API runs directly on your TREP infrastructure or the Thomson Reuters platform and presents data in an open (JSON) readable format. The API supports all Thomson Reuters Elektron data models and can be integrated into multiple client technology standards e.g. JavaScript, Python, R, .Net etc.

TypeScript programming language is a typed superset of JavaScript that compiles to readable, standards-based JavaScript. The language is designed for application-scale JavaScript by adding optional types, classes, modules, ECMAScript 2015 features and future proposals to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript is as a first-class programming language in Microsoft Visual Studio and Angular web application platform. It also supported by various modern application frameworks like ReactJS, NodeJS and Express framework, ASP.Net Core, Vue.js and more.

This example shows how to implement the Elektron WebSocket API JavaScript web application with TypeScript programming language. The web application source codes are implemented in TypeScript language to connect, consume and display data from the ADS server via the Elektron WebSocket API in the web browsers. All source codes will be compiled to readable JavaScript file which the application will run from it.

 

*Note: The initial release of this API is for deployed TREP customers only (i.e. to use it you will need an installed version of TREP 3.2).

Supported Web Browsers

This example supports the following web browsers (based on the WebSocket browser supported)

  • Chrome
  • Firefox
  • IE11

Application files

The project includes complete TypeScript source codes, a simple Express.js web server applciation file, CSS files and all required static dependencies. All dynamic dependencies for compiling and building JavaScript source file are defined in package.json file which can be installed via npm install command.

  • src/ folder: The folder that contains all TypeScript source code files
  • web/ folder: The folder that contains all application web page files
  • web/dist folder: The folder that the compiled JavaScript application file named web_app.js will be generated and deployed
  • web/index.html: The application HTML page
  • web/css/cover.css: The application CSS file
  • web/libs/jquery-3.2.1.min.js: jQuery library file
  • web/bootstrap/cssweb/bootstarp/fonts and web/bootstrap/js folders: The folders for Bootstrap CSS and libraries files
  • package.json: Project's NPM dependencies file
  • tsconfig.json: Project's TypeSccript compiler options file
  • webpack.config.js: Project's Webpack compiler options file
  • server.js: Project's simple web server application file

Application Code Walkthrough

When building against the Elektron WebSocket API interface, you follow the standard HTML5 WebSocket connection initiation and event processing. That is, once you initiate a connection within your application, you define and process the events generated within standard WebSocket callbacks.

Establish a connection

The web_app.ts file implements the standard WebSocket required functions and callbacks to capture WebSocket events. Firstly, the application receives a connect command from the web UI's connect button. The application then establishes a connection with ADS server 3.2 in the connect() function.

//web_app.ts

//Initiate WebSocket connection
function connect(url: string): void {
  ws = new WebSocket(url, protocol);
  ws.onopen = onOpen;
  ws.onmessage = onMessage;
  ws.onerror = onError;
  ws.onclose = onClose;
}

//indicates that the connection is ready to send and receive data
function onOpen(event: any): void {
  console.log("connected");

  //$("#btnConnect").html("Connected");

  btnConnect.innerHTML = "Connected";
}

//An event listener to be called when a message is received from the server
function onMessage(event: any): void {

}

//An event listener to be called when an error occurs. This is a simple event named "error".
function onError(event: any): void {
  console.log(JSON.stringify(event.data));
}

//An event listener to be called when the WebSocket connection's readyState changes to CLOSED.
function onClose(event: any): void {
  console.log(JSON.stringify(event.data));
}

Sending Login request message

Next, the application sends the OMM Login request message to ADS server 3.2 in JSON format. In TypeScript, you can create JSON message with JSON object directly (like standard JavaScript) or via TypeScript's Interface and Class approaches. This application uses TypeScript's Interface and Class approach for creating the OMM JSON Login, Item request and Close request messaages.

We define the Login interfaces for the OMM Login Request message in json_msg_interface.ts file. We use export keyword to export each JSON object into TypeScript module.

//json_msg_interface.ts

//Interface for Login domain JSON message
export interface JSONLogin {
    ID:number;
    Domain:string;
    Key: JSONLoginKey;
}

//Interface for Login domain's Key attribute JSON message
export interface JSONLoginKey{
    Elements: JSONLoginKeyElements;
    Name: string;
}

//Interface for Login domain's Key's Elements attribute JSON message
export interface JSONLoginKeyElements{
    ApplicationId: string;
    Position: string;
}

Then we define the Login classes for the OMM Login Request message in json_msg_classes.ts file. The Login classes implement the Login interfaces based on json_msg_interface.ts file.

//json_msg_classes.ts

import { JSONLogin } from "./json_msg_interface";
import { JSONLoginKey } from "./json_msg_interface";
import { JSONLoginKeyElements } from "./json_msg_interface";

export { LoginMsg };

const loginDomain: string = "Login";

class LoginMsg implements JSONLogin {
  ID: number;
  Domain: string = loginDomain;
  Key: JSONLoginKey;

  constructor(
    ID: number,
    Name: string,
    ApplicationId: string,
    Position: string
  ) {
    this.ID = ID;
    let loginMsgKey_class = new LoginMsgKey(Name, ApplicationId, Position);
    this.Key = loginMsgKey_class;
  }
}

class LoginKeyElements implements JSONLoginKeyElements {
  ApplicationId: string;
  Position: string;
  constructor(ApplicationId: string, Position: string) {
    this.ApplicationId = ApplicationId;
    this.Position = Position;
  }
}

class LoginMsgKey implements JSONLoginKey {
  Name: string;
  Elements: JSONLoginKeyElements;
  constructor(Name: string, ApplicationId: string, Position: string) {
    this.Name = Name;
    let loginKeyElements_class = new LoginKeyElements(ApplicationId, Position);
    this.Elements = loginKeyElements_class;
  }
}

The web_app.ts file initiates the LoginMsg object and then sends it to ADS 3.2 via WebSocket.send() function. This login object will be compiled to standard Login JSON message in the compiled JavaScript we_app.js file.

//web_app.ts

import { LoginMsg } from "./json_msg_classes";
const loginID: number = 1;

//Create the Login JSON message from LoginMsg class and send it to ADS WebSocket
function sendLogin(username: string): void {
  let login: LoginMsg = new LoginMsg(loginID, username, "777", "127.0.0.1");
  ws.send(JSON.stringify(login));
}

Handling Login Refresh response message

All messages (Refresh, Update, Status, etc) from the ADS server will be available via WebSocket.onMessage() callback function. We implement this onMessage() callback function in web_app.ts file to print out incoming messages from ADS in the web browser's inMessagePre <pre> element tag.

//web_app.ts

let inMessagePre: any;

//An event listener to be called when a message is received from the server
function onMessage(event: any): void {

  let incomingdata = JSON.parse(event.data.toString());

  //Iterate each incoming JSON message
  let data:any = null;
  for (let index = 0; index < incomingdata.length; index++) {
    data = incomingdata[index];
    display(inMessagePre,JSON.stringify(incomingdata[index], undefined, 2));
  }
}

//display string value in selected element
function display(el:any, msg:string): void{
  el.innerHTML = msg;
}

window.onload = () => {
  ...
  inMessagePre  = document.getElementById("inMessagePre");
}

Sending Item request message

Next, we implement the application source code to send the OMM Market Price request message to ADS server when users click the Subscribe button in the web UI.

We define the Item Request interfaces for the OMM Market Price Request message in json_msg_interface.ts file. We use export keyword to export each JSON object into TypeScript module. We set the ADS Service information as an optional information in the JSONItemRequestKey interface because it is an optional parameter in the OMM Request message.

//json_msg_interface.ts

//Interface for Market Price domain item request JSON message
export interface JSONItemRequestMsg {
    ID: number;
    Key: JSONItemRequestKey;
}

//Interface for Market Price domain item request's key attribute JSON message, service name is an optional 
export interface JSONItemRequestKey {
    Name: string;
    Service?: string;
}

Next we define the Item Request classes for the OMM Market Price request message in json_msg_classes.ts file. The Item Request classes implement the Item Request interfaces based on json_msg_interface.ts file.

//json_msg_interface.ts

import { JSONItemRequestMsg } from "./json_msg_interface";
import { JSONItemRequestKey } from "./json_msg_interface";

export { ItemRequestMsg };

class ItemRequestMsg implements JSONItemRequestMsg {
  ID: number;
  Key: JSONItemRequestKey;
  constructor(ID: number, Name: string, Service: string) {
    this.ID = ID;
    let itemrequestKey_class = new ItemRequestMsgKey(Name, Service);
    this.Key = itemrequestKey_class;
  }
}

class ItemRequestMsgKey implements JSONItemRequestKey {
  Name: string;
  Service?: string;

  constructor(Name: string, Service?: string) {
    this.Name = Name;
    if (Service !==''){
      this.Service = Service;
    }
    
  }
}

The web_app.ts file initiates the ItemRequestMsg object based on user input from the web UI and sends it to ADS server via WebSocket.send() function. This item request message object will be compiled to a standard Item Request JSON message in the compiled JavaScript we_app.js file.

//web_app.ts

import { ItemRequestMsg } from "./json_msg_classes";
let itemID: number = 0;
let itemname:string = "";

//Create the Item Request JSON message from ItemRequestMsg class and send it to ADS WebSocket
function sendItemrequest(service: string, item_name: string): void {
  //set Item ID value
  if (itemID === 0) {
    itemID = loginID + 1;
  } else {
    itemID += 1;
  }

  let itemrequest: ItemRequestMsg = new ItemRequestMsg(
    itemID,
    item_name,
    service
  );

  ws.send(JSON.stringify(itemrequest));
  display(outMessagePre,JSON.stringify(itemrequest));

}

window.onload = () => {

  btnSubscribe.addEventListener("click", function() {
    let txtServiceName:any = document.getElementById("txtServiceName");
    let txtItemName:any = document.getElementById("txtItemName");
    itemname = txtItemName.value;
    sendItemrequest(txtServiceName.value, itemname);
  });
};

Handling incoming Item response message

All messages (Refresh, Update, Status, etc) for all Domains from the ADS server will be available in WebSocket.onMessage() callback function. We will modify the onMessage() callback function in web_app.ts file to support incoming Market Price data from ADS.

The onMessage() callback function verifies if incoming message is an incoming Market Price Refresh Response message or not by checking the data type and data.Key.Name property. If it is the Market Price Refresh message, it calls the pushIDstoDropDownMenu() function to add this item name and subscription id to the web UI list box. These item name and subscription id information will be used for unsubscribing items.

The onMessage() callback function also print out incoming Market Price messages from ADS in the web browser's inMessagePre <pre> element tag.

//web_app.ts

let inMessagePre: any;
let itemname:string = "";

//An event listener to be called when a message is received from the server
function onMessage(event: any): void {

  let incomingdata = JSON.parse(event.data.toString());

  //Iterate each JSON message and send it to market_price_app.js
  let data:any = null;
  for (let index = 0; index < incomingdata.length; index++) {
    data = incomingdata[index];
    if(data.Type === 'Refresh' && data.Key.Name === itemname){
      //Push subscription item name and ID to selection box
      pushIDstoDropDownMenu(data.Key.Name, data.ID);
    }
    display(inMessagePre,JSON.stringify(incomingdata[index], undefined, 2));
  }
}
//display string value in selected element
function display(el:any, msg:string): void{
  el.innerHTML = msg;
}

window.onload = () => {
  ...
  inMessagePre  = document.getElementById("inMessagePre");
}

function pushIDstoDropDownMenu(itemname:string, id:number):void {

  let cb:any = document.getElementById("listenerCombo");
  let opt:any = document.createElement("option");
  opt.value = id;
  opt.text = `${itemname} ID ${id}`;
  cb.options.add(opt);
}

Unsubscribe Market Price Item

Next, we implement the application source code to send the OMM Market Price close request message to ADS server 3.2. We define the Close Request interfaces for the Close Request message in json_msg_interface.ts file. We use export keyword to export each JSON object into TypeScript module. We set the Domain information as an optional In the JSONClose interface because it is an optional parameter in the OMM Close message (Market Price by defaulted).

//json_msg_interface.ts

//Interface for close JSON message
export interface JSONClose {
    Domain?: string;
    ID: number;
    Type: string;
}

Next we define the Close Message classe in json_msg_classes.ts file. The Close Message class implements the JSONClose interface based on json_msg_interface.ts file.

//json_msg_interface.ts

import { JSONClose } from "./json_msg_interface";

export {CloseMsg};

class CloseMsg implements JSONClose{
  Domain?: string;
  ID: number;
  Type: string;

  constructor(ID: number, Domain?: string) {
    this.ID = ID;
    this.Domain = Domain;
    this.Type = "Close";
  }
}

When unsubscribing item, users must choose the item name and subscription id that users want to unsubscribe from the web UI list box, then click the Unsubscribe button. We implement this UI interaction in web_app.ts file.

//web_app.ts

window.onload = () => {

  btnUnSubscribe.addEventLisener("click", function() {
    //get Selected ID to unsubscribe
    let cb:any = document.getElementById("listenerCombo");
    if(cb.selectedIndex === -1){ //If user does not select any ID, alert user
      window.alert("Select ID first");
      return;
    }
    //get unsubscribe ID from HTML select element
    let unsubID:number = parseInt(cb.options[cb.selectedIndex].value);
    //Unsubscribe 
    sendItemCloserequest(unsubID);

    //remove unsubscribe ID from HTML select element
    cb.removeChild(cb.options[cb.selectedIndex]);
  });
};

The web_app.ts file initiates the closeitemrequestMsg object, receives user input from the web UI and then sends it to ADS 3.2 via WebSocket.send() standard function. This item close request message object will be compiled to a standard Item Close Request JSON message in the compiled JavaScript we_app.js file.

//web_app.ts

import { CloseMsg } from "./json_msg_classes";

//Create the Item Close Request JSON message from ItemCloseRequestMsg class and send it to ADS WebSocket
function sendItemCloserequest(unsubID:number): void {
  //let closeitemrequestMsg: ItemCloseRequestMsg = new ItemCloseRequestMsg(itemID);

  let closeitemrequestMsg: CloseMsg = new CloseMsg(unsubID);

  ws.send(JSON.stringify(closeitemrequestMsg));
  display(outMessagePre,JSON.stringify(closeitemrequestMsg));
}

Handling Ping Pong messages

The last step is handling the Ping and Pong messages. The Ping and Pong messages are the handshake message in JSON format ({ "Type": "Ping" } and { "Type": "Pong" }) between the ADS WebSocket server and client for monitoring a connection health. The ADS server periodically sends Ping message to applications and applications must be prepared to send Pong messages as a response to any Ping message they receive.

The application will receive the Ping message via WebSocket.onMessage() callback function. We will modify this function to detect an incoming Ping message, then sends the Pong message back to ADS server.

//web_app.ts

//An event listener to be called when a message is received from the server

function onMessage(event: any): void {

  let incomingdata = JSON.parse(event.data.toString());

  //Iterate each JSON message and send it to market_price_app.js
  let data:any = null;
  for (let index = 0; index < incomingdata.length; index++) {
    data = incomingdata[index];

    if(data.Type === 'Refresh' && data.Key.Name === itemname){
      //Push subscription item name and ID to selection box
      pushIDstoDropDownMenu(data.Key.Name, data.ID);
    }
    display(inMessagePre,JSON.stringify(incomingdata[index], undefined, 2));
    //If incoming message is PING (server ping)
    if (incomingdata[index].Type === "Ping") {
      sendPong();
    }
  }
}

//Create the client PONG message  and send it to ADS WebSocket
function sendPong(): void {
  let pong: any = { Type: "Pong" };
  ws.send(JSON.stringify(pong));
  display(outMessagePre,JSON.stringify(pong));
}

Application Setup

The application source code is available at GitHub. You can get it via the following git command

$>git clone git@github.com:TR-API-Samples/Example.EWA.TypeScript.WebApplication.git

This example requires the following dependencies softwares and runtime

  1. Node.js runtime - version 8.9.3 or higher.
  2. npm package manager (included in Node.js)
  3. TypeScript compiler (will be installed via npm install command)
  4. Express.js web framework (will be installed via npm install command)

This example also uses the following 3rd party libraries for UI presentation only.

  1. jQuery 3.2.1 JavaScript library
  2. Bootstrap 3.3.7 CSS library

please check the README.md in the source code project for more detail.

How to run this example

  1. Get the project via the above git command
  2. Run $> npm install command in the command prompt to install all the required dependencies to run the sample in a subdirectory called node_modules/
  3. If the machine is behind a proxy server, you need to configure Node.js uses proxy instead of a direct HTTP connection via the following command in command prompt: 
    set https_proxy=http://<proxy.server>:<port>

     

  4. Run $> npx webpack command in the command prompt to build and compile all TypeScript files in src folder into JavaScript source file (/web/dist/ folder) 
  5. Run $> node server.js command in the command prompt to start the web server at HTTP port 8080 
  6. Open web browser (IE11, Chorme and Firefox), then navigate to index.html of the web server at http://localhost:8080/index.html. When you open index.html in your browser. The application page will show in the web browser. 

References

For further details, please check out the following resources:

For any question related to this article or Elektron WebSocket API page, please use the Developer Community Q&A Forum.