If getting response like this-
data: Array(0)
length: 0
How to handling the error and how to show message the no matching data found in vuejs.
First of all, you should either wrap your axios request with try/catch if using async/await, or simply use then..catch methods.
Here's a simple example
axios.get('http://api.com')
.then((response) => {
if (response.data.length === 0) { // Lets check if response contains any items
// Do Your 'no items found' logic here
console.log('No items found')
return
} else { // We have items, handle them here!
// We have some items, lets log them
console.log(response.data)
}
})
.catch((error) => {
// Catch and handle any errors here
console.log(error)
})
Related
I'm new to vue. I use interceptors for handling action responses, all easy with successful responses. But I would like to know what are the best practice to handle error responses.
I want to show a toastr with error message from response by default if there's no catch block in the action, but if there is a catch, do only catch function with no toastr shown.
Also, is it ok to handle unauthorized response making a redirect to login page directly in interceptor and what advices can be given about it?
My current interceptor looks like this:
axios.interceptors.response.use(
(response) => {
return response.data.data;
},
(error: AxiosError) => {
const data = error.response?.data;
const code = data?.code;
if (code === ErrorCodes.NEED_EMAIL_CONFIRMATION) {
router.push("email-verification").then();
} else if (code === ErrorCodes.UNAUTHORIZED) {
router.push("sign-in").then();
} else {
if (undefined !== data.error) {
toaster.error(data.error);
} else {
toaster.error(i18n.t("unexpected"));
}
}
return error;
}
);
but I don't like too many responsibilities here and I don't know how to avoid toastr show when the action has a catch function
You can control error toast notification from where you send the request, by sending an extra config.
Using axios:
axios.post('/api-name', data, {
config: {
showToast: true,
},
})
and then on axios intercept:
axios.interceptors.response.use(
response => {...},
error => {
const showTost= error.config.errorToast
if(showToast){
// show toast you can pass custom message too...<3
}
}
I have a problem that I can't solve with vue.js
I intercept queries that return an error (axios interceptor), and when it passes through this interceptor, the catch of the axios query is still taken into account.
Except that I wait for an error "error.api". which I don't receive, so it generates a console error.
Here is the code:
axios.interceptors.response.use(null, error => {
let path = '/login';
switch (error.response.status) {
case 401: path = '/login'; break;
case 404: path = '/404'; break;
}
store.commit('logout')
router.push(path);
return Promise.reject(error);
});
this error
2.js:376 Uncaught (in promise) TypeError: Cannot read property 'api' of undefined
And finally, the axios query and the error is generated by the last line (err.api[0])
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => this.$toast.error(err.api[0]))
},
I finally found a solution but very dirty, which I find repetitive for not much.
It's on each call axios, to put a condition that checks if "err" exists...
I would have preferred to be able to interact on the interceptor to have managed this in only one place.
If someone has a better solution, I'll take it !
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => { if(err) this.$toast.error(err.api[0]) })
},
I'd like to intercept all api responses with the code != 200 in my main.js with the following code, dispatch an action and after that, show a toast showing the error message. I'm using vue-resource and my interceptor is the following:
Vue.http.interceptors.push(function(request, next) {
next(function(response) {
debugger;
if (response.status != 200) {
store.dispatch("errorAction", response);
}
});
});
But the code inside the callback is never reached...
And my api call is done this way. The java controller just throws an exception with the 500 error code.
Vue.http
.get(`http://${ADDRESS}/${store.state.module}/foo/exception`)
.then(() => {}, () => {});
I'm new with Promises and probably i'm messing things, but i don't want to be passing an error callback to every single promise. And what if my request is as follows:
export function getFoo(cb) {
Vue.http
.get(`http://${ADDRESS}/${store.state.module}/foo`)
.then(
response => {
return response.json();
},
() => {}
)
.then(foos => {
cb(foos);
});
}
I would like to get rid off () => {} and use the interceptor code to be run.
I think I'd had the same issue, so I tried to look at the documentation. Well, it is very simple, you just need to do something like this:
In main.js
Vue.http.interceptors.push(function(req) {
//Here you can add some headers, if needed
req.headers.set('awesomeHeader', 'owwnt')
return function(res) {
if( res.status == 200 || res.status == 201 || res.status == 202 ){ //Here you add the status codes that you'll work with, just like my example
//Sucess response
} else {
//Every time witch an request return a status differ form the list above, you can do whatever you want, for example you can redirect the page for a new one
window.location.href = `http://localhost:8080/#`
//If you want to display a notification, you need to import the component before, and then do something like it:
Notification.success({
title: 'error',
message: 'Unauthorized request!',
offset: 100
})
}
};
})
Does it answer you question? I hope it does.
I have the following API call that is supposed to return data for each of the IDs, however for v2, instead of returning information about each order, it only displays one of the IDs. The funny thing is all orders get displayed in the console log.
app.get("/all", function (req, res) {
api.get("/v3/orders/refunds")
.then((response) => {
// console.log(response.data[0].order_id)
// console.log(response)
for (var i = 0; i < response.data.length; i++) {
// console.log(response.data[i].order_id)
let ids = response.data[i].order_id;
// console.log(ids)
api.get(`/v2/orders/${ids}`)
.then((refundedOrders) => {
bothResponses = {
v3: response,
v2: refundedOrders
}
console.log(bothResponses)
res.status(200).json(bothResponses)
})
}
})
.catch((err) => {
console.log(err)
})
})
You have created a for loop to loop through the various orders, but inside that for loop, you call:
res.status(200).json(bothResponses)
You only get one response per request so when you call that on the first iteration of the for loop, no other responses will be sent for that request again. Subsequent calls to res.json() in that for loop will be ignored. In fact, they should have been outputting a warning to your console about "headers already sent" or something like that.
Instead, you need to accumulate the results for all the ids into an array and then send one response with all the data in it.
You could use Promise.all() to accumulate all the orders into an array and notify you when it's done like this:
app.get("/all", function(req, res) {
api.get("/v3/orders/refunds").then((response) => {
// console.log(response.data[0].order_id)
// console.log(response)
return Promise.all(response.data.map(item => {
return api.get(`/v2/orders/${item.order_id}`);
})).then(refundedOrders => {
let bothResponses = {
v3: response,
v2: refundedOrders
}
console.log(bothResponses);
res.json(bothResponses);
});
}).catch((err) => {
console.log(err);
res.sendStaus(500);
})
});
List of improvements:
Use .map() to iterate the array. Return a promise for each item in the array.
Use Promise.all() to monitor the array of promises and turn it into an array of ordered results.
Create one response to the http request and send that one response when all the data is available.
Send error status when there's an error in any of the api calls.
Remove .status(200) as that is already the default so it is unnecessary.
Add error handling for 2nd API call (by returning promise to the higher level so the .catch() will catch those 2nd API call errors too).
here is what i do, and i'am not realy sure its correct :
//store
async addUser({commit}) {
try {
const {data} = await apiService.addUser()
commit('SET_USER', data)
commit('SET_NOTIFICATION', {type:'success', message: 'user successfuly created'})
} catch (error) {
commit('SET_NOTIFICATION', {type:'error', message:error})
}
}
SET_USER(state, user) {
state.users.push(user)
}
//my component:
async addUser() {
this.isLoading = true
await this.$store.dispatch('updatePatient', this.form)
this.isLoading = false
}
is it legit ?
sometimes i think i would need more logic inside my component depending on the succes or rejected api request. Should i put all the logic in my actions ? like i do at the moment ?
Maybe should I add a status state for each actions, for example :
state {
users: []
postUserSuccess: null
postUserError: false
updateUserSuccess: null
updateUserError: false
// ...
}
and do what i want in the component with a computed property mapped to the store ?
What do you think ?
I don't know if it's a best practice but I let the components the exception handling. That method has its pros (you don't have to pollute the state with error management) and cons (you have to repeat the error management code for every action call).
All service calls will be made in actions
The state will only be set in mutations.
All service calls will return a promise with a resolve(data to load in the state) and a reject(message errors to present).
There will be an interceptor to reject the response in case there's a custom error (here you can put if the response has an error prop reject the response and send as an error the error prop, now you don't have to deconstruct the response in the action).
I'm going to give you a simplified example (I use axios, you can learn how to do it with the library that you use).
Actions in Vuex are asynchronous. So you don't need to try/catch them.
ApiService - Add User
const addUser = () => {
return new Promise((resolve, reject) => {
axios
.post(url, user)
.then(response => resolve(response.data))
.catch(error => reject(error));
});
};
store
async addUser({commit}) {
const data = await apiService.addUser();
commit('SET_USER', data);
return data;
}
if the promise in apiService.addUser is resolved the commit is going to be made if is rejected axios will return the promise and you can catch the error in the component that calls the action.
Component
async addUser() {
this.isLoading = true;
try {
await this.$store.dispatch('updatePatient', this.form);
} catch (error) {
// here goes the code to display the error or do x if there is an error,
// sometimes I store an errors array in the data of the component other times I do x logic
}
this.isLoading = false;
}
State
Your state will be cleaner now that you don't need to store those errors there.
state {
users: []
}