I am getting this error when I console data returned from function that fetch data from back end
{"_U": 0, "_V": 0, "_W": null, "_X": null}
here is below the code:
const events_data = [];
function getvals() {
return fetch('http://PCIP:3000/users/timetable')
.then((response) => response.json())
.then((output) => {
return addData(output, events_data);
})
.catch(error => console.log(error))
}
function addData(data, data2) {
data.map((d) => {
data2.push({
title: d.name,
startTime: genTimeBlock(d.day, d.start_time),
endTime: genTimeBlock(d.day, d.end_time),
location: d.location,
extra_descriptions: [d.extra_descriptions],
});
});
}
const data = getvals();
console.log(data); // the error come from here
I have checked answers here but nothing worked for me
fetch API always returns {“_U”: 0, “_V”: 0, “_W”: null, “_X”: null}
How do I access promise callback value outside of the function?
This is because the fetch promise has not return a response yet,
There two way to solve the issue , first you create another async funciton and use it to await for the response
const events_data = [];
async function getvals() {
return fetch('http://PCIP:3000/users/timetable')
.then((response) => response.json())
.then((output) => {
return addData(output, events_data);
})
.catch(error => console.log(error))
}
function addData(data, data2) {
data.map((d) => {
data2.push({
title: d.name,
startTime: genTimeBlock(d.day, d.start_time),
endTime: genTimeBlock(d.day, d.end_time),
location: d.location,
extra_descriptions: [d.extra_descriptions],
});
});
}
async function waitForResponse() {
let resp = await getvals();
return resp;
}
const data = waitForResponse();
console.log(data); // the error come from here
The other way would be using state hooks, passing the return obj to state hook on response.
Function for API call:
export const getApplication = async (URL, headers) => {
let data;
await fetch.get(URL, headers).then(res => data = res.data).catch(err => err);
return data;
}
You can call the API from anywhere after importing it:
getApplication(`your url`, {
headers: {
Authorization: AUTH_TOKEN,
},
}).then(res => console.log(res)).catch(err => console.log(err));
Related
I'm trying to simple add a new property in an object. The array of objs is being fetched from my database and then I try to add a property which is also fetched from my database. Although when I try to manipulate it I'm receiving "undefined".
Is it indeed an asynch problem?
Am I doing any silly mistakes?
Those are questions that surrounds my head at the moment.
Code:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRows = rows.map(el => {
Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows, fieldData]) => {
console.log(rows);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows.name
};
}).catch(err => console.log(err));
// return{
// ...el,
// userOfReport: 'Joao'
// };
});
res.render('user/index', { reports: rows, pageTitle: 'Social Reporter', path: '/' });
}).catch(err => console.log(err));
};
Obs This works if comment this out and comment Report.fetchUserNameOfReport function->
// return{
// ...el,
// userOfReport: 'Joao'
// };
Expected result:
{
idComplaint: 83059,
title: '4444',
description: '4444',
image: '4444',
location: '4444',
UserInfo_idPessoa: 80068,
userOfReport: 'Joao'
}
Actual result:
undefined
Thank you in advance!
You never return anything in your .map, so all of the values of modifiedRows will be undefined. You can map them all to promises to get all the values, and then access the modified rows once you wait for all of the promises to resolve. Also, you're shadowing your variable by declaring rows and fieldData multiple times:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRowPromises = rows.map(el => {
return Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows2, fieldData2]) => {
console.log(rows2);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
});
Promise.all(modifiedRowPromises).then(modifiedRows => {
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' });
}).catch(console.log);
}).catch(err => console.log(err));
};
Alternatively, if you use async/await syntax, this can be achieved much more cleanly:
exports.getIndex = async (req, res, next) => {
try {
const [rows, fieldData] = Report.fetchAll();
const modifiedRowPromises = rows.map(async el => {
const [rows2, fieldData2] = await Report.fetchUserNameOfReport(el.UserInfo_idPessoa);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
const modifiedRows = await Promise.all(modifiedRowPromises);
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' };
} catch (err) {
console.log(err);
}
};
I have to fetch 2 api from backend, and try to get the result from this two. but, at the moment, the JSON result I get from the first API is object Array in JSON. I need to pass the id from first API(using setState) to second API for path variables. But when I do in my way, it fail to retrieve the data. Consider the code below:
componentDidMount(){
// console.log(loginEmail)
fetch(`http://localhost:9000/api/item/list`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({data: res.data});
}
)
})
const id = this.state.data.id;
fetch(`http://localhost:9000/api/item/photo/view/${id}`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({res});}
)
})
}
The problem is that fetch returns a Promise so, at the line
const id = this.state.data.id;
You do not have data populated yet.
You have to concatenate the two requests in a way like the following:
componentDidMount() {
fetch(`http://localhost:9000/api/item/list`)
.then((resp) => {
// return the id
})
.then((id) => {
fetch(`http://localhost:9000/api/item/photo/view/${id}`)
.then((resp) => {
// do what you need with the result
})
})
}
Fetch is asynchronous, which means javascript will
fetch data on the first call with no waiting, and continue
to the second fetch call where the id is not defined or Null.
In order to fix that you can use promises as follow
My code example
import React from "react";
class Home extends React.Component {
constructor() {
super();
this.state = {
res: [],
}
}
// http://jsonplaceholder.typicode.com/users
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res);
}
)
})
})
}
async componentDidMount() {
let data = await this.fetchData("http://jsonplaceholder.typicode.com/users");
console.log("data :", data);
let id = data[0].id;
console.log("Id :", id);
let newData = await this.fetchData(`http://jsonplaceholder.typicode.com/users/${id}`);
this.setState({ res: newData });
}
render() {
return (
<div>
Call API
</div>
)
}
}
export default Home
Adapted on your code
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res.data);
}
)
})
})
}
async componentDidMount() {
// console.log(loginEmail)
let data = await this.fetchData("http://localhost:9000/api/item/list");
let id = data.id;
let newData = await this.fetchData(`http://localhost:9000/api/item/photo/view/${id}`);
this.setState({ res: newData });
}
You need to make sure that each id gets its relevant results.
async componentDidMount() {
await fetch(`http://localhost:9000/api/item/list`)
.then(async (resp) => {
let req_ = resp.map((item)=>{
return await fetch(`http://localhost:9000/api/item/photo/view/${item.id}`)
})
let result = Promise.all(req_)
console.log(result)
})
}
I am fetching some exchange data from DB, then extracting the name of distinct exchanges and passing again into MYSQL query to fetch data from a different table.
The problem I am facing is that async await does not return the value rather just return Promise { }.
Below is the code that I am trying, wondering where I am going wrong.
//Function that fetches the exchanges from DB
const getExchange = () => {
return new Promise((resolve, reject) => {
db.connection.query(`
SELECT *
FROM,
(
SELECT
exchange,
COUNT(pair) as noOfMarkets
FROM ticker_data
) as t
`, (err, resp) => {
if (!err) {
resolve(resp)
} else {
reject(err)
}
})
})
}
// push unique exchanges to an array.
const getExchangesData = async () => {
const allExchanges = await getExchanges();
let exchanges = []
allExchanges.forEach(item => {
let exchange = {
exchange: item.exchange
}
exchanges.push(exchange)
})
return await exchanges
}
// mapping through an array of exchanges and passing to DB query to get data from the DB.
const getSingleExchange = async () => {
const exchanges = await getExchangesData()
await Promise.all(exchanges.map(async (item) => {
db.connection.query(`
SELECT
exchange_rank,
name
volume24hUSD
(
SELECT
volume24hUSD as tradingVolYesterday
FROM exchanges
WHERE name = '${item.exchange}'
AND createdAt >= now() -interval 1 day
AND createdAt < now() -interval 1 day + interval 120 second
LIMIT 1
) volumeDay1
FROM exchanges
WHERE name = '${item.exchange}'
`, (err, resp) => {
if (!err) {
console.log(resp) // getting all the values
let volData = {
name: resp[0].name,
exchange_rank: resp[0].exchange_rank,
icon: resp[0].icon
}
return volData
}
})
}))
}
const data = getSingleExchange()
console.log(data) // returning Promise { <pending> }
Edit
After making changes suggested in an answer, I still have an issue:
//Function that fetches the exchanges from DB
const getExchange = () => {
return new Promise((resolve, reject) => {
db.connection.query(`
SELECT *
FROM,
(
SELECT
exchange,
COUNT(pair) as noOfMarkets
FROM ticker_data
) as t
`, (err, resp) => {
if (!err) {
resolve(resp)
} else {
reject(err)
}
})
})
}
// push unique exchanges to an array.
const getExchangesData = async () => {
const allExchanges = await getExchanges();
let exchanges = []
allExchanges.forEach(item => {
let exchange = {
exchange: item.exchange
}
exchanges.push(exchange)
})
return await exchanges
}
// mapping through an array of exchanges and passing to DB query to get data from the DB.
const getSingleExchange = async () => {
const exchanges = await getExchangesData()
await Promise.all(exchanges.map((item) => {
return new Promise((resolve, reject) => {
db.connection.query(`...`, (err, resp) => {
if (!err) {
resolve(resp)
} else {
reject(err)
}
}).then(resp => {
console.log(resp)
let volData = {
name: resp[0].name,
exchange_rank: resp[0].exchange_rank,
icon: resp[0].icon
}
return volData
})
})
}))
}
getSingleExchange().then(data => {
console.log(data)
});
I now get this error:
(node:30583) UnhandledPromiseRejectionWarning: TypeError: db.connection.query(...).then is not a function
at Promise (/getExchanges.js:217:16)
at new Promise ()
at Promise.all.exchanges.map (/getExchanges.js:145:16)
at Array.map ()
at getSingleExchange (/getExchanges.js:144:33)
The main issue is in this part:
await Promise.all(exchanges.map(async (item) => {
That map callback is not returning anything, and it has no await, so using async makes no sense.
Instead remove async:
await Promise.all(exchanges.map((item) => {
... and return a promise in the callback function, much like you had done in the first function:
return new Promise((resolve, reject) => {
db.connection.query(`...`), (err, resp) => {
if (!err) {
resolve(resp)
} else {
reject(err)
}
})
}).then(resp => {
console.log(resp)
let volData = {
name: resp[0].name,
exchange_rank: resp[0].exchange_rank,
icon: resp[0].icon
}
return volData
});
You would benefit from writing one generic function that promisifies query, so that you don't have to do that new Promise-thing for every single query you need.
Finally, you cannot expect to get an asynchronous result synchronously: async functions do not return the asynchronous result synchronously, but return a promise for it. So your last lines (main code) should still await. So either do this:
(async () => {
const data = await getSingleExchange()
console.log(data)
})(); // immediately executing (async) function expression
Or:
getSingleExchange().then(data => {
console.log(data)
});
NB: doing return await exchanges in the second function makes no sense (exchanges is not a promise), so you can just do return exchanges.
After reading up on this topic for the last 2.5 hours I cant determine how to fix my: Cannot set headers after they are sent to the client issue, but I think it has to do with the below code at the bottom especially the code is in bold.
Any help or assistance will be greatly appreciated.
app.post("/api/tracking/retrieve", (req, res) => {
res.setHeader('Content-Type', 'application/json');
// before all the iterations
const trackingCodes = ['EZ6000000006', 'EZ4000000004'];
const carrierCodes = ['UPS', 'UPS'];
trackingCodes.forEach((trackingCode) => {
carrierCodes.forEach((carrierCode) => {
const tracker = new api.Tracker({
tracking_code: trackingCode,
carrier: carrierCode
})
tracker.save().then(function (data) {
table = 'tracking_table';
col = ['user_id', 'tracking_number'];
val = [user_id, tracker.tracking_code];
**// !ISSUE: :: ::: :::: ::::: :::::: ::::::: //**
main.create(table, col, val, function (data) {
res.send(JSON.stringify({
id: "",
user_id: user_id,
tracking_number: data.tracking_code
})); // replace this for your res.json()
});
}
)
.catch(error => {
// handle errors
console.log('There has been an error with your submission.')
});
})
})
res.end()
});
As #kiran Mathew has answered, the res.json() are called again and again inside for loop which is why 'cannot set headers after response sent' occurs.
You could have a result array 'trackingNumbers' to store all tracking_number and later exiting from the loop, sent a single response.
app.post("/api/tracking/retrieve", (req, res) => {
const trackingCodes = ["EZ6000000006", "EZ4000000004"];
const carrierCodes = ["UPS", "UPS"];
const trackingNumbers = [];
trackingCodes.forEach(trackingCode => {
carrierCodes.forEach(carrierCode => {
const tracker = new api.Tracker({
tracking_code: trackingCode,
carrier: carrierCode
});
tracker
.save()
.then(function(data) {
table = "tracking_table";
col = ["user_id", "tracking_number"];
val = [user_id, tracker.tracking_code];
// !ISSUE: :: ::: :::: ::::: :::::: ::::::: //**
main.create(table, col, val, function(data) {
// res.json({
// id: "",
// user_id: user_id,
// tracking_number: data.tracking_code
// });
trackingNumbers.push(data.tracking_code);
});
})
.catch(error => {
// handle errors
console.log("There has been an error with your submission.");
});
res.json({
id: "",
user_id: user_id,
tracking_number: trackingNumbers
});
});
});
});
The issue with your code is you are calling res.json() in an iterative loop.
You should call that only once since
res.json() implements res.write(),res.setHeaders() and res.end() under the hood,
which means once res.end() is called it ends the request and cannot send anymore.
You are better off writing the responses using
res.setHeader('Content-Type', 'application/json'); // before all the iterations
res.send(JSON.stringify({key:"value"})); // replace this for your res.json()
res.end() // after iterations
I use a function for Fetch with below code :
var URL='...'
export function PostData(method,data){
fetch(URL+method,{
method:'POST',
body:JSON.stringify(data),
headers:{'Content-Type':'application/json'},
}).then(res => res.json())
.then(response => {
var ret=JSON.stringify(response)
return ret
})
.catch((error) => {
console.error(error)
})
}
and use it like below :
var retData=PostData('login/Authenticate',data)
retData is empty but in function ret has data
You PostData function does currently not return anything, so it is empty.
First step would be to add a return statement:
export function PostData(method,data){
return fetch(URL+method,{
method:'POST',
...
This will make your function return a value, but not just a simple value, but a promise! Promises are not the easiest to understand, but there is also a of people who tried to explain them
- https://developers.google.com/web/fundamentals/primers/promises
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Now how can you use the value anyway?
PostData('login/Authenticate',data)
.then(retData => {
// ... use retData here
});
Now, you used the react-native tag, so I am assuming you want to use this value in your render function. You can't do this simply by putting the PostData call in your render function. You'll have to put it in state, and then use that value in render:
state = { retData: null }
componentDidMount() {
PostData('login/Authenticate',data)
.then(retData => {
// This puts the data in the state after the request is done
this.setState({ retData: retData });
});
}
render() {
let retData = this.state.retData;
// ... use retData in your render here, will be `null` by default
There are a lot more different or cleaner ways to do this, but I tried to keep this answer as simple and bare as possible :)
It is empty at this point because the call to fetch is asynchronous and the literal is set to undefined as it moves to the next statement because it has not been resolved yet. One way around it is to return the promise object itself and then use .then to get the response once it is resolved.
var URL = '...'
export function PostData(method, data) {
// return the promise object
return fetch(URL + method, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
}).then(res => res.json())
.then(response => {
var ret = JSON.stringify(response)
return ret
})
.catch((error) => {
console.error(error)
})
}
PostData('login/Authenticate',data).then(response => {
// do something with the response
});
A cleaner approach would be is to use the async/await ES7 feature which makes it more readable.
var URL = '...'
export function PostData(method, data) {
// return the promise object
return fetch(URL + method, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
}).then(res => res.json())
.then(response => {
var ret = JSON.stringify(response)
return ret
})
.catch((error) => {
console.error(error)
})
}
async function getData() {
let retData = await PostData('login/Authenticate',data);
}