FETCH API return undefined - api

I want to use Fetch API but i don' t really understand it's mecanism.
I have an in my HTML and i want to assign the result of my fetch with this code :
const weather = "http://api.apixu.com/v1/current.json?key=cba287f271e44f88a60143926172803&q=Paris";
const array = [];
fetch(weather)
.then(blob => blob.json())
.then(data => {
array.push(data.current.humidity)
console.log(array[0])
}
);
document.querySelector('h1').innerHTML = array[0];
i have the result with the console.log but the returns "undefined". can you explain why ?
thanks a lot

This is because the call to the API is asynchronous, meaning that the code is not executed just line by line as you write it. The callback only runs as soon as the call to the API has finished, basically meaning that
data => {
array.push(data.current.humidity)
console.log(array[0])
}
runs after
document.querySelector('h1').innerHTML = array[0];
So when you try to set your h1, array is still empty. If you want to set it as soon the data is available, you have to do it within the callback function:
data => {
array.push(data.current.humidity)
document.querySelector('h1').innerHTML = array[0];
}
This might seem weird at first, but keep in mind that you're only registering an anonymous function but not running it yet. You just define the function that you want to trigger as soon as something happens, in this case: when your API call has finished.

Related

Sending response in async function

I need to return an array of labels, but I can only return 1 of the labels so far. The error which I get is "Cannot set headers after they are sent to the client". So I tried res.write and placed res.end after my for loop then I get the obvious error of doing a res.end before a res.write. How do I solve this?
for(let i=0;i<arr.length;i++){
request.get(arr[i], function (error, response, body) {
if (!error && response.statusCode == 200) {
myfunction();
async function myfunction(){
const Labels = await Somefunctioncallwhoseresponseigetlater(body)
res.send(Labels);
}
}
});}
New code-
async function getDataSendResponse(res) {
let allLabels = [];
for (let url of arr) {
let body = await got(url).buffer();
var imgbuff= Buffer.from(body,'base64')
const imageLabels = await rekognition.detectLabels(imgbuff);
allLabels.push(...imageLabels);
}
res.send(allLabels);
}
The error I have with this code is
"Resolver: AsyncResolver
TypeError: Cannot destructure property Resolver of 'undefined' or 'null'."
You are trying to call res.send() inside a for loop. That means you'll be trying to call it more than once. You can't do that. You get to send one response for any given http request and res.send() sends an entire response. So, when you try to call it again inside the loop, you can the warning you see.
If what you're trying to do is to send an array of labels, then you need to accumulate the array of labels first and then make one call to res.send() to send the final array.
You don't show the whole calling context here, but making the following assumptions:
Somefunctioncallwhoseresponseigetlater() returns a promise that resolves when it is done
You want to accumulate all the labels you collected in your loop
Your Labels variable is an array
Your http request returns a text response. If it returns something else like JSON, then .text() would need to be changed to .json().
then you can do it like this:
const got = require('got');
async function getDataSendResponse(res) {
let allLabels = [];
for (let url of arr) {
let body = await got(url).buffer();
const labels = await Somefunctioncallwhoseresponseigetlater(body);
allLabels.push(...labels);
}
res.send(allLabels);
}
Note, I'm using the got() library instead of the deprecated request() library both because request() is not deprecated and because this type of code is way easier when you have an http library that supports promises (like got() does).

ExpressJS - res.status(500) returning undefined so I can't call send on it

