I am doing api calls with axios on express. I have an external API controller that has different functions to call and fetch data from the IGDB api.
I have a gameController.js that will build a finalized JSON object using the different data fetched from the different calls.
this is my gameController.js
const externalApiController = require("./externalApiController");
exports.getGames = async (req, res) => {
var initialGameResult = await externalApiController.getGames(
req.body.searchInput
);
await initialGameResult.forEach(async (game) => {
if (game.cover) {
const cover = await externalApiController.getCover(game.cover);
console.log(cover[0]);
// >>>>>>>>>>>>>>>>>>>
game.cover = cover[0]; // MY ISSUE IS HERE. IT IS NOT CHANGING
// >>>>>>>>>>>>>>>>>>>
}
});
res.send(initialGameResult); //SEND THE UNCHANGED DATA
};
This is my externalApiController.js
var axios = require("axios");
require("dotenv").config();
exports.getGames = async (searchInput) => {
var data = `fields id,name,cover,platforms,category,genres,collection ; search "${searchInput}"; limit 5;`;
var config = {
method: "post",
url: "https://api.igdb.com/v4/games",
headers: {
"Client-ID": process.env.CLIENT_ID,
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
"Content-Type": "text/plain",
},
data: data,
};
const result = await axios(config);
// console.log(result.data);
return result.data;
};
exports.getCover = async (id) => {
var data = `fields id, url; where id = ${id};`;
var config = {
method: "post",
url: "https://api.igdb.com/v4/covers",
headers: {
"Client-ID": process.env.CLIENT_ID,
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
"Content-Type": "text/plain",
},
data: data,
};
const result = await axios(config);
// console.log(result.data);
return result.data;
};
Basically this is the data that I get from the initial request. It is correct. But as seen in the picture, the cover is an ID value. I need to fetch another API request using that value to get the image URL. It works fine in the foreach line. When i log it i get this.
However, it does not change in this line: game.cover = cover[0];
I need the data to change from:
{
"id": 110248,
"category": 0,
"cover": 225254,
"genres": [
31,
32
],
"name": "Stray",
"platforms": [
6,
48,
167
]
},
to:
{
"id": 110248,
"category": 0,
"cover": {
id: whatever_id_it_is,
url: whatever_url_it_is
},
"genres": [
31,
32
],
"name": "Stray",
"platforms": [
6,
48,
167
]
},
Also, I am not quite sure I am using the async and await correctly.
CodePudding user response:
The problem is in the .forEach(async (game)
part. When you await result of .forEach
, it will not wait for all promises to finish executing. .forEach
returns void
so it merely iterates over array elements and sends the promises to event loop.
The trick is to change .forEach
to .map
and pipe that to Promise.all
to ensure your promises finish executing.
Change from:
const externalApiController = require("./externalApiController");
exports.getGames = async (req, res) => {
var initialGameResult = await externalApiController.getGames(req.body.searchInput);
await initialGameResult.forEach(async (game) => {
if (game.cover) {
const cover = await externalApiController.getCover(game.cover);
console.log(cover[0]);
// >>>>>>>>>>>>>>>>>>>
game.cover = cover[0];
// MY ISSUE IS HERE. IT IS NOT CHANGING
// >>>>>>>>>>>>>>>>>>>
}
});
res.send(initialGameResult); // SEND THE UNCHANGED DATA
};
To:
const externalApiController = require("./externalApiController");
exports.getGames = async (req, res) => {
var initialGameResult = await externalApiController.getGames(req.body.searchInput);
const modifiedGameResult = await Promise.all(initialGameResult.map(async (game) => {
if (game.cover) {
const cover = await externalApiController.getCover(game.cover);
console.log(cover[0]);
game.cover = cover[0];
}
return game;
}));
res.send(modifiedGameResult);
};