My global configuration in main.js:
http.configure(config => {
config
.withInterceptor({
response(response) {
if (response.status === 500) {
toastr.error('Contact the tech guys.', 'Something has gone wrong!');
throw response;
}
return response;
}
})
.useStandardConfiguration()
.withBaseUrl('api/blah/blah');
In my view models, I also have more handling after using http.fetch(). This is for things like using my validator to wire up error message on fields, etc.
this.http.fetch('some/route',
{
method: 'put',
body: json({some: 'data'})
})
.then(response => response.json())
.then(data => {
this.otherService.doSomeStuff(data);
})
.catch((response) => {
if(response.status !== 500)
response.json()
.then(failures => {
this.validator.handle(failures);
});
});
However, I don't really want to throw response; in my interceptor (I'm doing that now because null was being passed), and, I don't want to do a response.status !== 500 check in each view model.
Is there a way to stop the chain completely with an interceptor?
Related
The app is not rendering the login page in case the dataprovider is failing.
I have made a customized login page, using firebase as authProvider.
I'm trying to make it work so that I log in and then use the user.id provided to use a correct API -key to fetch & update data from WooCommerce site.
Everything works fine if I have predefined the user id in the dataprovider, like this
const user = async () => {await authProvider.checkAuth()};
const vendor = user.lengt > 0 ? user.uid: 'reader';
let WooCommerce = new WooCommerceAPI(wcConfig[host][vendor]);
If I plainly use the user.uid it is undefined before I log in and the login age will not be shown at all. Now what I do wonder is that why would we try to use the dataprovider before auth and how to get pass that?
After log in the vendor (used for woocommerce api) is not updated either.
WooCommerce dataProvider is self made, it does return a 401, but I'm wondering if there's something missing in the error handling.
Here's the actual code:
export default {
getList: (resource, params) => {
const search = params.filter.q;
const { page, per_page } = params.pagination;
const query = {
page: JSON.stringify(page),
per_page: JSON.stringify(per_page),
search: JSON.stringify(search)
};
let url = `${resource}/?${stringify(query)}`
if (resource === 'system_status'){
url = resource;
}
return WooCommerce.get(url, params.data)
.then((response) => {
return {
data: response.data,
total: parseInt(response.headers['x-wp-total']),
pages: parseInt(response.headers['x-wp-totalpages'])
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
getOne: (resource, params) => {
return WooCommerce.get(resource + '/' + params.id)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
update: (resource, params) => {
return WooCommerce.put(resource + '/' + params.id, params.data)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
},
create: (resource, params) => {
return WooCommerce.post(resource, params.data)
.then((response) => {
// Successful request
return {
data: response.data
};
})
.catch((error) => {
// Invalid request, for 4xx and 5xx statuses
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
return { data: error.response.data };
})
.finally(() => {
// Always executed.
});
}
}
Apparently one has to handle the configuration error.
let WooCommerce = () => {
try {
return new WooCommerceAPI(config[host][vendor]);
} catch (error) {
console.error(error)
}
}
Could've been better, but at least it works now.
i already call the axios and show using console log if it is successful or not already, However i wanted to pass the axios post response value to my vue component and display the response in my vue component in order for me to make a condition. Is there any way to do it? I try some other part but no luck. Kindly guide me.
main.vue
methods: {
onClicked() {
this.$store
.dispatch('Clickme', this.data)
.then(() => {
alert("Success");
})
.catch(() => {
alert("Error");
})
}
}
clicked.js
return new Promise((resolve, reject) => {
clicked(username, password)
.then(resp => {
console.log("---->>>> : ");
const data = resp.data.data
console.log(username, password);
console.log(resp);
console.log("statresponse.status : " + resp.data.status);
console.log("statresponse.message : " + resp.data.message);
console.log("statresponse.inside message : " + resp.data.data.message);
// console.log("USER.JS RESPONSE: " + resp.data.status);
// console.log("USER.JS RESPONSE: " + resp.data.message);
setToken(data.token)
commit('SET_TOKEN', data.token)
resolve()
})
.catch(error => {
console.log(error)
reject(error)
})
})
Try changing main.vue to:
onClicked() {
this.$store
.dispatch('Clickme', this.data)
.then((response) => {
//Do whatever you want with your response
alert("Success");
})
.catch(() => {
alert("Error");
})
}
and change clicked.js to:
resolve(resp.data.data)
This will make so the promise resolves the response data.
However if you make the http request in your store/using vuex, what you probably want to do is commit a mutation to put the response into your state - and then map the state from your component.
I am trying to return some value from this dispatch
this.$store.dispatch('setValue', this.Value)
.then(response => {
console.log(response)
});
In my vuex action I have
.catch(error => {
if (error.response.status === 412) {
return "some message"
}
});
How can I pass the error back to the .vue file where the vuex dispatch is made?
I think the correct way of doing this is to have a status property in your store.
Your status object would consist out of error, success, loading.
So if your action throw exception you can handle it like this:
catch (error) {
commit("error", `Some Message`);
}
Your error mutation would look like this:
error(state, payload) {
state.status.success = false;
state.status.loading = false;
state.status.error = payload || false;
}
Your template would just listen on the store.state.status
<div v-if="store.state.status.error">{{store.state.status.error}}</div>
I might be wrong but in my personal opinion I feel it is wrong to use actions to return stuff. Your using the store so might as well leverage it best you can.
Other extra benefits is, you can indicate to your .vue file if api is loading or when something is successful.
What I ended up doing was pretty simple. I chained the catch to my dispatch:
this.$store.dispatch('setValue', this.Value)
.then(response => {
console.log(response)
})
.catch(error => {
if (error.response.status === 412) {
return "some message"
}
});
Then I returned the Axios call from the action:
return axios({
method: 'post',
url: `/mypath,
data: mydata,
json: true,
})
This means I could deal with the returned data/errors locally where I wanted to trigger an action.
Store:
.catch(error => {
if (error.response.status === 412) {
throw error
}
});
Vue element with async method:
try{
let response = await this.$store.dispatch('setValue', this.Value)
} catch(error) {
console.log(error)
});
If I call my api function from POINT 1, fetch method inside the api method works well. When I comment it out and call the function at POINT 2 fetch method inside the addAccount() doesn't work. There is no exception, no rejection, no request on Reactotron, even I can't find request over Charles Proxy. What is the difference and what I have to know to figure it out?
I tried with RN 0.55.2 and 0.57.5
// Auth.js typical react native component
import * as api from '../actions/api';
class Auth extends Component {
// first triggered function
loginAccount(){
// api.addAccount(); // POINT 1 - this line works well if I uncomment
fetch('https://domain-a.com/login/',{
method: 'POST',
credentials: "same-origin",
headers: {
'accept-language': 'en-US;q=1',
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: encodeURIComponent(bodyParameters)
}).then((response) => {
console.log(response);
return response.json()
}).then(({ status, invalid_credentials }) => {
if(status == "ok"){
CookieManager.get('https://domain-a.com')
.then((cookies) => {
this.fetchAccountData(cookies);
})
})
}
fetchAccountData(cookies){
fetch('https://domain-a.com/'+cookies.user_id+'/info/',{
method: 'GET',
headers: {
'cookie': cookies
}
}).then((response) => {
return response.json();
})
.then(({ user, status }) => {
api.addAccount(); // POINT 2 - this line doesn't work
});
}
}
// api.js
// I repleaced fetch code with document example just to be clearify
export const addAccount = () => {
console.log("fetch begin"); // always works
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson); // won't works from point 2
})
.catch((error) =>{
console.error(error); // never runs
});
}
It looks like your first .then statement in the addAccount() function is missing a return statement. responseJson would be undefined without a proper a 'return response.json()' statement. Also adding brackets for better semantic formatting.
export const addAccount = () => {
console.log("fetch begin"); // always works
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => {
console.log(response); //test this response
return response.json();
})
.then((responseJson) => {
console.log(responseJson); // won't works from point 2
})
.catch((error) =>{
console.error(error); // never runs
});
}
If the internet connection is lost during a fetch in my react-native app I get Network request failed and the app crashes.
updateClientData() {
var cachedData = null;
AsyncStorage.getItem('cachedData').then((cachedDataString) => {
cachedData = JSON.parse(cachedDataString);
})
.done(() => {
if (cachedData) {
const base64 = require('base-64');
return fetch('https://...data.json', {
method: 'get',
headers: {
'Authorization': 'Basic '+base64.encode("..."),
}
})
.then( (response) => {
// never called:
return response.json();
})
.catch( (error) => {
//Shouldn't this catch network errors? It never gets called.
console.log('caught network error');
})
.then( (responseJSON) => {
//do something with the JSON
})
}
});
},
I would love to be able to handle this gracefully rather than have it crash. Any ideas?
For some reason, moving the AsyncStorage call out of this function made it work fine. I didn't actually need it until I had the result of the fetch anyway, so I moved it.
This works now:
updateClientData() {
const base64 = require('base-64');
return fetch(clientListURL, {
method: 'get',
headers: {
'Authorization': 'Basic '+base64.encode("..."),
}
})
.then( (response) => {
return response.json();
})
.catch( (error) => {
console.log('error...')
})
.then( (responseJSON) => {
// now do something with the JSON and the data from Async Storage
}
},