I have some code that usually works, but twice now has produced the following error:
TypeError: Cannot read property 'send' of undefined
The code is:
app.user.get('/status.json', mGatewayTimeout, function (req, res) {
var user = req.user
var qs = cu.querystring.parseUrl(req.url)
if (user.apps && user.apps.beeminder && user.apps.beeminder.access_token) {
if (bsCache[user.username] && !qs.force) {
res.send(bsCache[user.username])
} else {
var bee = new Bee({access_token: req.user.apps.beeminder.access_token})
bee.getUserSkinny(function (err, bm_user) {
if (err) {
bsCache[user.username] = null
return res.status(500).send('error: ' + err.toString())
So that last line produces the TypeError when it tries to call .send on res.status(500).
I've left in a whole bunch of stuff that is certainly irrelevant, because if I tried to take out everything that I thought was irrelevant, we'd be left with nothing.
Bee is an API client, but one that I wrote, so I'm not sure it isn't doing something weird, except that I can't see how it could be affecting the response object.
Try
res.status(500).send(`error ${err.message}`),
new Error's are objects made from a constructor and one of the properties is message.
Oh man, I'm a fool. I made my own problem here. This was on an endpoint that accesses an external API, and since I'm on heroku I need all requests to take under 30s, so I wrote some timeout code that would send an error then turn various functions like res.send into no-op functions. Problem, of course, was that I didn't proceed to return the res object in those no-ops.
🤦‍♀️

How to access the current instance in nuxt page validate()?

I return a Promise in validate(). Now, I want to pass the data which is returned in the validation by the server to one of the methods. However, I am not able to do this. Please help!
validate({ params, store, context }) {
return store.dispatch(types.VALIDATE_PARAMS_ASYNC, params.id).then(data => {
this.saveSettings(this, data)
return true
}).catch(e => {
return false
})
}
Its not possible. Validate executed before the instance initialized, so you cant access methods. And validate isnt supposed to be used that way.
For passing data to need either to save them into vuex store ( preferably in fetch method ) or return them as data in asyncData method. Then you can do what you want with your data in for example mounted method, or beforeMounted.

Variable Doesn't Change in Vue.js

I can't change the variable qty in my computed properties.
getQuantity(){
return (qtyId) => {
var qty = 0;
axios.get( window.location.origin + '/api/quantity/' + qtyId)
.then(res => {
console.log(res.data.qty)
qty = res.data.qty
})
.catch()
console.log(qty)
return qty
}
},
It is an asynchronous request using axios. the console.log(res.data.qty) works fine it output 4 but the console.log(qty) is 0. I think it's because of asynchronous request... How can I make it work... TY
I think it's because of asynchronous request
It definitely is.
If you're not familiar with writing asynchronous code, I would read up on that first (in particular promises).
console.log(qty) returns 0 because that code is executed immediately after the request is sent and before the response has come back from the server. The callback function you passed to then is the function that will be executed once the response has come back from the server, and only then will you be able to obtain qty from the response data.
If you want to return qty from that function (which is what it looks like you are trying to do), then that function must return a promise that once resolved will contain the qty value (code isn't blocked in JavaScript, hence the reason for the promise).
getQuantity() {
return (qtyId) => {
return axios.get(window.location.origin + '/api/quantity/' + qtyId)
.then(res => {
return res.data.qty;
});
}
},
Why is it a computed property instead of a method? I think a different approach would be better, but I don't know exactly how this code fits into your project.

using bluebird promises with express to make API calls

I'm trying to get different chunks of data from a trello API using bluebird promises library. In my express router I'm using middleware isLoggedIn, and getBoards, which body looks something like:
trello.get("/1/members/me/boards") // resolves with array of board objects
.each((board) => {
// do some async stuff like saving board to db or other api calls, based on retrieved board
.catch(err => console.error('ERR: fetching boards error - ${err.message}'))
})
The question is: I want to redirect (res.redirect('/')) only when all boards were retrieved and saved. How can I do that? Where should I place xres.redirect('/') expression?
I think you need something like:
var Promise = require('bluebird');
var promises = [];
trello.get("/1/members/me/boards") // resolves with array of board objects
.each((board) => {
//
promises.push( /*some promisified async call that return a promise, saving data in db or whatever asynchronous action. The important bit is that this operation must return a Promise. */ );
});
//So now we have an array of promises. The async calls are getting done, but it will take time, so we work with the promises:
Promise.all(promises).catch(console.log).then( function(results){
/*This will fire only when all the promises are fullfiled. results is an array with the result of every async call to trello. */
res.redirect('/'); //now we are safe to redirect, all data is saved
} );
EDIT:
Actually, you can avoid some boilerplate code using map instead of each:
trello.get("/1/members/me/boards") // resolves with array of board objects
.map((board) => {
return somePromisifiedSaveToDbFunction(board);
}).all(promises).catch(console.log).then( function(results){
res.redirect('/');
} );