I use react + react-router + redux. I would like to create a global thing for handling all the errors thrown in the app. Is it possible to catch also API call errors and 401 statuses?
I thoung about something like this in Root.jsx:
window.addEventListener("error", (e) => {});
It works for critical errors which I can log. But what if I want to serve some API errors?
For example: I want to save some grid data, but server thrown an error that 3 of 10 given rows weren't saved (I know it's a common problem and it should be resolved using transactions, but I use Mongo here :P). Now I want to show a simple dialog for a user which displays error message and 3 rows that weren't saved. What if I don't have permissions and the server throws 401 status code? Probably I would like to redirect user to index or login page.
This is some hipothetical example, because I want to simplify the thing I'm currently implementing.
I'm new in React, so I don't know the solutions for now, but if I programmed same thing in Angular, I would use Angular's HTTP Interceptors to solve my problem. I guess I need something similar here (or maybe it's some common solution for this?).
[EDIT]
Hmm. It seems I have found something that solves my problem: fetch-intercept
Anyway, do you know other solutions?
I'm assuming you're using ajax calls to access your API;
I would create a simple ajax wrapper that looks something like this;
AjaxWrapper = function(options){
return $.ajax($.extend({}, options, {
error: function (jqXHR, textStatus, errorThrown){
if(jqXHR.status === 401){
browserHistory.push('/unauthorized_route_handler');
}
options.error(jqXHR, textStatus, errorThrown);
}
}))
}
Then you can simply use this wrapper to call your api, passing in an options object as you normally would to $.ajax. Update the section within the jqXHR === 401 as needed, or add handlers for 403 & 500 as well.
Related
I am trying to call an API that is given to me. First, I did not understand the question. The API given to me looks like 'test.com/a/b/c/d/d' and it also says: callback parameter name: 'jsonp'. I tried things like adding ?callback='jsonp' at the end of the API and other few things. I am trying to call this API and display the result. I am using React on CodeSandBox and I used the fetch() function to make this call. I keep getting error saying it failed. The API is correct but I just don't understand how I add that callback parameter. I have fetched other JSON based APIs before but this time I am doing something wrong, especially withe this JSONP things. Please help.
Edit** When I put that API in the browser, I do get actual data back. But it in this format /**/invalidCallbackFunctionName([ {DUMMY_DATA1}, {DUMMY_DATA2},.....]) So clearly the API works, it's just that the way I am calling it and the way JSONP works, I am missing something in the code.
Turns out I was not using the right package and the correct way. Here is what works:
import fetchJsonp from "fetch-jsonp";
fetchJsonp("https:/www.a.com/b/c/d", {
jsonpCallback: "jsonp"
})
.then((res) => res.json())
.then((data) => console.log(data));
I am trying to decide what to do to handle errors in my chat application using Socket.io and react. I can successfully get a 'connect_error' error so I can do something inside the socket.on('connect_error', ()=> //Do something) but I am having trouble getting any other type of error. I can't think of a scenario where I can modify the app or do something specific to trigger the socket.on('error', ()=> //Do something). Does anybody have an idea?
The 'error' event is not a specific one. It's by design, so ANY error event will trigger it. What you can do is console.log it.
So now, anytime you'll be able trigger any error (Which is what you want) you'll see its description, then you can google it and then write a more specific code to handle it.
If you can't trigger any errors no matter what you do, it's not a bad thing since it means things works correctly.
socket.on('error', (error) => {
console.log(error);
});
I'm trying to test clicking a button on a registration app to make sure that the page correctly navigates to the right page.
When I console.log out response in the code it returns an array that looks like this
[undefined, null]
However when I take a screenshot of the page or check the url, the click and navigation worked. It is on the correct page.
I don't understand why this is returning undefined/null. Also, I could not figure out how to test which function was being called when you click on the button.
I wanted to be able to see the actual function that is being called.
I'm using AngularJS 1.6, Mocha, Puppeteer 1.11, and Node 6.4.0
I'm also a junior dev so it could be something simple that I just didn't understand, please help!
it('should rederict to guest_sms_code state when clicking \'I have a guest code\'', async (function () {
var response = await (Promise.all([
page.waitForNavigation({waitUntil: 'domcontentloaded'}),
page.click('[ng-click="enterSmsCode()"]'),
]));
var url = await (page.url());
if (url.indexOf('guest_sms_code') === -1) {
assert.ok(false, 'The URL does not contain \'guest_sms_code\'')
}
}))
I'm not convinced that you can tell which method is called from a UI test. That's something that a JavaScript unit test can prove using, say, something like Mocha or Jest to test your codes behaviour. However an automated UI test, from my experience, won't tell you that. After all, you're trying to hide the inner workings of your app from an external user, right?
As for why the Promise.all([]) call is returning [undefined, null], well I can at least help you with that.
Firstly, you should have a look at the API documentation for both methods you've invoked in your test:
waitForNavigation docs: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions
click docs: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageclickselector-options
In the case of waitForNavigation the response actually returns a Promise which may or may not have a Response value. Whether any data is returned with that Response is dependent on the navigation that occurs in the UI. In your case, you're seeing that undefined value in your array to indicate that there has not been any Response data returned from the navigation.
For the click method, this also just returns a resolved or rejected Promise with no data of any kind returned. So, naturally, you've no actual value returned here at all hence the null value being pushed to the array.
I would like to have a two part submit strategy for my redux-form. First, the user called submit on the form which calls a validation method. The response might have some warnings. I want the user to see the warnings, if any, and optionally continue with another submit that will be a real POST to the server rest api.
If there are no warnings, I would like the component to submit automatically. I am trying to kick this off from the componentWillReceiveProps method.
The problem is that nextProps.handleSubmit(this.doSubmit2of2); does not call this.doSubmit2of2. Execution just steps over that call.
componentWillReceiveProps(nextProps) {
//boolean that indicates validation just occured against the server
if (nextProps.storeWithValidation) {
//the user hit submit, first it was validated, if no issues, go ahead and try to create
if (nextProps.storeValidationOk) {
//fire off create store
nextProps.handleSubmit(this.doSubmit2of2);
}
else {
//there are validation issues of some kind, let the user see them
//do nothing here and let the render method do its thing with the props
}
}
}
I have found the discussion here: https://github.com/erikras/redux-form/issues/67, but in my case the submit is happening as result of a particular server response. Also, I realize that there are validation features of redux-form. Am I designing too far outside of the intended framework convention?
Also, I have thought of redesigning my server api, but I would like to know how far I can go with this current approach of automatically resubmitting after a response from the server.
From what I understand you want to submit the form remotely after a response from the server. You can create a remote submit following this example from the docs. Then you can dispatch(submit('yourFormName')) whenever you want to as many times as you want to.
I'm trying to figure out the best way to hide/show the loading indicator when I'm doing a request.
I have a:
LoadingAction to emmit an event to show/hide the loading indicator.
LoadingStore to hold the loading information (show/hide).
loading.jsx: the loading indicator component.
I tried different things to do that in the "flux way":
good: call a LoadingAction.showLoading() before the request and LoadingAction.hideLoading() when the response arrives.
bad: call a LoadingAction.showLoading() in each view that call an action (that made a request) and LoadingAction.hideLoading() when my callback is called from the Store.
ugly: I tried to change the LoadingStore directly with a setter method (what is not the right solution...) when I made the request and receive the response.
But, except for the last try (the "ugly"), I always receive the error dispatch in the middle of a dispatch.
I'm aware that what this means but I can't think in another strategy.
I don't want to use setTimeout function to resolve this problem. This is not the right solution.
Thanks!
After some time, we end up with the solution described here. The approach was very different than my original idea: each component take cares about the loading, like this:
render: function(){
// while loading
if (!this.state.data){
return <Loader/>
}
// loaded, you can use this.state.data here
return <div>...</div>
}
But, we have problems when an API return an error. How the component can remove the <Loader /> in this case?
Well, each component with need to register and listen (we use Flux) the dispatch from our promise based HTTP client (Axios). Like this:
componentDidMount: function(){
LoaderStore.addChangeListenerEsconderLoading(this.stopLoading);
},
componentWillUnmount:function(){
LoaderStore.removeChangeListenerEsconderLoading(this.stopLoading);
},
And this (using Axios):
request(options)
.then(function(response){
success && success(response.data);
})
.catch(function (error) {
LoaderAction.hideLoading();
}