Can't show response after post request - javascript

I'm having trouble when I try to show the answer of post request with node and request. I can see the response in the console in service, but it does not arrive into controller..why?
Thaaaanks!
Here is the code:
function postData(req, res, next){
eventService.getItems()
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
})
.then(response => {
console.log(response) // undefined
res.send(response)
})
.catch(error => {
console.log('error')
next(error)
})
}
module.exports = {postData}
service
postData(data) {
return new Promise(function (resolve, reject) {
request.post({
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + '00002'
},
url: 'url ',
json: data
},
function (error, response, body) {
if (error) {
reject(error)
} else {
console.log(response.body) // shows the message
resolve(response.body)
}
});
})
}
}

Let's focus on the following part of the code:
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
})
.then(response => { // the previous `then` didn't return anything so you shouldn't expect any argument to be passed here!
console.log(response) // undefined
res.send(response)
})
response is available in the context of the first then but not in the second! (this is the reason it's undefined).
In order to pass it to the second then you'll need to add return response after the for-loop of the first then:
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
return response; // <-- pass it here
})
.then(response => {
console.log(response) // and now you'll have it!
res.send(response)
})

You need to return something in every .then in the Promise if you want to use it in the next.
In this case there is not point creating a new .then and you code can be changed to:
function postData(req, res, next){
eventService.getItems()
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
const promises = []
// Should 16 be here? Seems like an error
for(var i = 16 ; i < nameFilter.length; i++){
promises.push(eventService.postData(nameFilter[i]))
}
// postData returns a promise, so above we build an array of all the promises
// then this line will wait for all of them to complete
return Promise.all(promises)
})
.then(allResults => {
// All results will now be the result of every call to `eventService.postData...`
console.log(allResults)
res.send(allResults)
})
.catch(error => {
console.log('error')
next(error)
})
}
module.exports = {postData}

Related

problem awaiting the callback given to a function

