Vue: Best practices for handling multiple API calls - javascript

So I found myself making more than one API call in my vuex action and this let me to wonder what would be the best way to hanfle this situatons, the best practices for multiple API calls, let's begin with the code I have.
I have an action where I gather all posts and all post categories from different API endpoints (laravel for backend), I'm sure there's have to be a better way t hanfle this than how I'm doing it:
fetchAllPosts ({ commit }) {
commit( 'SET_LOAD_STATUS', 1);
axios.get('/posts')
.then((response) => {
commit('FETCH_ALL_POSTS', response.data.posts )
commit( 'SET_LOAD_STATUS', 2 );
},
(error) => {
console.log(error);
commit( 'SET_LOAD_STATUS', 3 );
})
axios.get('/postcategories')
.then((response) => {
commit('FETCH_ALL_POSTCATEGORIES', response.data.postcategories )
commit( 'SET_LOAD_STATUS', 2 );
},
(error) => {
console.log(error);
commit( 'SET_LOAD_STATUS', 3 );
})
},
First issue with my approach that I can think of is if the first API call fails but the second succeeds I will get a load status of 2 (2 equals success here) !
I only want to procced with the commits if BOTH the first and second API call correctly fetch the data, please help someone who is learning.

I think you may want to read about promises.
On your example you are using Axios, which is a Promise based HTTP Client and that's great.
With Promises you can do several requests, and when all requests are successful you can THEN execute code.
With Axios you can do that with .all like this:
axios.all([getPosts(), getPostCategories()])
.then(axios.spread(function (posts, categories) {
// Both requests are now complete
}));

axios.all([
axios.get(firstUrl),
axios.get(secondUrl)
])
.then(axios.spread(function (response1, response2) {
//response1 is the result of first call
//response2 is the result of second call
}))
.catch(function (error) {
});
Note about catch(): It is called on the first failing request omitting the rest of the calls. So if the first call fails, catch() is called without even making the second request.

Related

I'm currently making 3 GET requests for JSON files using Axios, are they loaded simultaneously or one after another?

The application that I'm making loads 3 JSON files in order to get information about a game's characters, spell and more. Currently I have 3 functions that use axios to make GET requests and then store the responses, however, I'm wondering if I'm slowing my load time because frankly I'm not sure if these JSON files are loaded simultaneously or one after another. Each file takes about 45 ms to load so if they're being loaded one after another, I'm looking at around 135 ms load time and I'm not liking it.
Currently I've tried 2 ways but frankly I don't see a difference in the loading time in chrome's network tab. If you're wondering, the functions are located in my Vue.js Vuex store and the calls are executed in App.vue mounted hook.
The first way uses 3 separate functions and each makes its own GET request. Then these functions are called one after another.
The call:
this.$store.dispatch('getChampions')
this.$store.dispatch('getSummonerSpells')
this.$store.dispatch('getSummonerRunes')
The functions:
getChampions({commit, state}){
axios.get("https://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/champion.json")
.then((response) => {
commit('champions', {
champions: response.data.data
})
})
.catch(function (error) {
console.log(error);
})
},
getSummonerSpells({commit, state}){
axios.get("http://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/summoner.json")
.then((response) => {
commit('summonerSpells', {
summonerSpells: response.data.data
})
})
.catch(function (error) {
console.log(error);
})
},
getSummonerRunes({commit, state}){
axios.get("https://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/runesReforged.json")
.then((response) => {
commit('summonerRunes', {
summonerRunes: response.data
})
})
.catch(function (error) {
console.log(error);
})
}
And using the second way, I have 1 function like this:
The call:
this.$store.dispatch('getRequirements')
The function:
getRequirements({commit, state}){
axios.all([
axios.get('https://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/champion.json'),
axios.get('http://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/summoner.json'),
axios.get('https://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/runesReforged.json')
])
.then(axios.spread((response1, response2, response3) => {
commit('champions', {
champions: response1.data.data
})
commit('summonerSpells', {
summonerSpells: response2.data.data
})
commit('summonerRunes', {
summonerRunes: response3.data
})
}))
}
You're executing the requests in parallel so your browser will attempt to execute them simultaneously. Whether or not it does this is up the browser.
You can use your browser's Network console timing column (aka Waterfall in Chrome) to see what's going on.
If your question is
"is there a difference between these?"
the answer is "no" as far as timing goes.
If you start running into errors with any particular request, your first option is more robust since axios.all will reject the promise if any fail.
If you want to speed this up, you could create a service that combines the three results in to one so you're only making a single request. Then throw in a cache for an extra speed-up.
When all requests are complete, you’ll receive an array containing the response objects in the same order they were sent. Commit() is called only after both of your requests are completed.

How can I tell when a loop is done.using JavaScript and Vue and AXIOS

