Error catched by then instead of catch of Promise - React Native - javascript

I am having a problem when calling two async functions in React Native.
Here is code (I just changed the names):
getItems()
.then((response) => {
setItems(response.data);
})
.catch((err) => console.log('getItems', err));
getOtherItems()
.then((response) => {
console.log('response.data', response.data);
setOtherItems(response.data);
})
.catch((err) => console.log('getOtherItems', err));
When the first function throws an error, the error is correctly catched by the catch. But, when the second functions breaks, the error passes through then instead of catch.
The logs are like this:
getItems <Error>
response.data <Error>
Any idea why this is happening?
EDIT:
getItems and getOtherItems make an HTTP call using axios to an external service that returns an array of items.
EDIT 2:
Code for getItems and getOtherItems:
getItems() {
return axios.get('an URL');
}
getOtherItems() {
return axios.get('another URL');
}
EDIT 3:
I realized the first function throws a 500 error while the second logs a 404. So, the problem may be with how the services return the error.
EDIT 4:
It seems the problem is an error in the service. I'll let you know once it's confirmed. Thanks!

Related

JavaScript try/catch block

export const getData = async (locationId) => {
try {
return await axios.get(`/api/data/?lotion=${locationId}`);
} catch (error) {
console.log('ERROR', error);
}
};
So I have function getData where I added try/catch block.That function is called in another component in componentDidMount() and its all working if endpoint is correct but if I try to make error its not running my catch block. I mistyped my endpoint the correct one is /api/data/?location=${locationId} I have done that to get error and I get error 400 Bad Request. So the problem is that my code never run my catch block and it doesn't console.log Error.
I found similar problem on internet and they said that async/await must be added I also added that but still not working...
Any ideas?

Issue using Axios with Scryfall API

Attempting to use axios to make a get request at the following endpoint, and I keep getting errors:
When I check it using Postman and in a browser (GET request), it returns data just fine, but otherwise I can’t get a response.
This is the call I’m using, I don’t know if it’s some sort of issue with my code or with axios itself:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
console.log(JSON.stringify(res));
})
.catch((err) => {
if (err.response) {
throw new Error(`Card with name (${name}) not found!`)
}
throw new Error(`Could not complete that query!`)
})
The argument args.name is passed as part of a GraphQL resolver, and it definitely has a value, so not sure what the deal is.
Any help would be greatly appreciated!
There are a couple of problems here.
Generally it's not a good idea to throw new errors after catching the original error. As written, your code throws an additional error because the axios Promise is thrown again instead of being dealt with inside catch - so node will complain that you didn't resolve or reject the promise.
The substantive issue is the same as the one answered here except for res - the actual error is TypeError: Converting circular structure to JSON which is caused by trying to JSON.stringify the res object:
JSON doesn't accept circular objects - objects which reference themselves. JSON.stringify() will throw an error if it comes across one of these.
The request (req) object is circular by nature - Node does that.
In this case, because you just need to log it to the console, you can use the console's native stringifying and avoid using JSON
So you can fix this by changing your code to:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
if (err.response) {
console.error(`Card with name (${name}) not found!`)
} else {
console.error(`Could not complete that query!`)
}
})
If you were just using console.log for testing/as an example and actually need to stringify the data to use some other way, just make sure you're stringifying the data (which is presumably what you actually want) and not the whole res object:
axios.get(`https://api.scryfall.com/cards/named?exact=${args.name}`)
.then((res) => {
let scryfallData = JSON.stringify(res.data)
doSomethingWith(scryfallData)
})

first time getting this error Uncaught Error in Console

