Using axios for post request and fetching response - reactjs

fetching data from axios response return undefined value when console.logged
I have tried numerous way but the response is always shows undefined
This is the usersdata
const userdatas=[ {id: 1,firstname: "Leanne",lastname:"Gram",password: "123",phone:"9474211442"}**
Client
handleSubmit=(e)=>{
alert(this.state.Firstname)
e.preventDefault();
axios.post('http://localhost:3001/login', {
lastname: JSON.stringify(this.state.Lastname),
firstname: JSON.stringify(this.state.Firstname),
password:JSON.stringify(this.state.password),
phoneno:JSON.stringify(this.state.phoneno)
}).then(res=>alert(res.data.id))
}
]
Express
const userdatas=[ {id: 1,firstname: "Leanne",lastname:"Gram",password: "123",phone:"9474211442"}**
app.post('/login',(req,res)=>{
let logindetail={firstname:req.body.firstname,
password:req.body.password}
logindetail.firstname=logindetail.firstname.replace(/['"]+/g, '')
logindetail.password=logindetail.password.replace(/['"]+/g, '')
var count = Object.keys(userdatas).length;
for(var i=0;i<count;i++)
{
if(logindetail.firstname===userdatas[i].firstname&&logindetail.password===userdatas[i].password)
{
res.json(userdatas[i])
}
}
});

In your Express section, userdatas appears to be an object, but you are trying to look it up like an array in your res.json call. You need to wrap it in Object.keys like you have when you are setting your count value.

Seeing as what you receive on the backend doesn’t appear to be right , I’d revisit the frontend request. IMHO, you ought to only have one JSON.stringify call against the whole object you want to wrap, not a separate call per prop. Try that and then see what the backend receives.

First the userdatas is an object and you are trying to access its values as in an array. Secondly are you sure that the if condition inside the loop gets satisfied once?. Because you can't have multiple responses to a single request. Build a single response body in a variable as you loop. Send it once the loop is finished.
for (var i = 0; i < count; i++) {
if (
logindetail.firstname === userdatas[i].firstname &&
logindetail.password === userdatas[i].password
) {
res.json(userdatas[i]);
}
}
Change it to something like this
let result = [];
for (var i = 0; i < count; i++) {
if (***your corrected condition***) {
result = userdatas[i];
}
}
res.send(result);

Related

Typescript - subscription inside iteration

I am trying to call the "getData" API over and over for each value in the "myArray" variable. Each time it gets new data from the "getData" call, I am trying to push the result to an array so I can manipulate the values in the "destinationArray" section of code. However, since typescript is not async, it gets to the "destinationArray" code before it's finished in the .subscribe / before it's finished iterating.
I've already tried fixing this with await waitUntil(() => done==true, { timeout: 10015 });
but I keep getting randomly appearing messages in the console saying ERROR Error: Uncaught (in promise): Error: Timed out after waiting for 10015 ms. The naive answer is to just increase the timeout to infinity, but the actual API call itself does not take 10 seconds, it takes about 1 second (if even that long). How can I make it wait until it's finished iterating / subscribing before it moves onto the "destionationArray" section at the bottom, without seeing that timeout error message in the console?
let dataFromAPIcall: any[] = []
let myArray: any[] = ["hello","world"]
for(let i = 0; i< myArray.length; i++) {
this.GetDataSubScription = this.myService.getData(myArray[i]).pipe( takeUntil(this.ngUnsubscribe) ).subscribe(data => {
dataFromAPIcall.push(data)
if(i+1 == myArray.length) {
done = true
}
});
}
await waitUntil(() => done==true, { timeout: 10015 });
let destinationArray: any[] = [];
for(let i = 0; i < dataFromAPIcall.length; i++) {
destinationArray[i] = [dataFromAPIcall[i].something1, dataFromAPIcall[i].something2]
}
You can zip your api calls and handle all responses in a reactive way, without using imperative state variables:
After all observables emit, emit values as an array
// creating an array of observables. The requests are not fired yet.
const requests = myArray.map(i => this.myService.getData(i));
const destinationArray: any[] = [];
// passing the request array to the zip function.
// this will actual initiate the requests and emit when ALL
// requests are done
zip(...requests).pipe(
tap(responses => {
// maping responses to destinationArray
destinationArray = responses.map(dataFromAPIcall => [dataFromAPIcall.something1, dataFromAPIcall.something2])
}),
tap(_ => {
// continue here
})
).subscribe();

Variable outside of FB API fetch value returns undefined

I'm trying to loop the URL in FB API so that I can retrieve all the photos without paginating it (for photo searching), but when i try to define the value for "after", it always returns undefined. This is the code:
let next;
for (let ctr=0; ctr<albumcount; ctr++) {
let url = '';
if (ctr>0) {
console.log(ctr, next)
url = `https://graph.facebook.com/v3.2/${val}?fields=photos.limit(100)%7Bimages%2Cname%2Clink%7D&after=${next}&access_token=${access_token}`;
} else {
url = `https://graph.facebook.com/v3.2/${val}?fields=photos.limit(100)%7Bimages%2Cname%2Clink%7D&access_token=${access_token}`;
}
fetch(url)
.then(results => {
return results.json();
}).then(data => {
next = data.photos.paging.cursors.after;
});
}
I've been trying multiple things but "next" always returns undefined. How do I return a value for "next".
Thanks in advance.
fetch/AJAX is asynchronous. So the whole loop will be completely finished BEFORE you even get to the first fetch callback. You can use a recursive function for that, or (even better) async/await:
let result = await fetch(url);
Also, you should not use the album count for the loop - just loop as long as there is a "next" link in the response.

async inside a for loop nodejs

I am trying to access an api and I will have to run the api calls several times based on the page numbers I need to iterate, the following is the code which I am using and how can I get the all the response pushed into an array.
as nodeJs is single threaded It is not waiting for the responses from the api.
How can I can tackle this and ensure all the response values are being pushed into an array
Inside the for loop I want the final array which has all the values of the api response. So, I check the total page value and response page Number if that matches which means that will be the last page and I push the array to another function but when I do that it does not have all the values because nodejs does not wait for the api response.
const fs = require('fs');
var pepKey = 'asdfasdfasd';
var pepResponse;
var pepTimecards = [];
pep();
function pep(){
var options = {
headers: {
"content-type": "application/json",
},
agentOptions: {
pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
passphrase: 'asdasdsda'
}
};
request.get('https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex',options, (err, res, body) => {
if (err) { return console.log(err); }
pepResponse = JSON.parse(body)
pepTimecards = pepResponse.data;
if(pepResponse.pages > 1){
for(let i=2;i<=pepResponse.pages;i++){
var url = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
request.get(url,options, (err, res, body) => {
if (err) { return console.log(err); }
body = JSON.parse(body)
pepTimecards = pepTimecards.concat(body.data)
if(pepResponse.pages == body.page){
console.log(pepResponse.pages)
console.log(body.page +"body page")
console.log(pepTimecards)
}
});
}
}else{
}
});
}
Use the request-promise library which supplies promisified versions of the request library. Then, you can use async/await in your for loop to serialize your operations:
Newer answer to go with the edited code in the OP's question
const fs = require('fs');
const rp = require('request-promise');
const pepKey = 'asdfasdfasd';
pep().then(pepTimecards => {
// the timecard data is valid in here
console.log(pepTimecards);
}).catch(err => {
console.log(err);
});
async function pep() {
let timecards = [];
const options = {
headers: {
"content-type": "application/json",
},
agentOptions: {
pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
passphrase: 'asdasdsda'
},
json: true,
uri: 'https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex'
};
let pepResponse = await rp(options);
timecards = pepResponse.data;
if (pepResponse.pages > 1) {
for (let i = 2; i <= pepResponse.pages; i++) {
options.uri = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
let body = await rp(url, options);
// add body.data onto the existing array
timecards.push(...body.data);
}
} else {
}
console.log(pepResponse.pages)
console.log(timecards)
return timecards;
}
Prior Answer before OP edited the code in their question:
const rp = require('request-promise');
// I'm assuming this is some sort of method definition on a class, otherwise it needs the function keyword
async pageno(pageNo) {
for (let i=2;i<=pepResponse.pages;i++){
try {
options.uri = 'https://test/timecard_keys?timecard_type=asdas&page='+pageNo;
// let request-promise parse the json for you automatically
options.json = true;
let body = await rp(options);
pepTimecards = pepTimecards.concat(body.data)
if (pepResponse.pages == body.page){
console.log(pepResponse.pages)
console.log(body.page +"body page")
console.log(pepTimecards)
}
} catch(e) {
// decide what to do for error handling
// this will log and rethrow so the caller will get a rejected promise
console.log(e);
throw e;
}
}
// return some value here to be the resolved value of the returned promise
return pepTimecards;
}
In your code, it is not clear where the options, pepTimecards, pepResponse variables are declared. They should probably be declared as local variables here or passed in to the function and/or returned from your function.
Summary of modifications:
Add async to method declaration so we can use await.
Load request-promise library into rp variable
Add options.json = true to the let the request-promise library parse the JSON result for us automatically
Change rp() to just use the options structure (add URL to that)
Add try/catch to catch any errors from the await, log them, then rethrow so pageno() will return a promise that rejects if there is an error (you can customize the behavior when there's an error if desired)
Add a return value so there is meaningful resolved value to the promise (you should not be using side-effect programming as it is now (modifying variables that are not passed in, declared locally or returned).
Things for you still to fix:
Stop using side-effect programming where you modify free variables that aren't passed in, aren't declared locally and aren't returned. This is a bad way to design code. You don't show enough overall context from the calling code or where these other variables are defined to make a concrete recommendation on how it should be done.
Decide what your error handling strategy is if there's an error on one of the requests and implement that strategy and proper handling.

Can Looping Through a Function "Too Fast" Break It (Node.js)

I am trying to accumulate API responses on a server and return them to the client as a single object. To do this I am looping through items in an array and mapping the responses back into the original object. This is working fine for an array of length 1, but logs blanks when looping through larger arrays.
When looping through the array does Node create a new instance of the function or does it keep passing data into the same function even if it hasn't returned a value yet?
loopThroughArray(req, res) {
for(let i=0; i<req.map.length; i++) {
stack[i] = (callback) => {
let data = getApi(req, res, req.map[i], callback)
}
}
async.parallel(stack, (result) => {
res.json(result)
})
}
....
function getApi(req, res, num, cb) {
request({
url: 'https://example.com/api/' + num
},
(error, response, body) => {
if(error) {
// Log error
} else {
let i = {
name: JSON.parse(body)['name'],
age: '100'
}
console.log(body) // Returns empty value array.length > 1 (req.map[i])
cb(i)
}
})
If Node is overloading the function, how can I ensure data has been received before running the function again?
The api calls are async.
When running the loop, the code is making many rest calls without waiting for the answer.
If the loop is not too big then you could synchronize the calls using recursion.
You could also synchronize the calls using nimble:
http://caolan.github.io/nimble/
a loop waits for the method inside it to finish before it loop back. so there's really no such thing as a loop that moves really fast unless you're using "threading" which your obviously not.

Multiple $http calls doesn't return in the right order

I made a for loop and inside I make a $http call to my API.
The for loop makes the calls in a specific order, but how I get the reponse is totally messed up..
This is my code:
for (var i = 0; i < amountOfEntries; i++) {
var _imageId = NieuwsService.nieuws[i].image;
if (_imageId != "") {
var uriString = "Web/Lists/getbytitle('Afbeeldingen%20voor%20nieuwsberichten')/Items(" + _imageId + ")/File";
NieuwsService.createRequest(requestUrl, baseUrl, uriString).then(function (response) {
var _parser = new DOMParser();
var _xmlData = _parser.parseFromString(response.data, "text/xml");
var _entry = _xmlData.getElementsByTagName("entry");
var _imageUrl = "http://sharepoint" + _entry[0].getElementsByTagNameNS("*", "ServerRelativeUrl")[0].childNodes[0].nodeValue;
//Display
$('#imageList').append("<li><a href='#'>" + _imageUrl + "</a></li>");
NieuwsService.images.push(_imageUrl);
})
}
}
var _createRequest = function (requestUrl, baseUrl, uriString) {
var promise = $http.get(requestUrl, {
params: {
"baseUrl": baseUrl,
"uriString": uriString
}
})
return promise;
}
NieuwsService.createRequest = _createRequest;
return NieuwsService;
So the question is, how do I get the responses in the order I make the calls?
You can create and array of promises, then use $q.all that will resolve when all the requests are done, and you will have the result of each one in the same position where you added the promise.
$http is ASYNC by design, it means that each HTTP will go out in the same order but the response depends on many cases (network,dns, server response time ext...)
you should design your code in a way that it will take that into consideration.
You can use promise
As #RonnieTroj pointed out, the ajax calls are asynchronous and there is no defined order in that respect.
However, if you want to chain api calls such that you get responses in a specific order, then your only option is nesting calls in the following way:
call1.then(function(data1) { //first call
call2.then(function(data2) {//second call after first call completes
//and so on
})
})
However, the issue with this method is that it will take more time because you are essentially making the calls sequential in nature(one call executes, then another instead of parallel async calls.)

Resources