I have a function who send a message to the server to get the answer and if the answer is true I want my application to send an error to the user. The problem is that I can't manage to await the callback in the Fetch function I wrote.
This is the function who send the question to the server.
async donglePaired(){
if (Platform.OS !=='ios'){
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log('Sending........');
let data={
data:pairedDevices,
};
new Api().fetch("bluetoothCheck",{devices:JSON.stringify(data),userid:this.state.probe.UID},(result) => {
if (!result.err) return false;
console.log("Dongle already paired");
return true;
//logNetworkState
});
}
}
This is the Api.fetch function i wrote
fetch(action,data,cb){
let url=Config.URL+"?version="+Config.VERSION+"&action="+action;
let post="";
let formData=new FormData();
for(let k in data) formData.append(k,data[k]);
for(let k in data) post+="&"+k+"="+encodeURIComponent(data[k]).replace(/%20/g,'+');
console.log(url+post);
console.log(url);
if (data.batch) console.log(data.batch);
let sending=true;
fetch(url,{
method: 'post',
body: formData
})
.then(function(response){
if (true) return response.json();
let txt=response.text();
console.log(txt);
return JSON.parse(txt);
})
.then(
(result)=>{
if (!sending) return;
sending=false;
console.log(JSON.stringify(result));
if (cb) cb(result);
},
(error)=>{
if (!sending) return;
sending=false;
console.log("fetch error");
console.log(error);
if (cb) cb();
}
);
setTimeout(()=>{
console.log("http timeout")
if (!sending) return console.log("nothing to abort");
if (cb) cb();
},Config.HTTP_TIMEOUT*1000)
}
}
And this is my main code where I wait for the first function donglePaired, and if donglePaired return true I send an error to the user.
let donglePaired = await this.props.app.donglePaired();
if (donglePaired) return this.props.app.setError("ERR_DONGLE");
The problem is that the program doesnt wait for donglePaired, despite of the await
your code here is inappropriate
let donglePaired = await this.props.app.donglePaired();
if (donglePaired) return this.props.app.setError("ERR_DONGLE");
Async function cannot return value normally unless it is a Promise
See my simple demo below!
async function test() {
const result = await asyncRequest()
return result
}
function asyncRequest() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
}
test().then((data) => {
console.log(data)
})
The snippets should give you an idea how to await the callback
Sending to the API
async function remove_configuration(filename) {
const data = { filename };
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
await fetch('/delete', options);
}
Just Retrieving Data
async function display() {
let response = await fetch('/get-available-configurations')
let data = await response.json(); // JSON or Text what do you prefer
// do something with data
}
You could return an Promise.race() with your timeout function.
fetch(action, data, cb) {
let url = Config.URL + "?version=" + Config.VERSION + "&action=" + action;
let post = "";
let formData = new FormData();
for (let k in data) formData.append(k, data[k]);
for (let k in data)
post += "&" + k + "=" + encodeURIComponent(data[k]).replace(/%20/g, "+");
console.log(url + post);
console.log(url);
if (data.batch) console.log(data.batch);
let sending = true;
return Promise.race([
fetch(url, {
method: "post",
body: formData
})
.then(res => res.json())
.then(result => {
if (!sending) return;
sending = false;
return result;
}),
sleep(Config.HTTP_TIMEOUT * 1000)
]);
}
const sleep = ms => new Promise((_, rej) => setTimeout(rej("TIMEOUT"), ms));
It either returns you the value or it rejects with TIMEOUT or it rejects with an error from fetch
And donglePaired looks like this then. I have wrapped it with an try / catch
async donglePaired() {
if (Platform.OS !== "ios") {
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log("Sending........");
let data = {
data: pairedDevices
};
try {
let result = await new Api().fetch("bluetoothCheck", {
devices: JSON.stringify(data),
userid: this.state.probe.UID
});
if (!result.err) return false;
console.log("Dongle already paired");
return true;
//logNetworkState
} catch (err) {
console.log(err);
}
}
}
One possibility is to drop the async and change it to this:
donglePaired() {
return new Promise( function(resolve, reject) {
if (Platform.OS !=='ios'){
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log('Sending........');
let data={
data:pairedDevices,
};
new Api().fetch("bluetoothCheck",{devices:JSON.stringify(data),userid:this.state.probe.UID},(result) => {
if (!result.err) reject(false);
console.log("Dongle already paired");
resolve(true);
//logNetworkState
});
}
reject(false);
});
}
And:
this.props.app.donglePaired().then( (response) => {
// do something here, this will only run if the response is true
});

Why does this code return undefined and how to make this code work

Request to the api successfully return the data as expected. The data from api is saved to 'fact' variable. The problem is that the 'getData' function returns promise which is expected to resolve
the data, instead it returns undefined.
const getData = num => {
let fact;
if (Array.isArray(num)) {
fetch(`http://numbersapi.com/${num[0]}/${num[1]}/date`)
.then(response => response.text())
.then(data => {
fact = data;
});
} else if (num.math === true) {
fetch(`http://numbersapi.com/${num.val}/math`)
.then(response => response.text())
.then(data => {
fact = data;
});
} else {
fetch(`http://numbersapi.com/${num}`)
.then(response => response.text())
.then(data => {
fact = data;
});
}
return new Promise((resolve, reject) => {
resolve(fact);
});
};
getData([1, 26]).then(val => {
console.log(val);
});
Fetch is a promise based api, it returns a promiss, and you don't need to wrap fetch in promise.
You could prepare the url string in the if checks, and then use it in the fetch call.
Example
const getData = num => {
let url;
if (Array.isArray(num)) {
url = `http://numbersapi.com/${num[0]}/${num[1]}/date`;
} else if (num.math === true) {
url = `http://numbersapi.com/${num.val}/math`;
} else {
url = `http://numbersapi.com/${num}`
}
return fetch(url);
};
getData([1, 26]).then(response => {
console.log(response.text());
});

Calling the return value of a function to other function

