How to structure an asynchronous call to an API? - javascript

I'm trying to write some code that makes a call to an API, which will then return some URLs, from each of which I'll then need to make a new call. To avoid nesting loads of callbacks everywhere I've tried using async/await, but it doesn't seem to be working for some reason despite the extremely simple setup I've tried.
I've tried to create two async functions, one of which makes the call to any url and returns the response, and another one which will then call the first function several times depending on the response (i.e. how many urls are returned).
const request = require('request');
init();
async function init() {
const username = "x";
const archiveUrl = "https://someurl.com";
const archiveResponse = await apiCall(archiveUrl)
const archives = archiveResponse.archives;
console.log(archives);
}
async function apiCall(url) {
request(url, { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(body);
return body;
});
}
This is literally my entire code at the moment and I'm not sure where it's going wrong. The error I'm getting is that it can't read .archives from undefined, and after that error message it's then logging the body from the apiCall function (making me fairly sure that the function isn't awaiting as expected).
That said I can't see what I'm doing wrong. Any tips on general best practice would be much appreciated, I've used async/await before but it's always been hacky and self-taught so I'm sure there's a better way of doing this.

In the apiCall function you are using callback instead of Promise, You need to promisify that function so that const archiveResponse = await apiCall(archiveUrl) actually works:
function apiCall(url) {
return new Promise((res, rej) => {
request(url, { json: true }, (err, res, body) => {
if (err) { return rej(err)}
console.log(body);
return res(body);
});
})
}
If you are using async-await please handle errors by enclosing this in try..catch
Note: Or you can use request-promis or axios they support promise out of the box.

You are close!
let response = await fetch('https://someurl.com');
let data = await response.json();
console.log(response);
decode the JSON body of the response with .json() and it should work

Related

Javascript Return Value in graphql

I have an apollo-server setup in my backed, I want to use a post request API inside one of my resolvers and then use the response from that API to return it to my client. but the problem am having is the return statement is running before the API response get returned. there is my code sample bellow.
module.exports = {
Mutation: {
checkFace: async () => {
console.log("Checking.....");
let confidence;
var parameters = {
image_url1: "link to image 1",
image_url2: "link to image 2",
};
facepp.post("/compare", parameters, function (err, res) {
if (!err) {
confidence = res.confidence;
} else {
console.log(err);
}
});
return confidence
},
},
};
That's because the faceapp.post is probably running asynchronously. Your checkFace function is correctly used as async that's fine, but inside where you call the POST you should await the response and then return it
confidence = await res.confidence;
Also when using the function make sure you await for it to finish, so call it with
let someResponse = await Mutation.checkFace();
console.log(someResponse);
or
Mutation.checkFace().then(response => {
console.log(response);
});
Whichever you prefer depending on your situation.
https://nodejs.dev/learn/modern-asynchronous-javascript-with-async-and-await

async/await with Limiter for sending requests

