I implemented a function calling a REST API. I defined my query, header, parameters.
I wasn't able to manage pagination with loadData() method. How can I achieve my second call to get the page 2 for example ? I tried the recursive way but it didn't work.
Here is an response example of HTTP GET request to REST API:
{
"data": [
{
...
}
],
"pageSize": 1000,
"currentPage": 1,
"lastPage": 3,
"totalObjectCount": 2789,
"truncated": false
}
The function I implemented :
readRestAPI: function (sQuery) {
var oDataModel = new JSONModel();
oDataModel.setSizeLimit(2000);
var oAuthModel = this.getOwnerComponent().getModel("AuthToken");
var oUserModel = this.getOwnerComponent().getModel("User");
var sCompanyName = oUserModel.getData().User[0].userCompanyName;
var sAccountName = oAuthModel.getData().accountName;
var sToken = oAuthModel.getData().token;
var iPage = 1;
var iPageSize = 1000; // Max object for one page in Query API is 1000
var mParams = {
"account": sAccountName,
"company": sCompanyName,
"query": sQuery,
"page": iPage,
"pageSize": iPageSize
};
var sURLQueryAPI = "/API/query/v1";
var sType = "GET";
var mHeaders = {
"Authorization": sToken,
"Content-Type": "application/json",
"X-Client-ID": sAccountName,
"X-Client-Version": "1.0.0"
};
return oDataModel.loadData(sURLQueryAPI, $.param(mParams, true), true, sType, false, true, mHeaders).then(
function (resData) {
return oDataModel;
});
}
Could you please explain me how can I handle the pagination ( 1 to 3 for instance )? Thanks
Related
I am using an internal service to Authenticate my Gsuite add-on. The Issue is we cannot find any request made from the Add-on to internal servers on Prod (or Dev environments). These are public facing authentication endpoints.
Currently this Addon only runs in Gmail. Unsure If there are any bandwidth limits we might be reaching but Google support said they couldn't help.
We followed the docs Google provides for 3rd Part Oauth.
auth File:
function accessProtectedResource(url, method_opt, headers_opt, body) {
var service = getOAuthService();
var maybeAuthorized = service.hasAccess();
if (maybeAuthorized) {
// A token is present, but it may be expired or invalid. Make a
// request and check the response code to be sure.
// Make the UrlFetch request and return the result.
var accessToken = service.getAccessToken();
var method = method_opt || 'get';
var headers = headers_opt || {};
headers['Authorization'] = Utilities.formatString('Bearer %s', accessToken);
var resp = UrlFetchApp.fetch(url, {
'headers': headers,
'method' : method,
'contentType': 'application/json',
'muteHttpExceptions': true, // Prevents thrown HTTP exceptions.
'payload': JSON.stringify(body)
});
var code = resp.getResponseCode();
if (code >= 200 && code < 300) {
return resp.getContentText('utf-8'); // Success
} else if (code >= 400 && code <= 403) {
// Not fully authorized for this action.
maybeAuthorized = false;
} else {
// Handle other response codes by logging them and throwing an exception.
Logger.log('Server error (%s): %s', code.toString(),
resp.getContentText('utf-8'));
throw ('Backend server error: ' + code);
}
}
if (!maybeAuthorized) {
// Invoke the authorization flow using the default authorization
// prompt card.
CardService.newAuthorizationException()
.setAuthorizationUrl(service.getAuthorizationUrl())
.setCustomUiCallback('createCompanyeAuthorizationUi')
.setResourceDisplayName('Company')
.throwException();
}
}
function getOAuthService() {
// added Console.log for debug
var service = OAuth2.createService('COMPANY_AUTH')
var servicewithurl = service.setAuthorizationBaseUrl(urlBase + '/oauth2/authenticate/');
var setauthBase = servicewithurl.setAuthorizationBaseUrl(urlBase + '/oauth2/authenticate/');
console.log('setauthBase ', setauthBase);
var setToken = setauthBase.setTokenUrl(urlBase + '/oauth/token/');
console.log('setToken ',setToken);
var setCallback = setToken.setCallbackFunction('authCallback');
console.log('setCallback ', setCallback);
setCallback.setClientId('2222TW9LzuT4AgAMN')
.setClientSecret('WZN5tyDKfMYoDLNnC')
.setPropertyStore(PropertiesService.getUserProperties());
.setCache(CacheService.getUserCache())
console.log('setCallback2 ', setCallback);
return setCallback;
}
function authCallback(callbackRequest) {
var authorized = getOAuthService().handleCallback(callbackRequest);
if (authorized) {
return HtmlService.createHtmlOutput(
'Success! <script>setTimeout(function() { top.window.close() }, 1);</script>');
} else {
return HtmlService.createHtmlOutput('Denied');
}
}
function createCompanyAuthorizationUi() {
var service = getOAuthService();
var authUrl = service.getAuthorizationUrl();
var authAction = CardService.newAuthorizationAction().setAuthorizationUrl(authUrl);
var CompanyLogo = CardService.newImage().setAltText("Company Logo").setImageUrl("image_url_replaced");
var headerText = 'Create actions in Company from your email.';
var mainImage = CardService.newImage().setAltText("Company Mail").setImageUrl("image_url_replaced");
var loginButton = CardService.newImage().setAltText("Login").setImageUrl("image_url_replaced").setAuthorizationAction(authAction);
var signupLink = CardService.newOpenLink()
.setUrl(urlBase + "/join")
.setOpenAs(CardService.OpenAs.FULL_SIZE)
.setOnClose(CardService.OnClose.NOTHING);
var signupButton = CardService.newImage().setAltText("Sign up").setImageUrl("image_url_replaced").setOpenLink(signupLink);
var featureOne = CardService.newKeyValue()
.setIconUrl("image_url_replaced")
.setContent("Company is the best way to plan, execute, and monitor all of your teams's projects in one place.")
.setMultiline(true);
var featureTwo = CardService.newKeyValue()
.setIconUrl("image_url_replaced")
.setContent("Content here")
.setMultiline(true);
var card = CardService.newCardBuilder()
.addSection(CardService.newCardSection()
.addWidget(CardService.newTextParagraph())
.addWidget(CompanyLogo)
.addWidget(CardService.newTextParagraph().setText(headerText))
.addWidget(mainImage)
.addWidget(signupButton)
.addWidget(loginButton)
.addWidget(featureOne)
.addWidget(featureTwo)
).build();
return [card];
}
function resetOAuth() {
getOAuthService().reset();
}
function getCompanyResourceUrls() {
accessProtectedResource(urlBase + '/api/v1/books/');
}
function makeRequest(url, params) {
var oauthService = getOAuthService();
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + oauthService.getAccessToken()
},
body: params
});
return response;
}
function getUserId() {
var cache = CacheService.getUserCache();
var userId = cache.get('userId');
if(userId) {
return userId;
}
var response = accessProtectedResource(urlBase + '/oauth/getIdentity');
var data = JSON.parse(response);
var userId = data.data.id;
cache.put('userId', userId);
return userId;
}
appsscript.json
{
"timeZone": "America/New_York",
"dependencies": {
"libraries": [{
"userSymbol": "OAuth2",
"libraryId": "",
"version": "37",
"developmentMode": true
}]
},
"webapp": {
"access": "ANYONE",
"executeAs": "USER_ACCESSING"
},
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/gmail.addons.current.message.readonly", "https://www.googleapis.com/auth/script.external_request"],
"urlFetchWhitelist": ["https://company.com/", "https://company.com/oauth/token/", "https://company.com/api/v1/books/", "https://companycom/oauth/revoke"],
"runtimeVersion": "V8",
"gmail": {
"name": "Name",
"logoUrl": "https://logourl.com",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildAddOn"
}],
"universalActions": [{
"text": "Logout",
"runFunction": "logout"
}],
"primaryColor": "#ffffff",
"secondaryColor": "#ffffff",
"authorizationCheckFunction": "getCompanyResourceUrls",
"openLinkUrlPrefixes": ["https://company.com/"]
}
}
You made mistake:
.setCustomUiCallback('createCompanyeAuthorizationUi')
but you have
createCompanyAuthorizationUi
I am not sure, but it can help you.
I'm new to JavaScript and REST, and I need to implement JSON as datasource to devextreme using knockout.js.
My problem is, that I can fetch the json, but it is not added to the datasource. I used console.log() for testing and noticed that the json is correctly loaded, but the datasource is empty (see comments in code below). How can I achieve the usage of my json as datasource?
Note: I used DevExtreme load JSON as datasource using knockout as base for getting my JSON-contents.
I have a sample JSON-File looking like this:
{
"ID":"3",
"content":
{
"ProdId":"000176491264",
"ProdDesc":"Sample 1",
"Type":"A",
}
}
And my current viewmodel looks like this:
MyApp.overview = function (params) {
"use strict";
var getData = function () {
var deferred = $.Deferred();
var xmlhttp = new XMLHttpRequest(), json;
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4 && xmlhttp.status === 200) {
json = JSON.parse(xmlhttp.responseText);
// prints needed content:
console.log(json.content);
deferred.resolve(json.content);
}
};
xmlhttp.open('GET', 'http://localhost:56253/test/3?format=json', true);
xmlhttp.send();
return deferred.promise();
};
var viewModel = {
overviewDatagridOptions: {
dataSource: getData(),
selection: {
mode: "single"
},
columns: [{
dataField: "ProdId",
caption: "ID"
}, {
dataField: "ProdDesc",
caption: "Description"
}, {
dataField: "Type",
caption: "Type"
}],
rowAlternationEnabled: true
},
// Returns {}
console.log("Datasource: " + JSON.stringify(viewModel.overviewDatagridOptions.dataSource));
return viewModel;
};
Edit: I changed my datasource to this:
dataSource: {
load: function (loadOptions) {
var d = new $.Deferred();
var params = {};
//Getting filter options
if (loadOptions.filter) {
params.filter = JSON.stringify(loadOptions.filter);
}
//Getting sort options
if (loadOptions.sort) {
params.sort = JSON.stringify(loadOptions.sort);
}
//Getting dataField option
if (loadOptions.dataField) {
params.dataField = loadOptions.dataField;
}
//If the select expression is specified
if (loadOptions.select) {
params.select= JSON.stringify(loadOptions.select);
}
//Getting group options
if (loadOptions.group) {
params.group = JSON.stringify(loadOptions.group);
}
//skip and take are used for paging
params.skip = loadOptions.skip; //A number of records that should be skipped
params.take = loadOptions.take; //A number of records that should be taken
var obj;
$.getJSON('http://localhost:56253/test/3?format=json', params).done(function (data) {
d.resolve(data);
});
//return obj;
return d.promise();
}, [...]
Based on the demo found here: https://www.devexpress.com/Support/Center/Question/Details/KA18955
Now, the output from the datasource is no longer empty, and looks like this:
Object
- load:(loadOptions)
- arguments:(...)
- caller:(...)
- length:1
- name:"load"
- prototype:Object
- __proto__:()
- [[FunctionLocation]]
- [[Scopes]]:Scopes[1]
- totalCount:(loadOptions)
- arguments:(...)
- caller:(...)
- length:1
- name:"totalCount"
- prototype:Object
- __proto__:()
- [[FunctionLocation]]
- [[Scopes]]:Scopes[1]
- __proto__:Object
I am using the ZingChart library to graph results from an API call. When I pass in a normal array for the "values" field of the chart data object, everything works fine. However, when I pass in an array made from Object.keys(titleSet) (where titleSet is a normal Javascript object), the graph displays as follows:
Example Chart
As you can see, the x-axis is now labeled with numbers instead of the array of strings. But when I print out the the result of Object.keys(titleSet) vs. passing in a normal array, they both appear to be the same in the console. Can anyone help me figure out what I'm doing wrong?
//List of movies inputted by the user
var movieList = [];
var movieSet = {};
var IMDBData = {
"values": [],
"text": "IMDB",
};
var metascoreData = {
"values": [],
"text": "Metascore"
};
var RTMData = {
"values": [],
"text": "Rotten Tomatoes Meter"
};
var RTUData = {
"values": [],
"text": "Rotten Tomatoes User"
};
var chartData = {
"type":"bar",
"legend":{
"adjust-layout": true
},
"plotarea": {
"adjust-layout":true
},
"plot":{
"stacked": true,
"border-radius": "1px",
"tooltip": {
"text": "Rated %v by %plot-text"
},
"animation":{
"effect":"11",
"method":"3",
"sequence":"ANIMATION_BY_PLOT_AND_NODE",
"speed":10
}
},
"scale-x": {
"label":{ /* Scale Title */
"text":"Movie Title",
},
"values": Object.keys(movieSet) /* Needs to be list of movie titles */
},
"scale-y": {
"label":{ /* Scale Title */
"text":"Total Score",
}
},
"series":[metascoreData, IMDBData, RTUData, RTMData]
};
var callback = function(data)
{
var resp = JSON.parse(data);
movieSet[resp.Title] = true;
//Render
zingchart.render({
id:'chartDiv',
data:chartData,
});
};
Full Disclosure, I'm a member of the ZingChart team.
Thank you for updating your question. The problem is you have defined your variable movieSet before the variablechartData. When parsing the page, top down, it is executing Object.keys({}) on an empty object when creating the variable chartData. You should just directly assign it into your config later on chartData['scale-x']['values'] = Object.keys(moviSet).
var callback = function(data)
{
var resp = JSON.parse(data);
movieSet[resp.Title] = true;
//Render
zingchart.render({
id:'chartDiv',
data:chartData,
});
};
There is a problem with the above code as well. It seems you are calling render on the chart every time you call this API. You should have one initial zingchart.render() and then from there on out use our API. I would suggest setdata method as it replaces a whole new JSON packet or modify method.
I am making some assumptions on how you are handling data. Regardless, check out the following demo
var movieValues = {};
var myConfig = {
type: "bar",
scaleX:{
values:[]
},
series : [
{
values : [35,42,67,89,25,34,67,85]
}
]
};
zingchart.render({
id : 'myChart',
data : myConfig,
height: 300,
width: '100%'
});
var callback = function(data) {
movieValues[data.title] = true;
myConfig.scaleX.values = Object.keys(movieValues);
zingchart.exec('myChart', 'setdata', {
data:myConfig
})
}
var index = 0;
var movieNamesFromDB = ['Sausage Party', 'Animal House', 'Hot Rod', 'Blazing Saddles'];
setInterval(function() {
if (index < 4) {
callback({title:movieNamesFromDB[index++]});
}
},1000)
<!DOCTYPE html>
<html>
<head>
<!--Assets will be injected here on compile. Use the assets button above-->
<script src= "https://cdn.zingchart.com/zingchart.min.js"></script>
<script> zingchart.MODULESDIR = "https://cdn.zingchart.com/modules/";
</script>
<!--Inject End-->
</head>
<body>
<div id='myChart'></div>
</body>
</html>
If you noticed in the demo, the length of scaleX.values determines how many nodes are shown on the graph. If you change values to labels this wont happen.
Having issues accessing data from my api once i have created a access token with a simple javascript client.
Here is my Js app object, as you can see i return a new access_token from my api - this works fine up to this point. I store the access_token into app.AccessToken for me to use in any other api calls i make throughout the app. But for some reason when i request anything the response is always the login page, so basically i am getting redirected when i try access anything even though i passing over a working in-date access_token.
var app = (function(){
/**
* Api
* #type Object
*/
var api = {
AccessToken : null,
views: {},
models: {},
collections: {},
content: null,
router: null,
documents: null,
init: function() {
this.content = $("#content");
this.documents = new api.collections.Documents();
Backbone.history.start();
return this;
},
changeContent: function(el) {
this.content.empty().append(el);
return this;
},
title: function(str) {
// set page title
}
};
/**
* ViewFactory
* #type Object
*/
var ViewFactory = {
documents: function() {
this.documentsView = new api.views.documents({
model: api.documents
});
return this.documentsView;
}
};
/**
* AppRouter
* #type Object
*/
var Router = Backbone.Router.extend({
routes: {
'' : 'documents'
},
documents: function() {
var view = ViewFactory.documents();
api.changeContent(view.$el);
view.render();
}
});
/**
* OAuth
* #type Object
* #return string
*/
var OAuth = {
title : 'Js Client',
clientId : 'NTUxNTY4YWE1NWUxMzI4',
username : 'john#globallcoach.com',
password : 'password',
init: function() {
var provision = OAuth.provision();
if(provision.hasOwnProperty('success')) {
var authenticate = OAuth.authenticate();
if(authenticate.hasOwnProperty('access_token')) {
api.AccessToken = authenticate['access_token'];
}
}
},
provision: function() {
var response;
$.ajax({
async: false,
url : 'http://customer-server-2.dev/oauth/provision/.json',
type : 'get',
data : {
title : OAuth.title,
client_id : OAuth.clientId
},
success:function(data) {
response = jQuery.parseJSON(data);
},
});
return response;
},
authenticate: function() {
var response;
$.ajax({
async: false,
url : 'http://customer-server-2.dev/oauth/token.json',
type : 'get',
data : {
'grant_type' : 'password',
'username' : OAuth.username,
'password' : OAuth.password,
'client_id' : OAuth.clientId,
},
success:function(data) {
response = data;
}
});
return response;
},
}
/**
* Exercute & return
*/
api.router = new Router();
OAuth.init();
return api;
})();
Solved! I needed to make sure that on the Rest AppController i needed to defined $this->Auth->allow() on the actions within the api scope.
I was very excited to see a calendar plugin like fullcalendar. I am trying to use fullcalendar to display events for each month. But the events are not displayed on the calendar.
My code is :
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult HighlightCalendar()
{
var tasksList = new List<HighlightMonthlyEvents>();
tasksList.Add(new HighlightMonthlyEvents
{
id = 1,
EventName = "Google search",
EventStartDate = ToUnixTimespan(DateTime.Now),
EventEndDate = ToUnixTimespan(DateTime.Now.AddHours(4)),
url = "www.google.com"
});
tasksList.Add(new HighlightMonthlyEvents
{
id = 1,
EventName = "Bing search",
EventStartDate = ToUnixTimespan(DateTime.Now.AddDays(1)),
EventEndDate = ToUnixTimespan(DateTime.Now.AddDays(1).AddHours(4)),
url = "www.bing.com"
});
var highlightDays = Jayrock.Json.Conversion.JsonConvert.ExportToString(tasksList.ToArray());
return Json(highlightDays, JsonRequestBehavior.AllowGet);
}
<script type="text/javascript">
$(function () {
// FullCalendar
$('.fullcalendar').fullCalendar({
theme: true,
header: {
left: 'today prev,next',
center: '',
right: ''
},
defaultView: 'month',
editable: false,
events: function (callback) {
// do some asynchronous ajax
contentType: "application/json; charset=utf-8",
$.getJSON("/Test/HighlightCalendar/", null,
function (result) {
var calevents = new Array();
var results = eval(result);
eval(results.length);
if (results != null) {
for (i in results) {
var calEvent = results[i];
calevents.push(calEvent)
}
}
alert(calevents.length);
// then, pass the CalEvent array to the callback
callback(calevents);
});
}
});
And as for my JSON, it looks like:
[{"id":1,"allDay":false,"title":"Google search","start":1279750267,"end":1279764667,"url":"www.google.com"},{"id":2,"allDay":false,"title":"Bing search","start":1279836667,"end":1279851067,"url":"www.bing.com"}]
What do you think about what is wrong?
This might probably has to do with quotes around your property and values.
Try to include quotes in both property and value and check your result.
I achieved the same without using JSON.js like this.
System.Web.Script.Serialization.JavaScriptSerializer eventListSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string eventListJSON = eventListSerializer.Serialize(addevList);