Chaining the $http.get AngularJS - javascript

As I am making few call to the endpoints within a function and it was causing issue with the parallel calls to the endpoints, so it was suggested in the other question to use the promise chaining. I updated my code so we can call the endpoints one after the other, so the code looks like below
$scope.getRequest = function () {
var url = $rootScope.BaseURL;
var config = {
headers: {
'Authorization': `Basic ${$scope.key}`,
'Prefer': 'odata.maxpagesize=2000'
}
};
$http.get(url, config)
.then(newViewRequest)
.then(function(response){
$scope.viewRequest.data = response.data;
},
function (response) { // failure async
console.log("There was an error getting the request from CORE");});
};
var newViewRequest = function (response) {
var url1 = $rootScope.BaseURL + `CMQ_REQUEST('${$scope.viewRequest.barcode}')`;
if (response.data.REV_SAMPLE_CMQREQUEST.length = 0) {
return $http.get(url1, config)
}
return $q.reject({ message: 'Validations didnt work' });
};
It always sends the reject message back from the newViewRequest if response.data.REV_SAMPLE_CMQREQUEST.length = 0, if I comment it out I get the response.data is undefined.

Update your condition to validate instead of assigning
Issue: Update if condition as below to check response.data.REV_SAMPLE_CMQREQUEST.length whether it is 0 or not with === instead of =
if (response.data.REV_SAMPLE_CMQREQUEST.length === 0)

Related

Axios - multiple requests for the same resource

I'm creating an app where in one page, I have two components requesting the same http resource. In this case I'm using axios and here's one example:
axios.get('/api/shift/type')
.then(
(response) => {
self.shiftTypes = response.data;
success(response.data)
},
(response) => {
error(response)
}
);
The issue lies in them requesting it almost at the same time. If Component A makes the request at the same time as Component B, 2 request calls are made and they'll get the same data. Is there a way to check if axios currently has an unresolved promise and return the result to both components once the request is resolved?
Not sure if it helps but the app is being built using the vue framework
Thanks
EDIT: I tried storing the promise in memory but Component B never gets the response
getShiftTypes(success, error = this.handleError, force = false) {
if (this.shiftTypes && !force) {
return Promise.resolve(this.shiftTypes);
}
if (this.getShiftTypesPromise instanceof Promise && !force) { return this.getShiftTypesPromise; }
let self = this;
this.getShiftTypesPromise = axios.get('/api/shift/type')
.then(
(response) => {
self.shiftTypes = response.data;
self.getShiftTypesPromise = null;
success(response.data)
},
(response) => {
error(response)
}
);
return this.getShiftTypesPromise;
}
Consider using a cache:
let types = { lastFetchedMs: 0, data: [] }
async function getTypes() {
const now = Date.now();
// If the cache is more than 10 seconds old
if(types.lastFetchedMs <= now - 10000) {
types.lastFetchedMs = now;
types.data = await axios.get('/api/shift/type');
}
return types.data;
}
while(types.data.length === 0) {
await getTypes();
}

