SAPUI5 - oDataService is called multiple times - request

We have an oDataService that receives a deep entity and with this information it creates a sales order in the SAP backend.
Now the oDataService works fine but sometimes we have a strange behavior: The oDataService is called two times of the same request. The result is, when i want to create a sales order, it creates two identical sales orders with different order id's. The creation time of the orders have a difference of 4 seconds, so it happens in a very short time period.
So my question is: When I call an oDataService once, why does it call the services two times?
I have also build security mechanism in the Fiori app and also in the SAP Backend to prevent the user to send multiple request within a minute. But it does not matter because i belive that the request is not send multiple times by the user. It seems that this happens automatically.
Btw. this also happens when we want to debug an incoming request from the Fiori app, in the SAP backend ABAP code. While we debug another window pops up with the starting breakpoint.
Here is my code where i call the request:
getServiceModel: function (serviceName, oDefaultUpdateMethod) {
var oModel = new ODataModel(this.sBaseUrl + serviceName + "/", {
serviceUrlParams: {
"sap-client": this.sClient
},
defaultUpdateMethod: oDefaultUpdateMethod
? oDefaultUpdateMethod
: sap.ui.model.odata.UpdateMethod.Put
});
oModel.setDefaultCountMode(sap.ui.model.odata.CountMode.None);
return oModel;
}
execCreateRequest: function (serviceName, entitySet, entity) {
if (this.bDevMode) {
return this.oDataDev.execCUDRequest(
this.sBaseUrl + serviceName + "/",
"POST",
entitySet.replace("/", ""),
entity
);
}
return new Promise(
function (resolve, reject) {
var oModel = this.getServiceModel(serviceName);
oModel.attachMetadataFailed(
function (oError) {
reject(oError);
}.bind(this)
);
oModel.attachRequestFailed(
function (oError) {
reject(oError);
}.bind(this)
);
oModel.create(entitySet, entity, {
success: function (response) {
resolve(response);
}.bind(this),
error: function (oError) {
reject(oError);
}.bind(this)
});
}.bind(this)
);
},
Any help is appreciated, thank you

Related

React APP makes a ton of API Calls and crashes

I am making a simple app that makes an api request to my local server and gets some data and puts it on a chart from trading view. This should be pretty simple as everything is just for practice, but when I change some of the values on my server and make the call, the app keeps making the call like 35 times before the server crashes and then the app just says
"net::ERR_CONNECTION_REFUSED"
and doesn't display the data as it should.
This is the whole code, it has two parts. One parts makes the call to get example data of name and another call to get example data that will go to the chart (the second part is the issue.)
This is the code just for the second part:
getBars: async (
symbolInfo,
resolution,
periodParams,
onHistoryCallback,
onErrorCallback
) => {
try {
if (resolution === '1D') {
resolution = 1440;
}
const response2 = await axios.get('http://localhost:8000/chart');
console.log('got bars data');
const bars = response2.data.map((el) => ({
time: new Date(el.timeInterval.minute).getTime(), // date string in api response
low: el.low,
high: el.high,
open: Number(el.open),
close: Number(el.close),
volume: el.volume,
}));
if (bars.length) {
onHistoryCallback(bars, { noData: false });
} else {
onHistoryCallback(bars, { noData: true });
}
console.log('bars done');
} catch (err) {
console.log({ err });
}
};
So what happens is that the console.log "got bars data" and "bars done" repeats many times until my localhost:8000 server crashes and then the app gives the error I showed above, because of this it doesn't display the data. I have no Idea why this may be happening,
This is what the data looks like for the one that does not works:
{"timeInterval":{"minute":"2022-03-14T23:45:00Z"},"volume":0.05,"high":3.910209183178435e-9,"low":3.910209183178435e-9,"open":"3.910209183178435e-09","close":"3.910209183178435e-09"}
This is for the one that works:
{"timeInterval":{"minute":"2022-03-17T15:00:00Z"},"volume":0.05,"high":0.00001255389794727055,"low":0.00001255389794727055,"open":"1.255389794727055e-05","close":"1.255389794727055e-05"}
I would appreciate any help, thanks!
EDIT
I just noticed, with the data set that works, console.log('got bars data') and console.log('bars done') don't occur for some reason, but the data still shows up on the chart even though the console doesn't log.

