I'm working on a module containing a class with functions which calls an api everytimes we use a function.
I want to handle the result & catch IN the module and only send data in return.
function getAllFromTable(aTableName){
const request = {
.... aTableName
}
return apiCall(request)
}
function apiCall(requestConfig){
axios(requestConfig).then(result => {
return result.data
}
.catch(err => {
return err
}
}
That's the idea of what I would like to do but of course this only sends back "undefined"..
Is there a way to make a return in a then() to send back the data ?
Or another way to send back only the data and not a Promise to the one who calls the function "getAllFromTable()" ?
Is there a way to make a return in a then() to send back the data ? Or another way to send back only the data and not a Promise to the one who calls the function "getAllFromTable()" ?
No. In Javascript, there is NO way to return an asynchronously retrieved result directly. You HAVE to use an asynchronous mechanism such as a promise, a callback or an event to communicate back the asynchronous result. Since you already have a promise, you need to just return the promise and make sure that its resolved value is your final result. Then, the caller can use either .then() or await to get the result out of the promise.
That's the idea of what I would like to do but of course this only sends back "undefined"..
In your apiCall() function, you have to return the promise and fix your error handling.
Change this:
function apiCall(requestConfig){
axios(requestConfig).then(result => {
return result.data
}.catch(err => {
return err
});
}
to this:
function apiCall(requestConfig){
return axios(requestConfig).then(result => {
return result.data;
});
}
I removed the .catch() because you were changing the promise from rejected to resolved and making the error object be the resolved value. That is unlikely what you want for the function behavior and very unlikely what the caller wants. If you want a .catch() to log the error or something, then you can throw the error again to make sure the promise stays rejected.
function apiCall(requestConfig){
return axios(requestConfig).then(result => {
return result.data;
}).catch(err => {
// log error and rethrow so the promise stays rejected
console.log(err);
throw err;
});
}
The caller of apiCall() will then either use .then() or await to get the resolved value of the promise that the function returns.
apiCall(...).then(val => {
console.log(val);
}).catch(err => {
console.log(err);
});
Related
I have a list of APIs I want to call GET simultaneously on all of them and return as soon as one API finishes the request with a response code of 200.
I tried using a for-loop and break, but that doesn't seem to work. It would always use the first API
import axios from 'axios';
const listOfApi = ['https://example.com/api/instanceOne', 'https://example.com/api/instanceTwo'];
let response;
for (const api of listOfApi) {
try {
response = await axios.get(api, {
data: {
url: 'https://example.com/',
},
});
break;
} catch (error) {
console.error(`Error occurred: ${error.message}`);
}
}
You can use Promise.race() to see which of an array of promises finishes first while running all the requests in parallel in flight at the same time:
import axios from 'axios';
const listOfApi = ['https://example.com/api/instanceOne', 'https://example.com/api/instanceTwo'];
Promise.any(listOfApi.map(api => {
return axios.get(api, {data: {url: 'https://example.com/'}}).then(response => {
// skip any responses without a status of 200
if (response.status !== 200) {
throw new Error(`Response status ${response.status}`, {cause: response});
}
return response;
});
})).then(result => {
// first result available here
console.log(result);
}).catch(err => {
console.log(err);
});
Note, this uses Promise.any() which finds the first promise that resolves successfully (skipping promises that reject). You can also use Promise.race() if you want the first promise that resolves or rejects.
I think jfriend00's answer is good, but I want to expand on it a bit and show how it would look with async/await, because that's what you are already using.
As mentioned, you can use Promise.any (or Promise.race). Both take an array of promises as argument. Promise.any will yield the result of the first promise that resolves successfully, while Promise.race will simply wait for the first promise that finishes (regardless of whether it was fulfilled or rejected) and yield its result.
To keep your code in the style of async/await as it originally was, you can map the array using an async callback function, which will effectively return a promise. This way, you don't have to "branch off into .then territory" and can keep the code more readable and easier to expand with conditions, etc.
This way, the code can look as follows:
import axios from 'axios';
const listOfApi = ['https://example.com/api/instanceOne', 'https://example.com/api/instanceTwo'];
try {
const firstResponse = await Promise.any(listOfApi.map(async api => {
const response = await axios.get(api, {
data: {
url: 'https://example.com/',
},
});
if (response.status !== 200) {
throw new Error(`Response status ${response.status}`, {cause: response});
}
return response;
}));
// DO SOMETHING WITH firstResponse HERE
} catch (error) {
console.error('Error occured:', error);
}
Side note: I changed your console.error slightly. Logging only error.message is a common mistake that hinders you from effective debugging later on, because it will lack a lot of important information because it prints only the message and not the error stack, the error name or any additional properties the error may have. Using .stack and not .message will already be better as it includes name and stack then, but what's best is to supply the error as separate argument to console.error so that inspect gets called on it and it can print the whole error object, with stack and any additional properties you may be interested in. This is very valuable when you encounter an error in production that is not so easy to reproduce.
This bit of code, after connecting, does some stuff
controller.connect((response)=>{ does some stuff })
Down deep in the guts of the connect method this async function gets called, which returns a promise by way of the callback
async function ServerSend(endpoint,params,callback) {
const response = axios.get(host+endpoint, {params})
callback(response);
}
If the server is not available it correctly throws: UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:8088
What is the correct way to handle this exception? I could possibly add a catch in the async method and rewrite all the call backs to return an err. But I'd rather catch it at the caller. I have not been able to get either method to work.
axios.get(host+endpoint, {params}) // this is a promise
so if it resolves it will be ok, but if it rejects (and yuou dont have any try .. catch, any .catch attached - it will throw error that exception is unhandled.
Why way would be to:
async function ServerSend(endpoint,params,callback) {
try {
const response = await axios.get(host+endpoint, {params})
callback(null, response);
} catch (err) {
callback(err, null);
}
}
OR
function ServerSend(endpoint,params,callback) {
// most callbacks are two parameters - 1st erro or null, second data if no error is present.
axios.get(host+endpoint, {params}).then(data => callback(null, data)).catch(err => callback(err, null));
}
I have a use case to resolve a Promise without returning it. Catching for errors internally, but don't want the caller to wait for the promise to resolve.
doSomething()
{
Promise.resolve()
.then(() => {
// do something.
})
.catch(reason => {
this.logger.error(reason);
});
}
Getting this error:
(node:2072) Warning: a promise was created in a handler at internal/timers.js:439:21 but was not returned from it, see http://. goo.gl/rRqMUw
at Function.Promise.cast (.../node_modules/bluebird/js/release/promise.js:225:13)
Just return something from the Promise callback where you are creating the fire and forget promise.
I'm guessing that handler is doSomething
doSomething()
{
Promise.resolve()
.then(() => {
// do something.
})
.catch(reason => {
this.logger.error(reason);
});
return null //or anything else that's sensible
}
Note: We usually ignore the error message, but sometimes they contain valuable information. In your error there's a link http://. goo.gl/rRqMUw that explains exactly this problem:d
I've been trying to use Axios in order to check whether or not a user is authenticated server side (Node+Express+Passport).
If a user is authenticated, the server sends back a "Connected" string, else, it sends back a "Not connected" string.
Router.get('/isAuth', function (req, res, next) {
if (req.isAuthenticated()) {
return res.status(200).send('Connected');
} else {
return res.status(200).send('Not connected');
}
});
I wrote a simple function to check the server's response:
function isAuth() {
return axios.get('http://localhost:3000/endpoints/isAuth')
.then((response) => {
if (response.data === "Connected") {
return true;
} else {
return false;
}
})
.catch((error) => {
console.log(error)
})
}
The function is supposed to return true if the user is connected, and vice-versa.
Now, when I try to log the the function's results in the console, this is what I get:
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
__proto__ : Promise
[[PromiseStatus]] : "resolved"
[[PromiseValue]] : false
As you can see, the value returned is a promise object, whereas the desired output would preferably be a "True" or "False".
isAuth does an async request which will take some time. therefore it cannot return true or false directly. it will instead return a promise that gets that boolean value. to access your boolean value, you have to treat your isAuth() function as a promise:
isAuth().then(isAuthenticated => console.log(isAuthenticated));
Update:
this code:
var test = isAuth();
will return the promise syncronously and won't wait for the reponse result
if you want to access the reponse of the promise, you need to use then:
test.then(value => ...);
if you really want to do a syncronous http request (blocks your app, untill the request is resolved) you can checkout https://github.com/ForbesLindesay/sync-request
but you actually don't want to use if it is not for test purpose only.
another thing you could consider is the use of async/await which comes with node 7.6 but you first should fully understand the concept of promises
I am trying to stop a promise chain midway (After a catch). So after an error occurred in the first promise the catch will catch it but I don't want the chain to continue. I'm using bluebird. How would I do this?
getRedirectedURL(url).then(function(url) {
console.log(1);
url = domainCleanse(url);
sql = mysql.format(select, url);
return [ url, mysqlQuery(sql) ];
}).catch(function(error) {
console.log(2);
console.error(error);
socket.emit('error:unreachable', url + ' was unreachable');
}).spread(function(url, rows) {
console.log(3);
if(_.isEmpty(rows[0])) {
socketList.push({
url: url,
ttl: _.now(),
socket: socket,
added: false
});
} else {
socket.emit('done', mapResults(rows[0]));
}
}).catch(function(error) {
console.log(4);
console.error(error);
socket.emit('error', 'We could not reach ' + url + ' at this time.');
});
Generalizing your example, it looks like this:
promiseToFoo()
.then(promiseToBar)
.catch(failedToFooOrBar)
.then(promiseToFrob)
.catch(failedToFrob)
Along the happy path you are promising to Foo, then to Bar, then to Frob. Based on your description, you want to handle errors Fooing or Barring separately from errors Frobbing. So a simple solution is bury the error handling for Frob into that promise. So instead of chaining a promise to Frob, you're chaining a promise to Frob and handle errors in Frobbing. Something like this:
promiseToFoo()
.then(promiseToBar)
.catch(function (error) {
failedToFooOrBar(error);
return Promise.reject(error);
})
.then(function (x) {
return promiseToFrob(x).catch(failedToFrob);
});
A key to this is to make sure that your on-reject handler in the first catch ends up leaving the chain in a rejected state when it leaves. This is handled in the sample above by returning a rejected Promise from the handler. You can also handle it by throwing an Error from the handler. If you don't do one of these things, then the promise will be in a fulfilled state when the handler finishes and the on-fulfill handler provided by the subsequent then call will be invoked.