I have a dataGrid from Syncfusion and I have a column of checkboxes. When I press a button the code reads all of the selected rows creates an array and loops until the process is ended.
this.selectedRecords = this.$refs.grid.ej2Instances.getSelectedRecords();
this.selectedRecords.forEach(function(arg, index) {
call HTTP API request. with AXIOS
get the return values and store it to the database
}
I could have 100+ rows selected and I need to be able to tell when all of the API calls are finished.
I have slowed down my calls so I only have a maximum of 10 calls per second using
axios.interceptors.request.use(
function(config) {
setTimeout(console.log("here request interceptor"), 100);
return config;
},
function(error) {
return Promise.reject(error);
}
);
And I have tried
if (self.selectedRecords.length - 1 === index) {
alert("Done");
}
but since there is not a guarantee that the rows are processed in order it can call "Done" too early.
I hope I've given you enough code to understand my problem without giving you too much to make it sloppy.
If I've understood correctly then you should just need to gather up the promises in an array and then use Promise.all to wait for them to all complete:
var requests = this.selectedRecords.map(function(arg, index) {
return axios.get(/* request details here */);
});
Promise.all(requests).then(function() {
console.log('Done')
});
If you need to process the individual requests using a then that's fine, just chain it on the end of the axios.get call:
return axios.get(/* request details here */)
.then(function(response) {
// Handle response
})
Update:
Request interceptors can return promises, which will be necessary if you want to hold up the execution of the request:
http.interceptors.request.use(function (config) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(config)
}, 5000)
})
})
Note that the example above is not performing proper throttling, it's merely delaying the request. It is purely to illustrate how promises can be used with interceptors. You haven't included the real interceptor in the question so I can't be more specific.

Data part of Response is a long script instead of desired json object

I am building a web app using laravel and vuejs. I have made a axios get request to get a list of users .
I am getting a Promise object, and from what i have read. Reason for getting a promise object is because it's an async request.
I have tried .then() to get data part of the response. But i am getting a huge script instead of desired data.
axios......then(function(response){
console.log(response.data);
})
Initially what i did was
var res = axios.get('/allUsers');
console.log(res)
That time i came to know about promise object and read about.
When i checked network in dev tools, status code is 200 and i can see list of users. So i guess my request is successfully completed.
What should be done to get the list of the users. That list i will be using to update my UI.
Depending on what you're getting back for data there are a few ways to handle this. You may need to convert the data after the you get receive the response.
axios.get('some_url')
.then(res => res.json())
.then(data => {
// do something with the data
}).catch(err) {
conosole.error(err);
}
if you're seeing the data come through properly in the response and you're getting what you need without doing that then just do
axios.get('some url').then(res => {
// do something in here with the data here
})
also make sure you're getting back json if that's what you're looking for. check your response to see if its html or json because they can be handled a bit differently
as an "Edit" you could also handle this with async await so you dont end up in callback hell
async function fetchData() {
try {
const res = await axios.get('some url');
// next step might not be necessary
const data = await res.json();
// do something with the data
console.log(data); // if converting it was necessary
console.log(res); // if not converting
} catch (err) {
console.error(err);
}
}

Redirect/ Routing issues in React and Express

I am creating a flight search app that makes external api calls. The data will be reorganized and returned in search results component.
On submit, the data is sent to express and takes about 10 seconds or more to complete all the api calls.
I think I need a loader at some point for during the delay of api calls, but also I am unsure of how to send/render the data.
As it stands, I have two pages home.js- '/' where i make the search and is sent to the server side, and prices.js- '/search' which when loaded fetches the data from the json file. but i do not have them connected
Both files work but I need to connect them. When I press submit, the user inputs are sent to server and the api calls are made but in order to see the results i have to manually refresh localhost:3000/search.
In express app after all the api calls, I tried res.redirect method, however the error given was setting the headers after sent to the client.
In react, I tried after submitting, to redirect to the search page. However I could not get it to redirect and also as soon as the /search page is called, it fetches the data from the file. This will happen before the api has finished writing to file and therefore the previous search results will render.
--in app.js
setTimeout(() => {
Promise.all([promise, promise2]).then(values => {
return res.redirect('http://localhost:3000/search');
});
}, 25000);
I had to wrap the api calls in promises so it will only redirect after all is written to file.
(in react prices.js)
componentDidMount() {
fetch('/search')
.then(res => {
return res.json()
})
.then(res => {
console.log(res.toString());
this.setState({flightData: res});
})
.catch(error => console.log(error));
}
home.js
home.js
```
onChange = (e) => {
this.setState({
originOne: e.target.value, originTwo: e.target.value});
};
onSubmit = (e) => {
e.preventDefault();
const { originOne, originTwo ,redirectToResult} = this.state;
};
```
app.js - I have all the functions calling each other in a waterfall style ( probably not the best way I know)
app.post('/', function getOrigins(req,res) {
var OrigOne;
var OrigTwo;
....
function IataCodeSearchOrg1(res, OrigOne, OrigTwo) {
...
findPrices(res,A,B)
}
function findPrices(res, A, B) {
promise = new Promise(function (resolve) {
...
}
}
All the methods are called within eachother. The api calls are in a loop and after each iteration they are written to the json file.
All these functions are in the app.post method and i tried to res.redirect but it did not work.
EDIT:
You can't redirect server-side from an XHR request. You would need to redirect client-side.
e.g.
componentDidMount() {
fetch('/search')
.then(res => res.json())
...
.then(() => window.location = '/myredirecturl')
}

How to use the fetch api method on Open Weather API

I'm trying to use the fetch method to display the current weather on a website. However, I keep getting an error stating that res is not defined. What do I need to do?
fetch('https://api.openweathermap.org/data').then(res => {
return res.json();
}).then(function(myJson) {
console.log(res.coord);
});
Note: The API call has been edited to ensure privacy
The problem is that you're using different parameter names in your functions. In your first function, you're using res:
.then(res => {
But in your second, you're using myJSON:
.then(function(myJson) {
Changing your code to this would fix your problem:
fetch('https://api.openweathermap.org/data').then(res => {
return res.json();
}).then(function(res) {
console.log(res.coord);
});

Categories

Resources