I'm trying to limit the number of requests I send to an API.
I'm using Limiter and it's working just like I need, the only issue is that I can't find a way to use it with await (I need all the responses before rendering my page)
Can someone give me a hand with it?
Btw the Log returns a boolean.
const RateLimiter = require('limiter').RateLimiter;
const limiter = new RateLimiter(50, 5000)
for (let i = 0; i < arrayOfOrders.length; i++) {
const response = limiter.removeTokens(1, async (err, remainingRequests) => {
console.log('request')
return await CoreServices.load('updateOrder', {
"OrderNumber": arrayOfOrders[i],
"WorkFlowID": status
})
})
console.log('response', response)
}
console.log('needs to log after all the request');
this is loggin:
response true
response true
response false
needs to log after all the request
request
request
request
...
Promisifying .removeTokens will help, see if this code works
const RateLimiter = require('limiter').RateLimiter;
const limiter = new RateLimiter(50, 5000);
const tokenPromise = n => new Promise((resolve, reject) => {
limiter.removeTokens(n, (err, remainingRequests) => {
if (err) {
reject(err);
} else {
resolve(remainingRequests);
}
});
});
(async() => { // this line required only if this code is top level, otherwise use in an `async function`
const results = await Promise.all(arrayOfOrders.map(async (order) => {
await tokenPromise(1);
console.log('request');
return CoreServices.load('updateOrder', {
"OrderNumber": order,
"WorkFlowID": status
});
}));
console.log('needs to log after all the request');
})(); // this line required only if this code is top level, otherwise use in an `async function`
explanation
Firstly:
const tokenPromise = n => new Promise((resolve, reject) => {
limiter.removeTokens(n, (err, remainingRequests) => {
if (err) {
reject(err);
} else {
resolve(remainingRequests);
}
});
});
promisifies the limiter.removeTokens to use in async/await - in nodejs you could use the built in promisifier, however lately I've had too many instances where that fails - so a manual promisification (I'm making up a lot of words here!) works just as well
Now the code is easy - you can use arrayOfOrders.map rather than a for loop to create an array of promises that all run parallel as much as the rate limiting allows, (the rate limiting is done inside the callback)
await Promise.all(... will wait until all the CoreServices.load have completed (or one has failed - you could use await Promise.allSettled(... instead if you want)
The code in the map callback is tagged async so:
await tokenPromise(1);
will wait until the removeTokens callback is called - and then the request
return CoreServices.load
is made
Note, this was originally return await CoreServices.load but the await is redundant, as return await somepromise in an async function is just the same as return somepromise - so, adjust your code too

How can i extract values from promise and send them to client via node.js server?

I have a promise that returns data and I want to pass values of the promise as a response to client(web browser). I know i should probably use asynchronous js, but I'm not sure how to do that. Could you please give me some advice?
Here is how it looks like:
if(req.url === "/api/posts"){
res.writeHead(200, {"Content-Type": "application/json"})
let db = new AppDAO('./db/db.sqlite3')
const postsDb = new PostsRepository(db)
let posts = postsDb.getAll()
db.close()
console.log(posts)
res.end()
}
What you need is to build the response when the DB Promise resolves
postsDb.getAll().then(posts => {
console.log(posts)
res.send(posts)
}).finally(() => db.close())
Or if you want to use the modern syntax, and can declare the surrounding function as async:
try {
const posts = await postsDb.getAll()
console.log(posts)
res.send(posts)
} catch(e) {
// Handle database error
} finally {
db.close()
}

How to get promise.response to return an API’s response?

TLDR: my promise.response needed to be called within both the API call and the promise.
I am attempting to get a return value from an API call via a Promise for a simple Express.js server.
This seems to be a topic of a lot of questions, but I have yet to successfully adapt an implementation to this case. I've also tried:
placing the API call within resolve()
async/wait implementations (willing to revisit)
Here's the basic structure of the code in question. There's a comment above the section where the trouble probably is.
Promise
const externalModule = require('<route to module>');
let promise = new Promise(function(resolve,reject) {
// This is probably where the problem is
let returnValue = externalModule.apiCall(parameters);
resolve(returnValue);
});
promise.then(function(returnValue) {
console.log(returnValue);
});
External Module
module.exports = {
apiCall: function(parameters) {
apiCall(
parameters,
function(err, response) {
if (err) {
console.error(err);
return;
} else {
console.log("success");
return response
}
}
)
}
};
If the code were working properly, we'd see two strings. One from inside the API call ("success") and another from it's return value. Because undefined is appearing before "success," we know that the resolve function has fired before the function above it has returned.
Logs from the Shell
> undefined
> "success"
You aren't providing a way to use the response from the api call. Convert that toa promise and then use it.
module.exports = {
apiCall: function(parameters) {
return new Promise((res, rej) => {
apiCall(
parameters,
function(err, response) {
if (err) {
rej(err);
} else {
res(response);
}
}
)
});
}
};
Then use it like so
let promise = externalModule.apiCall(parameters);

What are the down sides to wrapping promises in an object that resolves them?

I'm working on a new framework of microservices built in Node 8 and trying to simplify some of the logic required for passing Promises around between services.
I have a function I import in each service called StandardPromise which you can pass a Promise to. StandardPromise will call .then() on the promise and place the result in an object. If the promise was resolved it will be placed in the data attribute, if was rejected or threw an error then that will go in the err attribute.
The result of the above is that when a service receives a standardized promise by awaiting a call to another service, it can just check if there's anything in err and move forward with data if err is empty. This flow is significantly simpler than having .then() and .catch() blocks in every function.
I'm pretty happy with how it's turning out, and it seems to be working great, but since I haven't seen many examples of this kind of flow I want to know if there's something I'm missing that makes this a terrible idea or an antipattern or anything like that.
Here's a simplified, somewhat pseudocode example:
Service1:
const sp = require('./standardPromise');
const rp = require('request-promise-native');
function ex() {
// Wrap the Promise returned from rp as a "standardPromise"
return sp(rp.get({url: 'https://example.com'}));
}
Service2:
const Service1 = require('./Service1');
async function ex2() {
var res = await Service1.ex();
if (res.err) {
// Do error stuff
console.error(res.err);
return;
}
// Here we know res.data is our clean data
// Do whatever with res.data
return res.data;
}
standardPromise:
module.exports = function(promise) {
try {
return promise.then((data) => {
return {err: undefined, data: data};
}).catch((err) => {
return Promise.resolve({err: err, data: undefined});
});
} catch(err) {
console.error('promise_resolution_error', err);
return Promise.resolve({err: err, data: undefined});
}
}
It can just check if there's anything in err and move forward with data if err is empty. This flow is significantly simpler than having .then() and .catch() blocks in every function.
No, this is much more complicated, as you always have to check for your err. The point of promises is to not have .catch() blocks in every function, as most functions do not deal with errors. This is a significant advantage over the old nodeback pattern.
You would drop your standardPromise stuff and just write
// Service1:
const rp = require('request-promise-native');
function ex() {
return rp.get({url: 'https://example.com'});
}
// Service2:
const Service1 = require('./Service1');
async function ex2() {
try {
var data = await Service1.ex();
} catch(err) {
// Do error stuff
console.error(err);
return;
}
// Here we know data is our clean data
// Do whatever with data
return data;
}
or actually simpler with then for handling errors:
// Service2:
const Service1 = require('./Service1');
function ex2() {
return Service1.ex().then(data => {
// Here we know data is our clean data
// Do whatever with data
return data;
}, err => {
// Do error stuff
console.error(err);
});
}

Categories

Resources