i am working on a ToDo list and its basically done. but i am getting this error in the console that i haven't come across yet, its preventing me to create the list (to do list)
This is the error im getting:
OPTIONS http://localhost:4000/cpds/add
net::ERR_NAME_NOT_RESOLVED
Uncaught (in promise) Error: Network Error createError.js:17
at createError (createError.js.17)
at XMLHttpRequest.handelError (xhr.js:80)
Can someone please explain what this means and how to resolve this issue.
the list prints in my console but not in my browser, then prints this error afterwards.
ERR_NAME_NOT_RESOLVED - points that system fail to resolve IP address for given hostname (http://localhost:4000/cpds/add in your case). While it is very unlikely that you are realy could not resolve address for localhost itself most probable reason is that you requesting for closed port (:4000).
In general this message say Uncaught which means that somewhere in you code when you request for "http://localhost:4000/cpds/add" form axios (it is assumtion cause you don't gave any details about your code) you have statement like
axios.get(url, { headers })
.then(data => console.log(data))
without
.catch(error => console.error(error))
so full version is
axios.get(url, { headers })
.then(data => console.log(data))
.catch(error => console.error(error))
So when request is fails due to any reason (probably error in url in you case) interpreter don't know how to overcome it (other words you should directly define function which would be called in case of error and pass it to catch method).
To ensure error is in url try to place http://localhost:4000/cpds/add to address bar of you browser, if it is realy unaccessable, browser should show you an error.
This is because one of your calls returned a rejected promise/async function, or in other words: An error that occurred calling your function.
Be careful about this. You can write yourlibrarycall.then(result => ...).catch(error => ...) But this can quickly get a pitfall. The catch clause will be called if the library call failed, but also when the .then clause failed. You'd expect the failure came from the library call, but this was fine, your code might also had a problem and the value that the variable error returns might be totally different (or undefined).
Hence i prefer having:
yourFunction = async () => {
let result;
try {
result = await yourlibrarycall // this is blocking
}
catch (error) {
// error handling only of your library call
}
// here comes your following logic
...
}
Using asnyc, your function is executed asynchronously and can now wait for the result using the keyword await. If the library call failed, it will enter the catch scope and provide you a variable with the error occurred.
This is now all the error handling and only will now only cope with the request, the following logic is then executed afterwards, getting rid of the misleading .then(...).catch(...).
If you still want to use the promise approach instead of async/await be careful to handle all the errors in the catch clause explicitly, otherwise they'll bubble up and will be catched by the catch clause, as stated above.

Jest - TypeError: response.json is not a function

We are unit testing a React-Native application (using Jest) which does various API calls using fetch.
We have mocked calls to fetch in our API call functions in order to test them. This works well so far. We also have functions that combine these API calls and operate some logic on them.
For example, here is one function that, given a token, will get the related user's first project (project[0]) and return the list of items from this project.
export async function getAllItems(token) {
try {
const response = await getCurrentUser(token); // fetch called inside
const responseJson = await response.json();
const allItemsResp = await getAllItemsFromSpecificProject(
token,
responseJson.projectIds[0],
); // fetch called inside
return await allItemsResp.json();
} catch (error) {
console.log(error);
return null;
}
}
Both functions getCurrentUser and getAllItemsFromSpecificProject are simple fetch calls and are currently mocked properly. Here one test that tries to test the getAllItems function:
it('Gets all items', async () => {
getAccessTokenMockFetch();
const token = await getAccessToken('usherbrooke#powertree.io', 'test!23');
getAllItemsMockFetch();
const items = await getAllItems(token.response.access_token);
expect(items.response.length).toEqual(3);
});
For clarity, here is how getAccessTokenMockFetch is done. getAllItemsMockFetch is almost identical (with different data in the response):
function getAccessTokenMockFetch() {
global.fetch = jest.fn().mockImplementation(() => {
promise = new Promise((resolve, reject) => {
resolve(accepted);
});
return promise;
});
}
where accepted contains the JSON content of a successful call. When we run this test, we get the following error:
TypeError: Cannot read property 'response' of null
And we console.log this one in the catch:
TypeError: response.json is not a function
which explains why response is null. It seems the json() call is not understood and I don't know how to mock it. I have done tons of research on Stack Overflow and beyond, but we have found nothing that helps me understand how to solve this issue. This might indicate that I am going the wrong way about this, which is quite possible since I'm new to JavaScript, React Native, and Jest.
One thing to try is giving it a fake json to call, like this:
const mockFetch = Promise.resolve({ json: () => Promise.resolve(accepted) });
global.fetch = jest.fn().mockImplementation(() => mockFetchPromise);

Observable - 401 causing forkJoin to error out

I am using forkJoin to make several server requests. This is a pattern I have commonly been using through out my application and it has been working great. However we just started implementing user roles which is done on the backend. I am not sure what is the best practice for implementing roles as I am mostly a front end developer, nonetheless this is the problem I have encountered:
Our application has member and admin member roles.
From each view I must make calls to the backend for both member and admin member roles regardless as roles are not determined on the frontend.
Member data is always returned in for both roles as members and admin members both have personal data.
Requests made for admin data is only returned when the user is an admin. Whenever the user does not have admin access the request returns a 401 error. This is where I am having a problem.
Whenever the call returns a 401, the error method in my subscribe method is invoked and I do not have access to any of the calls that were made including the calls associated to the member data.
In my included code within the forkJoin there are five calls passed into the method. The third and forth call only return data if the user is an admin while the rest of the calls are always returned for either member or admin.
When the user is not an admin the third call returns a 401 and the stream stops and the error handler in my subscribe method is invoked. This is obviously not what I want. I want the stream to continue so I can use the data in the _data method.
I have only been using RXJS for 6 months and am learning. Maybe I should be using a different pattern or maybe there is a way to fix this. Any help with code examples would be greatly appreciated. Below my code example I included another example of code in which I attempted to fix the problem by playing around with catch methods. It didn't work.
My View get method:
private getZone() {
this.spinner.show();
this.zonesService.getZone(this.zoneId)
.map(response => {
this.zone = response['group'];
return this.zone;
})
.flatMap(() => {
return Observable.forkJoin(
this.teamsService.getTeam(this.zone['TeamId']),
this.zonesService.getZoneAssociations(this.zone['id'], '/myDevices'),
this.zonesService.getZoneAssociations(this.zone['id'], '/devices'),
this.zonesService.getZoneAssociations(this.zone['id'], '/groupMembers'),
this.sitesService.getSite(this.zone['SiteId'])
);
})
.subscribe(
_data => {
// data handling...
},
_error => {
// error handling ...
}
);
}
My attempt to fix:
private getZone() {
this.spinner.show();
this.zonesService.getZone(this.zoneId)
.map(response => {
this.zone = response['group'];
return this.zone;
})
.flatMap(() => {
return Observable.forkJoin(
this.teamsService.getTeam(this.zone['TeamId']),
this.zonesService.getZoneAssociations(this.zone['id'], '/myDevices'),
this.zonesService.getZoneAssociations(this.zone['id'], '/devices')
.catch(error => Observable.throw(error)),
this.zonesService.getZoneAssociations(this.zone['id'], '/groupMembers')
.catch(error => Observable.throw(error)),
this.sitesService.getSite(this.zone['SiteId'])
);
})
.subscribe(
_data => {
// data handling...
},
_error => {
// error handling...
}
);
}
Returning Observable.throw will just rethrow the caught error, which will see forkJoin emit the error.
Instead, you could use Observable.of(null) to emit null and then complete, which will see forkJoin emit a null for the observable that emitted the error:
return Observable.forkJoin(
this.teamsService.getTeam(this.zone['TeamId']),
this.zonesService.getZoneAssociations(this.zone['id'], '/myDevices'),
this.zonesService.getZoneAssociations(this.zone['id'], '/devices')
.catch(error => Observable.of(null)),
this.zonesService.getZoneAssociations(this.zone['id'], '/groupMembers')
.catch(error => Observable.of(null)),
this.sitesService.getSite(this.zone['SiteId'])
);
Or, if you wanted to emit the error as a value, you could use Observable.of(error).

Categories