How to properly return the value of the variable otherURL and call/use it in other function of the same file.
Using the code below.
function getOtherURL() {
var url = "https://url/data.json";
fetch(url)
.then(res => res.json())
.then((data) => {
console.log('Checkout this JSON! ', data);
let otherURL;
for (var i = 0; i < data.length; i++) {
//some code
otherURL = "http://url/from" + from + "&to=" + to;
}
console.log("otherURL" , otherURL);
})
.catch(err => { throw err });
}
This is my other function
export function getData() {
//need to read the value of otherURL and assign into new variable something like this
let newURL = otherURL;
const promiseMSFT = fetch(newURL) //here I want to assign the newURL
.then(response => response.json())
.then(data => {
//more code
}
function getOtherURL() {
var url = "https://url/data.json";
return fetch(url)
.then(res => res.json())
.then((data) => {
console.log('Checkout this JSON! ', data);
let otherURL;
for (var i = 0; i < data.length; i++) {
//some code
otherURL = "http://url/from" + from + "&to=" + to;
}
return otherUrl; //return value
})
.catch(err => { throw err });
}
and then call it in your exported function
export function getData() {
//return promise to the caller
return getOtherURL().then(otherUrl => {
let newURL = otherURL;
//then you can chain the other promise
return fetch(newUrl);
})
.then(response => response.json())
.then(data => {
//more code
})
}
If you can modify the getData() function to have a parameter like getData(otherURL), you can do this:
function getOtherURL() {
const url = 'https://url/data.json';
fetch(url)
.then(res => res.json())
.then((data) => {
console.log('Checkout this JSON! ', data);
let otherURL;
for (let i = 0; i < data.length; i++) {
// some code
otherURL = `http://url/from${from}&to=${to}`;
}
console.log('otherURL', otherURL);
return otherURL;
})
.then(otherURL => {
// chain then() here
getData(otherURL);
})
.catch((err) => {
throw err;
});
}
Modified function
export function getData(otherURL) {
// need to read the value of otherURL and assign into new variable something like this
let newURL = otherURL;
console.log(newURL);
}

Javascript - Chain multiple Fetch promises

I have this method who performs 3 window.fetch
const API_URL = 'http://localhost:3000/'
, API = {
'getArtistLyric': artist => {
return fetch(`${API_URL}artist?name=${artist}`)
.then(res => res.json())
.then(res => {
const artistID = JSON.parse(res).message.body.artist_list[0].artist.artist_id;
console.log('Artist ID is:', artistID);
fetch(`${API_URL}artist/albums/?artist_id=${artistID}`)
.then(resp => resp.json())
.then(resp => {
const trackID = JSON.parse(resp).message.body.album_list[0].album.album_id;
console.log('Random Track ID is:', trackID);
fetch(`${API_URL}artist/album/songsnippet?track_id=${trackID}`)
.then(response => response.json())
.then(response => {
const lyricSnippet = JSON.parse(response).message;
console.log('Track Id lyric snippet is:', lyricSnippet);
})
.catch(err => {
console.error(err);
});
})
.catch(err => {
console.error(err);
});
})
.catch(err => {
console.error(err);
});
}
}
Now i want to call it like this
API.getArtistLyric('Prodigy').then(res).catch(err);
What's the best practice here?
If you want to make a chain requests it's better to use async/await :
async func(){
let response = await /* some request */
let res = await /* another request */
...
return results;
}
Here you can use try/catch syntax and wrap specific request :
try {
let response = await...
} catch ( exception) {
...
}
Also you can wrap a couple of requests.
(async() => {
const API_URL = 'http://localhost:3000/';
const API = {
getArtistLyric: async(artist) => {
try {
const res = await fetch(`${API_URL}artist?name=${artist}`);
const artistID = JSON.parse(res.json()).message.body.artist_list[0].artist.artist_id;
console.log('Artist ID is:', artistID);
const resp = await fetch(`${API_URL}artist/albums/?artist_id=${artistID}`);
const trackID = JSON.parse(resp.json()).message.body.album_list[0].album.album_id;
console.log('Random Track ID is:', trackID);
const response = await fetch(`${API_URL}artist/album/songsnippet?track_id=${trackID}`);
const lyricSnippet = JSON.parse(response.json()).message;
console.log('Track Id lyric snippet is:', lyricSnippet);
return lyricSnippet;
} catch (e) {
console.error(e);
}
}
}
try {
const art = await API.getArtistLyric('Prodigy');
console.log(art);
} catch (e ){
console.error(e);
}
})()
Check out this link regarding chaining promises: https://javascript.info/promise-chaining
Here's the core idea:
It looks like this:
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1 return result * 2;
}).then(function(result) { // (***)
alert(result); // 2 return result * 2;
}).then(function(result) {
alert(result); // 4 return result * 2;
});
The idea is that the result is passed through the chain of .then
handlers.
Here the flow is:
The initial promise resolves in 1 second (*), Then the .then handler
is called (**). The value that
it returns is passed to the next .then handler (***) …and so on.