How can I run this function synchronously in node.js [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I want to run the function synchronously. In my application
the supply source needs to be created before it is assigned to the other data.
And the application should only further if this task was fulfilled.
Because otherwise it will fail because the other data is created and no SupplySourceId is found (undefinded).
here i want to start the synchronous function (processSupplySource();)
var articleSupplySourceId = processSupplySource();
Function ProcessSupplySource:
function processSupplySource(){
var postJson2 = {};
postJson2.articleNumber = entry['part-no'];
postJson2.name = entry['part-no'];
postJson2.taxName = 'Vorsteuer';
postJson2.unitName = 'stk';
postJson2.supplierNumber = "1002";
postJson2.articlePrices = [];
var articlePrices = {};
articlePrices.currencyName = 'GBP';
articlePrices.price = entry['ek-preisgbp'];
articlePrices.priceScaleType = 'SCALE_FROM';
articlePrices.priceScaleValue = '1';
postJson2.articlePrices.push(articlePrices);
return postSupplySource(postJson2);
Function PostSupplySource
function postSupplySource(postJson2) {
rp({
method: 'POST',
url: url + '/webapp/api/v1/articleSupplySource',
auth: {
user: '*',
password: pwd
},
body: postJson2,
json: true
}).then(function (parsedBody) {
console.log('FinishArticleSupplySource');
var r1 = JSON.parse(parsedBody);
console.log(r1.id);
return r1.id;
})
.catch(function (err) {
console.log('errArticleSupplySource');
console.log(err.error);
// POST failed...
});
}
You can use async/await if you are using node 8 to get that synchronous behaviour you looking for.
Otherwise, you will need to use a library like deasync to wait for the post to complete and return the id.
You can wrap your postSupplySource function in a promise and call the other function when it resolves. This will ensure you have `sourceSupplyId' by the time you run the other functions. Except in case of an error. Something like this:
function postSupplySource(postJson2) {
return new Promise(resolve, reject){ //**added
rp({
method: 'POST',
url: url + '/webapp/api/v1/articleSupplySource',
auth: {
user: '*',
password: pwd
},
body: postJson2,
json: true
}).then(function (parsedBody) {
console.log('FinishArticleSupplySource');
var r1 = JSON.parse(parsedBody);
console.log(r1.id);
resolve(r1.id); // ** added
})
.catch(function (err) {
console.log('errArticleSupplySource');
console.log(err.error);
return reject(err); //*** added
// POST failed...
});
});
}
And then you can call the other function inside it like this:
postSupplySource(postJson2)
.then((supplySourceId) => {
// supplySourceId is available.
// you can call other functions here.
}).catch((err) => {
console.log(err);
});
Hope I got your question right.
As someone mentioned also, you can use asyc await.
As

Why does fetch return a weird hash of integers?

I'm using fetch API with React Native.
My response follows a normal format of {"message": "error here"} if the status is >= 400, which I will show in a native popup.
I'm trying to call response.json() after detecting a failure, but it keeps putting everything in a weird format...
{ _45: 0, _81: 0, _65: null, _54: null }
For whatever reason... the actual response I want is located in _65... I have no idea what these random keys are.
So currently I'm having to access it via _bodyText, but I assume that is wrong because it's a private underscore method.
What am I doing wrong?
var API = (function() {
var base = 'https://example.com/api/v1';
var defaults = {
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
};
var alertFailure = function(response) {
if (response.status >= 200 && response.status < 400) {
return response;
} else {
var json = JSON.parse(response._bodyText || '{}');
var message = json.message || 'There was a problem. Close the app, and try again later.';
var error = new Error(message);
error.response = response;
throw error;
}
};
var callAPI = function(url, opts) {
opts.headers['X-Version'] = 'v' + Package.version;
return fetch(base + url, opts)
.then(alertFailure)
.then((response) => {
return response.json();
})
.catch((error) => {
Alert.alert(null, error.message);
});
};
return {
get: function(url, opts) {
var fullOpts = Object.assign({}, defaults, opts);
return callAPI(url, fullOpts);
},
post: function(url, data, opts) {
var fullOpts = Object.assign({}, defaults, {
method: 'POST',
body: JSON.stringify(data || {})
}, opts);
return callAPI(url, fullOpts);
}
};
})();
The answer is that .json() returns a promise... so I had to do everything from within .then()
AsyncStorage.getItems always returns a promise. You can use this method below
AsyncStorage.getItem("access_key").then((value)=>
{
console.log(value);
});
I would recommend you to use the new ES7 syntax async/await, they are easier to understand than using .then()
To use it, just declare some method with the async prefix and inside of it use await to wait for the call to finish.
E.g
async someMethod(){
result = await fetch(URL); // Do some request to any API.
// Use the result after that knowing that you'll have it completed.
}
I hope this helps, at least in my opinion, I find this easier than using .then(), especially when you have to do multiple calls within the same method.

Parse.com and closures

I have a Cloud Code function that will execute n times the same block. The block consist in an http call with auth header. to make things simple, I have created a function at the root of my main.js. The function needs to return a result and keep in memory the authData (in order to reuse it for future calls).
function requestURI (uri){
var authData; // gets generated if null, should be reused if not null
var result; // supposingly contains the results
return something();
}
The function something() is a Parse.Promise because I need my calls to be asynchronous. As I understand I can't attach the result nor the authData to my promise.... If I run a console.log() within the function requestURI(), I see authData and result correctly populated as expected
Then I want this function from a Parse function. (the whole purpose is to have the function being re-usable by any other)
Parse.Cloud.define("testCall", function(request, response) {
var uri1 = '...';
var uri2 = '...';
var uri3 = '...';
return requestURI(uri1).then(function(){
// how do I get the result of my request?
return request(uri2);
}).then(function(){
// how do I get the result of my request?
return request(uri3);
});
}
The problem I have is that I can't retrieve my result out of the requestURI function and it seems that authData is reset everytime I run the function
I read the solution lies in closures but I can't get my head around them...
edit: add the function something():
return Parse.Cloud.httpRequest({
method: 'GET',
url: url,
headers: {
"Authorization" : digestAuthHeader
},
success: function(httpResponse) {
// all went well, let's increase the nonceCount, for future calls
authData["nc"] += 1;
// I need to return the result object in a promise
result = httpResponse.data;
// return a Promise that can be handled by any function
return Parse.Promise.as(result)); // this promise doesn't work
},
error: function(httpResponse) {
console.error('Request failed with response code ' + httpResponse.status);
return (null,Parse.Promise.error(httpResponse.text));
}
});
edit: here is what I'm trying
// authData is not null, we can make an authenticated call
function makeAuthenticatedRequest(){
// generate the appropriate auth Header;
var digestAuthHeader = generateDigestAuthHeader();
return Parse.Cloud.httpRequest({
method: 'GET',
url: url,
headers: {
"Authorization" : digestAuthHeader
}}).then(function(httpResponse) {
// all went well, let's increase the nonceCount, for future calls
authData["nc"] += 1;
// create the final object to return in a promise
result = httpResponse.data;
console.log(result) // returns something not null!!!
// return a Promise that can be handled by any function
return promise.resolve({'authData': authData, 'result': result});
},
function(error) {
console.error('Request failed with response code ' + error.status);
return (null,Parse.Promise.error(error));
});
}
Parse.Cloud.define("testCall", function(request, response) {
var uri1 = '...';
var authData;
return apiCall1001Menus(authData,uri1).then(function(result){
response.success(result); // returns {}
});
});
my response callback is {}!!! which is not what I would expect at all
I will give you an example to prevent my bad english cause misleading.
The following rewrite function makeAuthenticatedRequest() in callback deferred antipattern and promise fashion.
Callback:
Deferred antipattern:
function makeAuthenticatedRequest(){
// generate the appropriate auth Header;
var digestAuthHeader = generateDigestAuthHeader();
var promise = new Parse.promise();
Parse.Cloud.httpRequest({
method: 'GET',
url: url,
headers: {
"Authorization" : digestAuthHeader
},
success: function(httpResponse) {
// all went well, let's increase the nonceCount, for future calls
authData["nc"] += 1;
// create the final object to return in a promise
result = httpResponse.data;
console.log(result) // returns something not null!!!
// return a Promise that can be handled by any function
promise.resolve({'authData': authData, 'result': result});
},
error: function(error) {
console.error('Request failed with response code ' + error.status);
// it could be promise.resolve (success) or promise.reject (error)
promise.reject(error);
}
});
return promise;
}
Promise:
function makeAuthenticatedRequest(){
// generate the appropriate auth Header;
var digestAuthHeader = generateDigestAuthHeader();
return Parse.Cloud.httpRequest({
method: 'GET',
url: url,
headers: {
"Authorization" : digestAuthHeader
}
}).then(function(httpResponse) {
// all went well, let's increase the nonceCount, for future calls
authData["nc"] += 1;
// create the final object to return in a promise
result = httpResponse.data;
console.log(result) // returns something not null!!!
// return a Promise that can be handled by any function
return {'authData': authData, 'result': result};
}, function(error) {
console.error('Request failed with response code ' + error.status);
return Parse.Promise.error(error);
});
}

Using the $q implementation in Angular how can I loop a promise until success?

As per my other recent questions, I'm trying to persist data to a server for an angular application that's targeted at mobile devices (unstable connections), so it should keep trying the request until success.
How can I do this with promises?
At the moment I've got:
Service:
this.addObject = function addObject(object) {
var deferred = $q.defer();
var httpConfig = {
method: 'POST',
url: 'http://api.foo.com/bar',
data: object
}
setTimeout(function() {
$http(httpConfig).
success(function(data, status) {
deferred.resolve('Woohoo!');
}).
error(function(data, status) {
deferred.reject('Couldnt reach server this time...');
});
}, 3000);
return deferred.promise;
}
Controller:
myService.addObject(myObject)
.then(function(message) {
console.log(message);
}, function(message) {
console.log(message);
});
I can't remove the reject callback, as the code won't seem to execute without it, but once the reject is called, it breaks the setTimeout loop. How can I force the promise to repeat until the success callback?
This is the proper form of the answer at AngularJS service retry when promise is rejected
this.addObject = function addObject(object) {
var counter = 0;
var deferred = $q.defer();
var httpConfig = {
method: 'POST',
url: 'http://api.foo.com/bar',
data: object
}
var doRequest = function() {
counter++;
var self = this,args = arguments;
$http(httpConfig).
success(function(data, status) {
deferred.resolve('Woohoo!');
}).
error(function(data, status) {
//just fail already, it's not working
if(counter > 5) {
return deferred.reject('Couldnt reach server this time...');
}
//this will re-call doRequest();
args.callee.apply(self);
});
}
doRequest();
return deferred.promise;
}
As you're doing with with $http, http interceptors can do this. If you want a http request to infinitely loop until it returns a success:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('RetryInterceptor');
}]);
app.factory('RetryInterceptor', function($timeout, $injector) {
return {
'responseError': function(rejection) {
// Manual inject to work around circular dependency issue
var $http = $injector.get('$http');
return $timeout(function() {
return $http(rejection.config);
},3000);
}
}
});
This works due to how the initial call to $http won't resolve until (in this case) all the responseError interceptors have been resolved.
You can see this in action at http://plnkr.co/edit/QAa9oIK4lTM6YwccEed3?p=preview (looking in the console log there is a failed request every 3 seconds.)
Note: there might need to be more logic to make sure it only retries on the right sort of error. i.e. it's not a real 404 where in fact the browser is to blame, for example.
it should keep trying the request until success. How can I do this with promises?
By "recursively" calling the function again in the error handler so that you're resolving the promise with the result of the next try.
this.addObject = function addObject(object) {
var httpConfig = {
method: 'POST',
url: 'http://api.foo.com/bar',
data: object
}
return $http(httpConfig).then(function(data, status) {
return 'Woohoo!';
}, function(data, status) {
throw 'Couldnt reach server this time...';
});
}
this.addObjectForever = function addObject(object) {
var that = this;
return this.addObject(object).then(null, function(err) {
console.log("Failed this time");
return $timeout(3000).then(function() {
console.log("Trying again now");
return that.addObjectForever(object);
});
});
};
instance.addObjectForever(obj).done(function() {
console.log("It eventually worked");
});
quite crowded here :)
my solution:
angular.module('app', [])
.service('Service',function($q,$http) {
this.addObject = function(object) {
var httpConfig = {
method: 'POST',
url: 'http://api.foo.com/bar',
data: object
}
var deferred = $q.defer();
$http(httpConfig)
.success(function(data, status) {
deferred.resolve('Woohoo!');
})
.error(function(data, status) {
deferred.reject('Couldnt reach server this time...');
});
return deferred.promise;
};
})
.controller('MainCtrl',function($scope,$interval,Service){
/*Service.addObject({})
.then(function(message) {
console.log(message);
}, function(message) {
console.log(message);
});*/
$interval(function(){
Service.addObject().then(function(message) {
console.log(message);
}, function(message) {
console.log(message);
});
},1000);
})
Uhm. Even though there are HTTP interceptors for this particular case, one of the advantages of working with promises instead of callback is that you can use higher order functions.
// both p and q are functions that create a promise
p = makeSomePromise(options)
q = repeat(10, p)
That is, for instance, a function that takes a promise making function and produces a new promise making function that retries the other promise repeatedly, until a max.
For example: (This is for nodeJS using kew, but you should get the point)
var Q = require('kew');
function retryPromise(n, mkPromise) {
if(n > 0)
return mkPromise()
.fail(function(){
console.log('failed promise, retrying maximum ' + n + ' more times');
return retryPromise(n - 1, mkPromise);
});
return mkPromise();
}
(function(){
var mkOp = function(){
if(Math.random() > .1)
return Q
.fcall(function(){return 1;})
.then(function(){throw Error('aah');});
return Q.fcall(function(){return 'yay'});
};
retryPromise(10, mkOp)
.then(function(data){
console.log(data);
})
.fail(function(err){
console.log('failed', err);
});
}());

Categories

Resources