How to call the same api multiple times in Express Route?

I'm working on a Node app with Express. I'm chaining several http calls to data api's, each dependent on the previous req's responses.
It's all working except the last call. The last call needs to happen multiple times before the page should render.
Searching has turned up excellent examples of how to chain, but not make a call to the same API (or HTTP GET, data endpoint, etc.) with different params each time.
I'm trying to do something like this: Using a generator to call an API multiple times and only resolve when all requests are finished?
var getJSON = (options, fn) => {
.....
}
router.route("/")
.get((req, res) => {
var idArray = [];
var results = [];
getJSON({
.... send params here, (result) => {
//add response to results array
results.push(result);
//create var for data nodes containing needed id params for next call
let group = result.groupsList;
//get id key from each group, save to idArray
for(i=0;i<groups.length;i++){
idArray.push(groups[I].groupId);
}
//use id keys for params of next api call
dataCallback(idArray);
});
function dataCallback(myArray){
// number of ID's in myArray determine how many times this API call must be made
myArray.forEach(element => {
getJSON({
.... send params here, (result) => {
results.push(result);
});
// put render in callback so it will render when resolved
}, myRender());
};
function myRender() {
res.render("index", { data: results, section: 'home'});
}
})
I learned the problem with the above code.
You can call functions that are outside of the express route, but you can't have them inside the route.
You can't chain multiple data-dependent calls, not in the route.
Anything inside route.get or route.post should be about the data, paths, renders, etc.
This means either using an async library (which I found useless when trying to build a page from multiple data sources, with data dependent on the previous response), or having an additional js file that you call (from your web page) to get, handle and model your data like here: Using a generator to call an API multiple times and only resolve when all requests are finished You could also potentially put it in your app or index file, before the routes.
(It wasn't obvious to me where that code would go, at first. I tried putting it inside my router.post. Even though the documentation says "Methods", it didn't click for me that routes were methods. I hadn't really done more than very basic routes before, and never looked under the hood.)
I ended up going with a third option. I broke up the various API calls in my screen so that they are only called when the user clicks on something that will need more data, like an accordion or tab switch.
I used an XMLHttpRequest() from my web page to call my own front-end Node server, which then calls the third party API, then the front-end Node server responds with a render of my pug file using the data the API provided. I get html back for my screen to append.
In page:
callFEroutetoapi(_postdata, _route, function (_newdata){
putData(_newdata);
});
function putData(tData){
var _html = tData;
var _target = document.getElementById('c-playersTab');
applyHTML(_target, _html);
}
function callFEroutetoapi(data, path, fn){
//url is express route
var url = path;
var xhr = new XMLHttpRequest();
console.log('data coming into xhr request: ', data);
//xhr methods must be in this strange order or they don't run
xhr.onload = function(oEvent) {
if(xhr.readyState === xhr.DONE) {
//if success then send to callback function
if(xhr.status === 200) {
fn(xhr.response);
// ]console.log('server responded: ', xhr.response);
}
else {
console.log("Something Died");
console.log('xhr status: ', xhr.status);
}
}
}
xhr.onerror = function (){console.log('There was an error.', xhr.status);}
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(JSON.stringify(data));
}
It adds an extra layer, but was necessary to show the latest, frequently changing data. It's also reusable which is better for a multiscreen web app. If there were fewer views (completely different screens and co-dependent datasets), a more centralized model.js file mentioned above would work better.

kinvey fetching and remove not working (AngularJS)

I have this problem with kinvey backend,
I'm trying to fetch data from my collection but it doesn't work for me. here is my code :
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
Can you help me please
If you let run the code you have posted then consider four things:
Make sure you have Kinvey implemented:
<script src="https://da189i1jfloii.cloudfront.net/js/kinvey-html5-sdk-3.10.2.min.js"></script>
Make sure you have initialized the Kinvey service before:
// Values shown in your Kinvey console
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
Make sure you are logged in with a user that has the rights to read your collection (should be fine using the All Users role (default)):
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
})
.catch(function(error) {
console.log (error);
});
Output the return result to see whats coming back. To make sure you do the query AFTER successful login, paste you query inside the .then function of login.
I'm not sure if your query is valid unter 3.x since a lot has changed and I'm not working with older Kinvey versions.
So that all together would look like this:
// Initialize Kinvey
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
// Login with already registered user
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
// Your query
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// Output of returning result
console.log (entity);
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
})
.catch(function(error) {
console.log (error);
});
There are now three return sets possible:
Nothing (as you say) -> Something missing/wrong in the code (compare yours with mine)
Empty array: Your query didn't find anything, adapt the search value(s)
One or more entries in the array -> All fine, what you were looking for!
Hope that helps!
When querying by _id there is a built in method: http://devcenter.kinvey.com/angular/guides/datastore#FetchingbyId
Try switching to var stream = dataStore.findById('entity-id');
Also check to make sure you don't have any preFetch or postFetch BL that is interfering with the query.

