Create RDP Manager Class using Dart
Overview
This article demonstrates use-cases and workflows for building a mobile application to shows a News headline and story content from the Refinitiv Data Platform (RDP). We will create a mobile demo application using the Flutter UI toolkit with a dart programming. We will use dart programming to create a class or library to support the functionality of the RDP REST API. The main functionalities that we need to support is a function to get Access Token from the RDP server and a function to search a news headline and retrieve news story content from News services.
To create a mobile UI, we will use the Flutter UI toolkit to build the app. Flutter can be natively compiled applications for mobile, web, and desktop from a single codebase. It is a free and open-source Google mobile UI framework that provides a fast and expressive way for developers to build native apps on both IOS and Android. You can also test the app on the Android emulator and ios emulator (macOS).
There are two parts for this article and this one is the first part to demonstrate how to use dart programming to create a class for retrieving News headlines data from RDP News services. The outcome from this article is a Dart library with a sample console app to test the functionality. The class will be used in the Mobile UI which is Part 2 of this article.
Below is a screenshot of the Flutter mobile app page break down by the use-case. We need to create a dart library to support these functions.
Prerequisites
Understand a basic concept of RDP and RDP REST API. We recommend you to read RDP API GENERAL GUIDELINES at the first steps. You can also test your RDP account with API Playground to understand the HTTP request and response messages the application has to send and receive.
Install Flutter and Dart. To build and run the sample application, you can follow instructions from Flutter dev page to setup Flutter on Windows or macOS. You also need to install Android Studio as we need to use an Android emulator to test the Flutter app. Please understand the primary usage of the Dart programming language and Flutter. There are many useful articles on the Internet, and you can also learn primary uses of Dart and Flutter from the Flutter developer site.
Visual Studio Code (VS Code). You can follow the setting from the Flutter Dev Getting start page to add the Flutter plugin to the visual studio code. Then you can use it to create a new project, write the codes, debug and then build and run the app on the emulator.
A valid RDP account with permission to retrieve news headlines and stories from RDP News services.
Create RDP Manager
In order to use RDP REST API, developers can use any programming languages which support the HTTP client library to send an HTTP request according to REST API specification to get the data from particular services. In this case, we will build a mobile application using Google Flutter UI toolkit, therefore, we can use the http client library provided in dart development kit to call a REST API.
We will create a class or library to provide interfaces to support the functionality of the REST API. It will use the dart http library to handle the HTTP requests and responses from the RDP server. The library will support the following functionalities on the RDP Services.
Get OAuth2 access token. This function will manage to get OAuth2 access token from RDP server. We need to pass the username, password, and client id in the Http request message to get the access token. Or we can use a refresh token to get the new access token from the server after the token is expired. The application has to pass the access token to the HTTP request header when calling the REST API to access the resource on the server.
Search news headlines. It will return a list of news headlines including its metadata from the News headline service.
Retrieve a news story including metadata from a News story service. Users must pass story id associated with the news headline to the function.
Implementations
Please note that we port the application logic to handle the HTTP request and response messages from C# websocket-api example provided on Github.
Let start creating a new dart console app using Visual Studio Code. You can press Ctrl+Shift+p (on windows) and then type 'Dart' and select Dart:New Project as below screenshot.
Select Console Application, and then select Console Application.
It will ask you to provide a project name and select location to generate the project files. Visual Studio Code will create a new console app with sample codes for you. Then you can modify or delete default files and replace it with our codes.
You can download the whole project and source files from Github. It's the project under folder rdp_manager_console_app. You can find RDP Manager class under the folder 'lib/rdp'.
In this article, we will omit some codes and show you only a snippet of codes required to implement the function.
Building RDP Manager class
This class is the main class to manage data and provide interface to retrieve contents from RDP. You can find full source codes from file <project folder>/lib/rdp/rdp_manager.dart. You can find the main interfaces for the class from the following snippet codes.
class RdpManager {
String clientId;
String refreshToken;
String scope;
String userName;
String userPassword;
rdpMsgData.AccessToken accessTokenInfo;
//Get OAuth2 acccess token from the server
Future<rdpMsgData.TokenResponse> getAuthenticationInfo(bool useRefreshToken,{String userName,String userPassword,String clientId,String refreshToken,String scope = 'trapi',String url}){
// Implementations
};
//Get News headlines from the server
Future<rdpMsgData.NewsHeadlineResp> getNewsHeadlines(
rdpMsgData.AccessToken accessToken,
{String query,
String cursor})
{
// Implmentations
};
//Get News Story from the server
Future<rdpMsgData.NewsStoryResp> getNewsStory(
rdpMsgData.AccessToken accessToken, String storyId)
{
// Implementations
};
}
Add function to get OAuth2 access token
getAuthenticationInfo is a function to get a username, password, and client id from user input and then send a Login request to the token endpoint to get the OAuth2 access token. This is the first method that the application has to call when using RDP services. This is because when you try to access resources on other services, you need to pass a valid access token in the Authorization header of the HTTP request message. Please find more details about the Authorization from Tutorial Page.
The root endpoint for REST API calls is:
https://api.refinitiv.com
Endpoint for Token Service:
/auth/oauth2/<VERSION>/token
class RdpEndpoints {
static const String rdp_hostname = "api.refinitiv.com";
static const String authTokenUrl = '/auth/oauth2/v1/token';
static const String streamServiceDiscUrl = '/streaming/pricing/v1/';
static const String newsHeadlinesUrl = '/data/news/v1/headlines';
static const String newsStoriesUrl = '/data/news/v1/stories';
}
Below is a snippet of codes for the implementation of the getAuthenticationInfo interface. It will return data as TokenResponse class which implemented in '<project>/lib/rdp/rdp_message_data.dart. The method uses the http client interface from the dart package so the app has to import the http library.
import 'package:http/http.dart' as http;
Create http headers.
var headerList = <String, String>{};
// Set Http Request Headers
headerList['Content-Type'] = 'application/x-www-form-urlencoded';
headerList['Accept'] = 'application/json';
headerList['AllowAutoRedirect'] = 'false';
Create a JSON request body and pass the username, password, and client id to the message. Users can just pass refresh_token in case that the access token about to expired.
// Construct JSON body for the Authentication request.
var body = {};
body['username'] = this.userName;
body['client_id'] = this.clientId;
if (useRefreshToken) {
body['grant_type'] = 'refresh_token';
body['refresh_token'] = this.refreshToken;
} else {
body['takeExclusiveSignOnControl'] = 'true';
body['grant_type'] = 'password';
body['scope'] = this.scope;
body['password'] = this.userPassword;
}
Then use the http client class to send a post message to a Token endpoint to get the new access token.
var tokenResp = rdpMsgData.TokenResponse();
var client = http.Client();
try {
var getTokenUri =
Uri.https(RdpEndpoints.rdp_hostname, RdpEndpoints.authTokenUrl);
var httpResponse =
await client.post(getTokenUri, headers: headerList, body: body);
//Handle http response message
//...
} on SocketException catch (e) {
print('SocketError Exception ${e.message}');
tokenResp.errorType = "SocketException";
tokenResp.errorDescription = e.message;
} catch (e) {
print("Unhandled Exception $e");
tokenResp.errorType = 'Unhandled Exception';
tokenResp.errorDescription = 'Unhandled Exception $e';
} finally {
client.close();
}
Process HTTP response message and get access token from the JSON message. Or process to get the error details from the response or exception in case that it fails. And then return TokenResp to the application.
if ((httpResponse.headers.containsKey('Transfer-Encoding') &&
httpResponse.headers['Transfer-Encoding'] == 'chunked') || httpResponse.body.isNotEmpty)
{
tokenResp.statusCode = httpResponse.statusCode;
tokenResp.reasonPhase = httpResponse.reasonPhrase;
tokenResp.errorType =
(json.decode(httpResponse.body) as Map<String, dynamic>)['error'];
tokenResp.errorDescription = (json.decode(httpResponse.body)
as Map<String, dynamic>)['error_description'];
if (httpResponse.statusCode == 200 && httpResponse.contentLength > 0) {
var accessTokenData = rdpMsgData.AccessToken.fromJson(
json.decode(httpResponse.body) as Map<String, dynamic>);
tokenResp.tokenData = accessTokenData;
}
// Handle HttpResponse status code
switch (httpResponse.statusCode) {
case 301:
case 302:
case 307:
case 308:
// Perform URL redirect
client.close();
print('${httpResponse.statusCode} ${httpResponse.reasonPhrase}');
String newHost = httpResponse.headers['Location'];
if (newHost != null && newHost.isNotEmpty) {
tokenResp =
await getAuthenticationInfo(useRefreshToken, url: newHost);
}
break;
}
}
accessTokenInfo = tokenResp.tokenData;
return tokenResp;
Create a function to get News headlines
Basically a get headlines operation is an endpoint under News Services group(/data/news/v1/) according to the API Docs page.
Get Headlines endpoint
/data/news/Version/headlines
Query Parameters
The user has an option to pass additional query parameters to get specific content related to the keyword in the query. The following parameters are request options.
query
The user search query. It supports Analyze operation. Analyze operation computes a tree expression from a user query string. It would break down a user query string into News related entities, then aggregate them into a boolean filtering tree. You can find more details of Analyze operation from the API Docs page.
limit Limit of headline (default 10, range value: [0, 100])
cursor The cursor is a pagination cursor that can be used to retrieve information by pages. Two cursors are prev and next depending on the direction in which you want to paginate. Most of our paginated endpoints support a cursors based syntax. Initial search results always return pagination information with all search contexts and can be used in the next page search.
Here is an example of cursors present in the response of headlines:
{
"data": [],
"meta": {
"next": "H4sIAAAAAAAAABWMsQ7CIBiE3+VWMQEikNZdt7qYGN0I/QcShAZKrWn67uJ2d9/dbXjb1aUaZ/SCYfJLampDpE/xI3oIpc2Ja2OkVipehodyz/h9HSQXHe+4PPNjC8Hgy0Br22LOlbAzlJT/tj3d0y2MrZIp0GKjo2tOdWrMhoD9B/aNdOODAAAA",
"prev": "H4sIAAAAAAAAABWMwQrCMBiD3yVXJ7TFtmze9TYvguitdL9QqO1o3ZyMvbu/tyRfkhUvt/g8pTc62WAMc2a1ItGnhgEdpDb2IIy1ymidTv1N+3v6PnZKyFa0Qh3FnkM0CLWnhbd4ulgJW4Oay9/z1TVf4sCdQpFmlzydS55GZi5GbD9x8rfohAAAAA=="
}
}
Then to get the next page for the same context use cursor value from the initial search:
/headlines?cursor=H4sIAAAAAAAAABWMsQ7CIBiE3%2BVWMQEikNZdt7qYGN0I%2FQcShAZKrWn67uJ2d9%2FdbXjb1aUaZ%2FSCYfJLampD
Sort Order
Support three values:
- New to Old (default)
- Old to New
- Most Read
If the MostRead sort order was selected, you could specify the date range for most read headlines using mostReadDateFrom and mostReadDateTo parameters.
For example:
/headlines?query=TOPNEWS&sort=mostRead&mostReadDateFrom=2011-10-10&mostReadDateTo=2018-10-10
If mostReadDateFrom or/and mostReadDateTo is specified, but the sort order is not equal to mostRead, values will be ignored.
Relevancy
Three values are supported:
- Filter on High relevance should return results for just HIGH
- Filter on "Medium" relevance should result for Medium+HIGH
- Filter on "All" relevance should result for Low+Medium+HIGH
For example:
headlines?query=A&relevance=Medium
Response Data
The response data is a JSON message containing fields that represent information such as a story id with headlines, text, and metadata; you can find a list of available fields and its usage from APIDocs.
In this example app, we will parse only fields we are interested such as a list of story id and its headlines, and keep it in our data structure so the application can get the list and show it in the UI.
Below is a class NewsHeadlineResp used to hold the News headlines response; we use it to cache the data from the Http response message.
class NewsHeadlineResp implements ResponseMsg {
List<NewsHeadlinesData> headlinesDatas;
NewsHeadlineMeta metaInfo;
@override
int statusCode;
@override
String reasonPhase;
@override
String errorType;
@override
String errorDescription;
}
The following codes are implementations of the getNewsHeadlines method. It starts with creating HTTP headers.
var headerList = <String, String>{};
headerList['Accept'] = 'application/json';
headerList['AllowAutoRedirect'] = 'false';
headerList['Authorization'] =
'${accessToken.tokenType} ${accessToken.accessToken}';
Build query parameters. There are two types of options supported by the app for now, that are query and cursor to get next page for the same data context.
var queryParameters = Map<String, String>();
if (query != null)
queryParameters['query'] = query;
else if (cursor != null) queryParameters['cursor'] = cursor;
var serverUri = Uri.https(RdpEndpoints.rdp_hostname,
RdpEndpoints.newsHeadlinesUrl, queryParameters);
And then use http get to retrieve data using headlines endpoints and query parameters.
rdpMsgData.NewsHeadlineResp headlinesResp = rdpMsgData.NewsHeadlineResp();
var client = http.Client();
var httpResponse = await client.get(serverUri, headers: headerList);
headlinesResp.statusCode = httpResponse.statusCode;
if (httpResponse.statusCode != 200) {
headlinesResp.reasonPhase = httpResponse.reasonPhrase;
headlinesResp.errorType =
(json.decode(httpResponse.body) as Map<String, dynamic>)['error'];
headlinesResp.errorDescription = (json.decode(httpResponse.body)
as Map<String, dynamic>)['error_description'];
}
If success we start parsing JSON message from the HTTP response. Below is a sample of the JSON message for the headlines response. Omit some parts to shorten a message.
{
"data": [
{
"storyId": "urn:newsml:reuters.com:20200911:nDJR9QcThk:1",
"newsItem": {
"_version": 1,
"contentMeta": {
"audience": [
{
"_qcode": "NP:MFDJ"
}
],
"creator": [
{
"_qcode": "NS:DJN",
"_role": "sRole:source"
}
],
"infoSource": [
{
"_qcode": "NS:DJN",
"_role": "sRole:source"
},
{
"_qcode": "NS:DJN",
"_role": "sRole:origProv"
}
],
"language": [
{
"_tag": "it"
}
],
"subject": [
{
"_qcode": "M:1QD"
}
],
"urgency": {
"$": 3
}
},
"itemMeta": {
"firstCreated": {
"$": "2020-09-11T09:19:17.053Z"
},
"versionCreated": {
"$": "2020-09-11T09:19:17.053Z"
},
"title": [
{
"$": "TOP STORIES MONDO: Microsoft denuncia attacchi hacker contro elezioni Usa"
}
]
}
}
},
{
"storyId": "urn:newsml:reuters.com:20200911:nDjcBkpdM:1",
"newsItem":
{
"title": [
{
"$": "TOP STORIES MONDO: Microsoft denuncia attacchi hacker contro elezioni Usa"
}
]
}
}
,
{
}
],
"meta": {
"count": 10,
"pageLimit": 10,
"next": "H4sIAAAAAAAAABWNywrCMBAA/2WvVkjEgo2nguDJCrWexENotxpYk5KkL0r/3e1x9jGzQGsooge1QJw7BAWtR4w4RUhg0NRvo+cjZ2pJfwKoF3xRN2QswntN4Ken2vU2gpIigc4MLm4yi2MwDf/KNMtOMhVHcRCpLcq8Hme04+7ALDIpz2J/yatbVXLBhGILK4ieuywPzm/IssrdqeETj4SDtjVeves73mkiWP/ASLWpxwAAAA==",
"prev": "H4sIAAAAAAAAABWOQQuCQBCF/8tcM1gLqbVTIAQejMpO0WHRMZemXdldzRD/e+PlwZs3882boNEU0EE6Qfh1CCk0DjHgGCCCQVG/jO63I7uG1MtD+oAWVU3aIDznCD5qrGxvAqSxiKDTgw0LzODX65pv40TKPUuyE8nWZPlVXqqyfa82YiOEjOODWGd5wXjti+UrF1DkERjtrVs8o0p7ppp3HBIOylR4crbvOFNEMP8BPZN3Z8UAAAA="
}
}
The following codes are sample codes the application used to parse the data from the JSON message. It starts from parsing an array of the story under the data node.
// Get a list contains story id.
var headlinesList = (json.decode(httpResponse.body)
as Map<String, dynamic>)['data'] as List<dynamic>;
if (headerList != null) {
List<rdpMsgData.NewsHeadlinesData> newsHeadlinesDataList =
List<rdpMsgData.NewsHeadlinesData>();
// Parsing Meta tag to get next and prev cursor
var metaInfo = (json.decode(httpResponse.body)
as Map<String, dynamic>)['meta'] as Map<String, dynamic>;
if (metaInfo != null) {
rdpMsgData.NewsHeadlineMeta metaData =
rdpMsgData.NewsHeadlineMeta.fromJson(metaInfo);
headlinesResp.metaInfo = metaData;
}
// Iterate through each node in array to get story id, firstcreated, version created and headline title.
headlinesList.forEach((element) {
var headlinesJsonData = element as Map<String, dynamic>;
var newsHeadlines = rdpMsgData.NewsHeadlinesData();
headlinesJsonData.forEach((key, value) {
switch (key) {
case 'storyId':
newsHeadlines.storyId =
headlinesJsonData['storyId'] as String;
break;
case 'newsItem':
{
(value as Map<String, dynamic>).forEach((key2, value2) {
if (key2 == 'itemMeta') {
(value2 as Map<String, dynamic>)
.forEach((key3, value3) {
switch (key3) {
case 'firstCreated':
newsHeadlines.firstCreated = (value3
as Map<String, dynamic>)['\$'] as String;
break;
case 'versionCreated':
newsHeadlines.firstCreated = (value3
as Map<String, dynamic>)['\$'] as String;
break;
case 'title':
String contentText = "";
(value3 as List<dynamic>).forEach((item) {
item.forEach((key4, value4) {
if (key4 == '\$') {
var content = value4;
contentText +=
(content == null) ? "" : content;
}
});
});
newsHeadlines.titleText = contentText;
break;
}
});
}
});
}
break;
}
});
newsHeadlinesDataList.add(newsHeadlines);
});
headlinesResp.headlinesDatas = newsHeadlinesDataList;
}
Create function to get News Story
Get Story endpoint
/stories/{story id}
Example
https://api.refinitiv.com/data/news/v1/stories/urn%3Anewsml%3Areuters.com%3A20190531%3AnL3N25U0E5
Get Story Content
The story can be retrieved in JSON or HTML format. And to select a story format, two options are available:
Set accept header:
- text/html
- application/json
extension
- json
- html
The extension has a higher priority than the header. It means that if, for example, accept header equal to "text/html", but story ID send as sampleStory.json result will be in JSON format. Using html is quite complicated than json format, which provided news story in plain text. You can find more details about the format of Html from the APIDocs page.
Note that our function will support only 'application/json' format, so it accepts only one input, which is a story id.
Same as the function to get news headlines, we create a class named NewsStoryResp to hold data from the response message. And below is a snippet code of the class.
class NewsStoryResp implements ResponseMsg {
NewsStoryData newsContent;
@override
int statusCode;
@override
String reasonPhase;
@override
String errorType;
@override
String errorDescription;
}
The getNewsStory function starts from creating the header using the same codes as news headlines, and we need to append the story id to the end of the endpoint like the following snippet code.
var serverUri = Uri.https(
RdpEndpoints.rdp_hostname, '${RdpEndpoints.newsStoriesUrl}/$storyId');
Then applications need to use the HTTP GET method to retrieve a News Story content.
var httpResponse = await client.get(serverUri, headers: headerList);
storyResp.statusCode = httpResponse.statusCode;
Last steps, we need to parse the JSON message to get content.
The function will parse only a language tag, headline text, and a news story in plain text format. The whole JSON Message contains a lot of metadata, so it quite long. We will omit unwanted nodes and focus only on the following JSON data.
Story Content
Node inlineData and inlineXml is a different representation of the same data. inlineData is a text representation, inlineXml is a formatted HTML markup which is ready to be used on HTML pages. Anyway, our function will parse content from inlineData node only.
"contentSet": {
"inlineData": {
"$": "string",
"_contenttype": "string"
},
"inlineXml": {
"$": "string",
"_contenttype": "string"
}
}
Language
It represents a list of Language in the news content.
"contentMeta": {
"language": [
{
"_tag": "en"
}
]
}
Title
Title is a short description of the news.
"contentMeta": {
"title": [
{
"$": "Bridgestone Enjoys Successful Olympic Winter Games Debut, Turns Attention to Olympic Games Tokyo 2020; Worldwide Olympic Partner's first global pro..."
}
]
}
Below is a snippet of codes that the function used to parse data from the JSON message.
var newsStoryData = rdp_message.NewsStoryData();
var newsItemData = (json.decode(httpResponse.body)
as Map<String, dynamic>)['newsItem'] as Map<String, dynamic>;
if (newsItemData != null) {
// Extract language
((newsItemData['contentMeta'] as Map<String, dynamic>)['language']
as List<dynamic>)
.forEach((element) {
if ((element as Map<String, dynamic>).containsKey('_tag')) {
newsStoryData.newsTitle =
(element as Map<String, dynamic>)['\$'];
}
});
// Extract News Title
((newsItemData['contentMeta'] as Map<String, dynamic>)['headline']
as List<dynamic>)
.forEach((element) {
if ((element as Map<String, dynamic>).containsKey('\$')) {
newsStoryData.newsTitle =
(element as Map<String, dynamic>)['\$'];
}
});
// Extract News Title
((newsItemData['contentSet'] as Map<String, dynamic>)['inlineData']
as List<dynamic>)
.forEach((element) {
if ((element as Map<String, dynamic>).containsKey('\$')) {
newsStoryData.newsContent =
(element as Map<String, dynamic>)['\$'];
}
});
storyResp.newsContent = newsStoryData;
}
Test the functionality
After creating the three functions, it's time to test and see if it works as we expected or not.
There is the main function implemented in file bin/main.dart. It will start when you run dart command or debug on Visual Studio code.
The application flow starts from the login to the RDP server and gets an access token. Then pass a query to getNewsHeadlines. The application will receive a list of headlines with story id. The last steps it will iterate through the list and call getNewStory to get a new content one by one and print to console.
Below is a snippet of codes from the primary function. It starts from setting the RDP account and set a query text to search headlines.
rdp.userName = '<RDP Username>';
rdp.userPassword = '<RDP Password>';
rdp.clientId = '<RDP Client ID>';
var headlinesQuery = '(Apple Iphone12) and searchIn:FullStory';
Then get OAuth2 Access Token and if it success, start a Timer to get a refresh token.
// Step1 : Get Access Token
var tokenResp = await rdp.getAuthenticationInfo(false);
if (tokenResp != null) {
if (tokenResp.statusCode == 200) {
PrintTokenInfo(tokenResp);
if (runLoop) {
Timer.periodic(
Duration(seconds: (tokenResp.tokenData.expiresIn * 0.9).round()),
(time) async {
myTimer = time;
if (tokenResp.statusCode == 200 &&
tokenResp.tokenData != null &&
tokenResp.tokenData.refreshToken != null) {
tokenResp = await GetNewToken(tokenResp.tokenData.refreshToken);
}
});
}
Next step, pass the Access Token to the getNewsHeadlines function and getNewsStory function to retrieve data from the News service
/// Run the loops to display news headline and fetch headlines
/// from next page cursor until it reach page count limit.
rdp_message.NewsHeadlineResp newsHeadlines;
var pageIndex = 0;
var pageCount = 0;
do {
if (newsHeadlines == null) {
newsHeadlines = await rdp.getNewsHeadlines(tokenResp.tokenData,
query: headlinesQuery);
} else {
newsHeadlines = await rdp.getNewsHeadlines(tokenResp.tokenData,
cursor: newsHeadlines.metaInfo.next);
}
if (newsHeadlines.statusCode == 200) {
if (pageCount == 0) pageCount = newsHeadlines.metaInfo.count;
print('Headlines Page#${pageIndex + 1}/$pageCount');
newsHeadlines.headlinesDatas.forEach((element) async {
print('${element.storyId} ${element.titleText}');
var storyResp =
await rdp.getNewsStory(tokenResp.tokenData, element.storyId);
if (storyResp.statusCode == 200) {
print('StoryId:${element.storyId}');
print('Title:${storyResp?.newsContent?.newsTitle}');
print('=======================================');
print(storyResp.newsContent.newsContent.replaceAll('\n', '\r\n'));
}
});
print('');
print('next ===>${newsHeadlines.metaInfo.next}');
} else {
print(
'Error => ${newsHeadlines.statusCode} ${newsHeadlines.errorDescription} Stop');
break;
}
} while (++pageIndex < newsHeadlines.metaInfo.count);
Running the app
Please download full projects and source files from Github.
There are two folder in the git repository. Go to folder rdp_manager_conosole_app\bin first.
You might need to start Terminal and run pubtool by typing pub get or flutter pub get command to get dependencies required by the project.
Then modify 'bin/main.dart' and change following lines to your RDP account.
rdp.userName = '<RDP Username>';
rdp.userPassword = '<RDP Password>';
rdp.clientId = '<RDP Client ID>';
and then change the headlinesQuery to a query you want to search in the following line:
var headlinesQuery = 'Put your query here';
Next step run dart application using the following command.
dart bin\main.dart
You will see Access Token print to console when the login is successful, and then the application will print the headline followed by story id and start retrieving a story.
Sampel Output
StatusCode:200
Token Type:Bearer
AccessToken:eyJ0eXAiOiJhdCtqd3QiLCJhbGciXXXXXXNUnibfnHkkCYYE4mrVgWN5_sEG9Y1FRhZdKwE147f7Jqi3mz0gqg4dM8WBZAC3LNRaBcKUTxYyQeE7r_8vR3j2w
RefreshToken:XXX8156-2XXXXXXXX7e5809522bb
Expired in:300 second
Headlines Page#1/10
urn:newsml:reuters.com:20200914:nRscdgmNDa:4 STM.PA: STMicroelectronics NV - Modeling for near term strength, but FX headwinds in 2021 (9 pages) - Credit Suisse
urn:newsml:reuters.com:20200914:nRscdgmNya:2 AMS.S: ams AG - 2H drivers in play - iPhone builds at ams and Auto recovery at Osram (9 pages) - Credit Suisse
urn:newsml:reuters.com:20200915:nRscdgmFJa:2 Electronics-苹果新品即将发布,关注消费电子产业机遇-09/12/2020 (10 pages) - Chuancai Securities Co., Ltd
urn:newsml:reuters.com:20200914:nRscdglqNa:2 AUERBACH GRAYSON: Asia Daily Morning Note 09-14-20: (AAC Technologies, Accton, Air China, China Resources Land, Berli Jucker, Cheng Loong Paper, China Eastern Airlines, China Southern Airlines, Chongqing Brewery, Oncosil Medical, CP All) (32 pages) - Auerbach Grayson & Co., Inc.
urn:newsml:reuters.com:20200914:nRscdglfda:1 KR: IT Hardware Industry: Anticipation rising towards 2H20 earnings for smartphone and foundry players (97 pages) - DBS Bank
urn:newsml:reuters.com:20200914:nRscdgkzna:1 华为发布鸿蒙 2.0 , 8 月特斯拉国内销售 1.18 万辆-09/14/2020 (17 pages) - CITIC Securities
urn:newsml:reuters.com:20200914:nRscdgkxXa:2 テクノロジーセクター: CS Japan Tech Weekly(Vol.20):先週の振り返りと今週の注目ポイントを整理 (21 pages) - Credit Suisse
urn:newsml:reuters.com:20200911:nRscdgcDJa:4 ITM Semiconductor (084850 KS)ΓÇöMultiple New Business Opportunities in FY21 (6 pages) - Haitong International Research
urn:newsml:reuters.com:20200911:nRscdgc3ca:1 KGI凱基台灣投資領航日報 -- 2020年09月11日 (27 pages) - KGI Greater China
urn:newsml:reuters.com:20200911:nRscdgc25a:1 KGI Taiwan Daily Navigator ΓÇôSeptember 11, 2020 (33 pages) - KGI Greater China
StoryId:urn:newsml:reuters.com:20200910:nRscdg9yra:1
Title:AUERBACH GRAYSON: Taiwanese Strategy - APPLE CONCEPTS HAVE THE ADVANTAGE OF THREE LOWS; IPHONE 12 WILL LURE BACK CAPITAL (Taiwan) (7 pages) - Auerbach Grayson & Co., Inc.
=======================================
R E S E A R C H R E P O R T D I S T R I B U T E D B Y The attached research report and the excerpts from the research report below were written entirely by a broker partner of Auerbach Grayson, and not by Auerbach Grayson. Auerbach Grayson is distributing/providing this research report for your consideration. P R E P A R E D B Y RESEARCH Market Report Taiwan Taiwanese Strategy September 10, 2020 APPLE CONCEPTS HAVE THE ADVANTAGE OF THREE LOWS; IPHONE 12 WILL LURE BACK CAPITAL > TaiwanΓÇÖs Apple (US) concepts stocks (excluding semiconductor) have foreign capital holdings of only 43.6%, the lowest point since 2015 and down significantly from the peak of 54.8% in 2017, which could be attributed to interference from the Sino-US trade war/tech war, the emergence of the red supply chain, and the impact of COVID19 on consumption. Going forward, with these negatives priced in to some extent and iPhone 12 coming up, which should help 4Q20 overall iPhone shipment growth YoY turn positive, foreign capital might be lured back to replenish stocks. In addition, foreign capital has had a habit of underweighting before product launches and buying back the stocks if the product sales are better than expected, and if iPhone 12 indeed is well received by market, then there is a chance foreign capital will return to replenish stock holdings. > Taiwanese Apple concepts'
...
traders@agco.com ops@agco.com Chief Executive Officer Managing Director, Head of Equities Managing Director, Global Trading Managing Director, Global Operations Asia Sales Asia Sales Asia Sales Asia / China Sales CEEMEA & LATAM Sales CEEMEA & LATAM Sales Global Emerging Markets Western Europe Sales Asia Trading Emerging Market Trading Emerging Market Trading Emerging Market Trading Western Europe Trading US & LATAM Trading Director, Global Capital Markets 1.212.453.3553 1.212.453.3545 1.212.557.4444 1.212.453.3518 david@agco.com adelafuente@agco.com gballantyne@agco.com fmuller@agco.com 1.212.453.3541 1.212.453.3515 1.212.453.3561 1.212.453.3539 1.212.453.3586 1.212.453.3571 44.773.941.0717 1.212.453.3538 hfukuchi@agco.com jhong@agco.com akukreja@agco.com jxiang@agco.com mdaoud@agco.com smandel@agco.com idevilder@ageurope.co.uk slueck@agco.com 1.212.557.4444 1.212.557.4444 1.212.557.4444 1.212.557.4444 1.212.557.4444 1.212.557.4444 mikelopiano@agco.com jkrase@agco.com ppeters@agco.com spollicino@agco.com kwood@agco.com ggimber@agco.com 1.212.453.3573 nbhatnagar@agco.com Trading Desk Hours (New York Time) ΓÇô Sunday 4:00 pm to Friday 5:00 pm (24 Hours) *After trading hours, please call 1.212.557.4444 and you will automatically be connected to a trader. Research Research Coordinator Information Services Ismael Sadek Settlement Information Technology 1.212.453.3549 1.212.453.3512 1.212.557.4478 research@agco.com it@agco.com ops@agco.com YOUR LOCAL BROKER IN OVER 125 MARKETS Auerbach Grayson & Company, LLC WORLDWIDE 25 West 45th Street New York, NY 10036 Telephone 212 557 4444 Toll-Free 1 800 31world web www.agco.com
Summary
In this article, we have described how to create a function to get Access Token from RDP and implement a function to retrieve news headlines and get its story content from a News Services using Dart programming. It also provides a sample code to parse a data returns from the RDP News services. You can add your own method to get additional data from the JSON message.
The library would be used to develop a mobile app in Part 2 of this article. In the second part, we will describe how to integrate the functions from the class with a Flutter UI toolkit to create a Mobile app. Users can deploy the app on android or ios and then use the app to log in to the RDP server and retrieve news headlines from user input. Let see the implementation in the second part.