How to return a single promise after for loop where every element of an array inside loop do multi async calls

I Have a array of objects which i need to clone with different values.
Those values i'll get from each promise finally after preparing main modified array of object i'll have to save this. So i many need this as one single promise.
I not sure how to do it.
Here is the example we need to clone oldUser data. Say old user has credit score = 100; but for new user default credit will be created randomly by system.
For each user in the array of users few details has to get updated using async call.
This is the requirement
function getUserCreditScore(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.creditScore = (res.data) ? res.data : 0;
});
}
function getUserRecomandations(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.recommendation = (res.data) ? res.data : 'basic recommendation';
});
}
function getUserHelpInfo(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.helpInfo = (res.data) ? res.data : 'Help Info';
});
}
function clone(){
var newUsers = angular.copy(oldUsers);
for (var i=0; i<newUsers.length; i++){
newUsers[i].id = undefined;
getUserCreditScore(newUsers[i]);
getUserRecommendation(newUsers[i]);
getUserHelpInfo(newUsers[i]);
}
var promises = _.map(newUsers, user => user.save());
$q.all(promises).then(function (data) {
console.log(data);
}
}
You'll need to Promise.all on an array of Promises that are returned by getScreditScore
something like
function getCreditScore(){
var url = '/someurl';
return $http.get(url).then(res => (res && res.data) ? res.data : res);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore()
.then(result => newUser.creditScore = result);
})
).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
Promise.all(newUsers.map(user => user.save()))
).then(data =>
console.log(data); // this will be the result of all the user.save
);
}
Note: the newUser.creditScore is set in the .then in the newUsers.map callback - (minimal change to my original answer)
Alternatively, passing user to getCreditScore
function getCreditScore(user){
var url = '/someurl';
return $http.get(url)
.then(res => (res && res.data) ? res.data : res)
.then(score => user.creditScore = score);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore(newUser);
})
).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
Promise.all(newUsers.map(user => user.save()))
).then(data =>
console.log(data); // this will be the result of all the user.save
);
}
Personally, I'd write the code
function getCreditScore(){
var url = '/someurl';
return $http.get(url).then(res => (res && res.data) ? res.data : res);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore()
.then(result => newUser.creditScore = result)
.then(() => newUser.save())
.then(() => newUser);
})
).then(data =>
console.log(data); // this will be the newUsers Array
);
}
This assumes, though, that you don't need to wait for all the $http.get before running the user.save() - in fact this may be a little (very little) more performant as the newUser.save and $http.get will run in tandem
Ok, I know your meaning, you want your every element of your array do something that is async.
So you can use map and Promise.all. Here is my code:
const asyncFunction = (item, cb) => {
setTimeout(() => {
console.log(`done with ${item}`);
cb();
}, 1000);
}
let requests = [1, 2, 3].map((item) => {
return new Promise((resolve) =>{
asyncFunction(item, resolve);
});
});
Promise.all(requests).then(() => console.log('done'));

Categories

Resources