React and Meteor Subscription

I am not sure if this is a limitation to React and Meteors connection as documentation suggests that it should be possible without the extra parameter.
When I call a meteor subscription in react if I do not explicitly state the parameter in the query it returns any data, ignoring the specified data in the publish function.
Meteor.publish("supplier", function() {
if(this.userId) {
var user = Meteor.users.findOne(this.userId, { fields : { active : 1 }});
if(user.active != this.userId || user.active != undefined){
// This only returns 1 singular supplier - is correct
var supplier = Supplier.find({ _id : user.active, users : this.userId });
return supplier;
} else {
return this.ready();
}
} else {
return this.ready();
}
});
Now I call the subscription in react as so
getMeteorData: function () {
var data = {}
handle = Meteor.subscribe("supplier");
if(handle.ready()) {
data.supplier = Supplier.findOne(); // Returns Wrong supplier
//data.supplier = Supplier.findOne({_id: session.get("active")}) // Returns correct supplier
data.supplierReady = true
}
return data;
},
This returns the first supplier in the collection not the one logged in the publish function on the server! However if I explicably pass { _id : user.active} it works!
Now it was my understanding that by doing the logic on the server within the publish function that I could simply use Supplier.findOne() but this is not the case and I don't understand why. Is this a limitation on React/Meteor or am I implementing this wrong?
This isn't a React-specific issue, it's a result of the way findOne works. If you have one or more documents in your client side Supplier collection, Supplier.findOne() will just grab the first record available without reference to the document(s) you just fetched from your subscription.
This means either (a) you have more than one supplier available on the client side due to other preexisting subscriptions, or (b) you are returning more than one supplier from the handle subscription.
Check the state of the client side collection prior to the handle subscription. If there's 1 or more docs and that is the intended state of your application, then modify the client side findOne to add {_id: user.active} as you have before.

Saving and Getting Data / Rows to and from PouchDB

i am very new to pouchdb, meaning i have not yet been successfully able to implement an app that uses it.
This is my issue now, in my controller i have two functions:
var init = function() {
vm.getInvoicesRemote(); // Get Data from server and update pouchDB
vm.getInvoicesLocal(); // Get Data from pouchDB and load in view
}
init();
Basically in my app i have a view that shows customer invoices, now i want customers to be able to still see those invoices when they're offline. I have seen several examples of pouchdb and couchdb but all use the "todo" example which does not really give much information.
Now i'm just confused about what the point was in me spending hours understanding couchdb and installing it if in the end i'm just going to be retrieving the data from my server using my API.
Also when the data is returned how does pouchdb identify which records are new and which records are old when appending.
well, i m working on same kind..!this is how i m making it work..!
$scope.Lists = function () {
if(!$rootScope.connectionFlag){
OfflineService.getLocalOrdersList(function (localList) {
if(localList.length > 0) {
$scope.List = localList;
}
});
}else{
if(!$scope.user){
}else {
Common.callAPI("post", '***/*************', $scope.listParams, function (data) {
if (data !== null) {
$scope.List = data.result;
OfflineService.bulkOrdersAdd_updateLocalDB($scope.List);
}
});
}
}
};
so,$scope.List will be filled if online as well as offline based on connectionFlag
note : OfflineService and Common are services.
call method:
$ionicPlatform.ready(function () {
OfflineService.configDbsCallback(function(res) {
if(res) {
$scope.Lists();
}
});
});
u can try calling $scope.Lists(); directly..!
hope this helps u..!

Resources