How to reliably distinguish fetch api rejects? - javascript

Is there a clearly defined guide on how to check on what a fetch call might reject with?
I'm developing an application similar to Postman (or any other api explorer), but without the electron shell, which means I have to rely on what's available in the browser. I would like to clearly distinguish what exactly went wrong when fetch rejects.
But browsers seem to reject with completely different messages, for even the most basic stuff. Relying on the error being an Error or TypeError is not very useful in itself.
For example with my currently installed browsers fetching a non existing endpoint will result in
Chrome - TypeError: Failed to fetch
Firefox - TypeError: NetworkError when attempting to fetch resource.
Safari - TypeError: Type error
Without knowing what other error types there might be, it's duck typing on a whole new level.
So my question is: how exactly could errors be reliably distinguished? Is there any library that "standardizes" errors?
I need to be able to tell the user, that "Your endpoint doesn't exists or the network is down" or "You provided wrong headers, which are wrong for this and that reason".
Update
To be clear, with a code example:
fetch('...some url...', { /* some args */ })
.then((response) => {
// I'm good here, it's clearly documented
})
.catch((error) => {
// How do I figure out what EXACTLY went wrong here?
})

Related

Google Firebase httpsCallable raising net::ERR_NAME_NOT_RESOLVED

I am running into net::ERR_NAME_NOT_RESOLVED when calling the API of my firebase project. I have tried using multiple devices, two internet connections, a VPN, Linux, macOS, Windows 11 to rule out any errors caused by my devices. When navigating to the API link on my browser it does not timeout, and I am provided with a response. The issue seems to be when using the httpsCallable function provided by Firebase. No logs of the function being called are present on firebase outside of navigating to it in a browser.
Here is my code:
const functions = firebase.functions
console.log(functions)
const loginWithCode = httpsCallable(functions, 'loginWithCode')
loginWithCode(loginPayload)
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log("ERROR CAUGHT HERE")
console.log(error)
});
The output from my browser console:
service.ts:206 POST https://us-central1-%22crowd-pleaser-75fd7%22%2C.cloudfunctions.net/loginWithCode net::ERR_NAME_NOT_RESOLVED
App.tsx:79 ERROR CAUGHT HERE
App.tsx:80 FirebaseError: internal
The result from directly inputting the link on the firebase web interface:
{"error":{"message":"Bad Request","status":"INVALID_ARGUMENT"}}
Is there something I am missing that is creating this issue? I have scoured the internet, and StackOverflow looking for an answer, and all solutions provided have not worked. The method implemented is exactly how it is done on the Firebase docs here
Edit: It seems like the link to which my post request is being sent is formatted oddly. Maybe this could be the issue? I can't figure out why it's formatted this way though.
I found a solution to the problem. My speculation in my edit was correct, the URL to which the post request was being sent by httpsCallable was formatted incorrectly. I am unsure as to why it was being formatted this way, however, the quick solution is to set the customDomain class attribute of the object returned by getFunctions to the correct domain. In my case this was done by doing:
functions.customDomain = functions.customDomain = 'https://us-central1-crowd-pleaser-75fd7.cloudfunctions.net'
The variable 'functions' in the code above is the class attribute returned from the method getFunctions provided by Firebase
The Thing
While I'm not an expert on Firebase the problem is that you're making a wrong HTTP request with loginWithCode(loginPayload), there is nothing wrong with your code that I can see at least.
By the way, you're using:
const loginWithCode = httpsCallable(functions, 'loginWithCode')
rather than a simple const loginWithCode = httpsCallable('addMessage')
as described here: Google FireBase Docs
And then, making a loginWithCode({ text: messageText })
Also, as you can see here: Google Firebase Docs:firebase.functions.HttpsCallable
You will be able to pass any type of data to the HttpsCallable function, so we end at the start point: you're making a wrong HTTP request.
As described in the HTTP answer the error is: net::ERR_NAME_NOT_RESOLVED this happens when a DNS request cannot be resolved, then a domain doesn't exists so this all leads to the thing that there is no way to send the HTTP request since there is not a route in the internet that was found to send it.
The Problem:
While decoding the url that you're making the HTTP request
service.ts:206 POST https://us-central1-%22crowd-pleaser-75fd7%22%2C.cloudfunctions.net/loginWithCode net::ERR_NAME_NOT_RESOLVED
App.tsx:79 ERROR CAUGHT HERE
App.tsx:80 FirebaseError: internal
You will find that you're sending the HTTP request to:
https://us-central1-"crowd-pleaser-75fd7",.cloudfunctions.net/loginWithCode
As you can see, you will find that when making the HTTP request it will be a problem: since you cannot put "crowd-pleaser-75fd7", in the URL to make the HTTP request. That is generating the error net::ERR_NAME_NOT_RESOLVED
I'm not sure what exactly are you trying to do, but I think that the correct URL to the HTTP request should be:
https://us-central1-crowd-pleaser-75fd7.cloudfunctions.net/loginWithCode
With this URL the HTTP request must pass, at least. And I suggest then check the loginPayload in order to fix this.

Best way to handle chrome.runtime.lastError

as you may all-ready know lastError is a global variable or property from chrome.runtime API used for determining if some error happened during the chrome API call execution.
It is defined only when there was an error, if the API call is OK it won't be defined. The error can be triggered from multiple reasons eg. bad API call due to missing or wrong parameter type, or it can be caused by user interaction, eg. the user rejects permission granting by pressing the "cancel" button.
Chrome has unified it's error handling by using this variable for error reporting across their API's instead of returning an error argument. Due to it's API's async nature Chrome makes an additional check that validates if chrome.runtime.lastError is checked/handled in the callback function from the extension code, if not it throws the famous Unchecked runtime.lastError
You can quickly get the error message by checking chrome.runtime.lastError.message and display it to the user, and all of this is great for most use cases, but I wouldn't write this question if that were my case.
So what happens when you need to implement some additional code logic based on the error result. Let's take launchWebAuthFlow for an example, for the sake of simplicity of the question, I will focus only on the two possible outcomes/errors that can happen:
User interaction required. thrown when API call with bad argument value is made, in this case interactive = false
The user did not approve access. happens when the user closes the authentication window
So my question is, what will be the best way to implement additional logic based on the error?
Is a comparison of chrome.runtime.lastError.message the only way to do it, and if so, is it safe considering that the user browser language might be different than English.
What's your opinion, should Chromium dev team implement: chrome.runtime.lastError.code?

How do I handle JavaScript Fetch errors?

If a fetch call fails in Chrome, then the only error details that I get back is
TypeError: Failed to fetch
How do I display an informative error message to the end user in this case?
Specifically:
Is it possible to get any details about why fetch failed?
For example, if the server crashed, Chrome DevTools might log a console message of net:ERR_EMPTY_RESPONSE, but there appears to be no way to access this from JavaScript.
As far as I can tell, the answer is no; I assume this is for security reasons, to avoid letting malicious JS find out which sites are and aren't accessible by inspecting error messages.
Is it possible to distinguish fetch errors from other TypeErrors?
If I can't get error details, I'd like to at least replace the horribly vague "Failed to fetch" with an informative "Failed to access the web site; please try again later" message, and I'd like to do this without any risk of displaying that message for other TypeErrors.
The only solution I've found here is to check the actual message to see if it's "Failed to fetch". This is obviously browser-specific; it works in Chrome, it seems like it will work in any user language of Chrome, and other browsers would need their own testing and handling.
It seems likely that there aren't any more details for networking/permission/input problems.
Is it possible to distinguish fetch errors from other TypeErrors?
Yes, you just need to catch only the the errors from the fetch call:
fetch(…)
.catch(err => new FetchError(err))
.…
class FetchError extends Error {
constructor(orig) {
super();
this.message = "fetch error";
this.details = orig;
}
}

Catch all errors on React 15.3.1

I need catch all javascript error that happen on client browser to send to Rollbar. I tried a lot of solutions like window.addEventListener and overwrite console.error method but none of the worked for me.
Ajax errors I already get, like the jqXHR on image, but it have less information on must time.
But the message above (in red) I cannot.
How to really get all browser erros messages with React?
I don't think the error you're seeing has anything to do with React, it's thrown by your browser because your script is trying to make a cross domain request.
Have a look at this for more details:
How does Access-Control-Allow-Origin header work?
I think it's not really possible to catch all browser errors in the one place, and it is not a problem of React.
For example, if you want to catch all API errors, the basic technique is to wrap all your API calls to simple function like:
/**
* #returns Promise
*/
export default function httpRequest(type, path, params, headers) {
return someHttpLibrary.request(type, path, params, headers)
catch((error) => {
logTheStuff(error);
});
}
And you should call that function instead of directly requests. Also, the additional achieves of that technique, that you'll be able to log all requests and change library in one place if you'll need it ;D
About other errors, for example errors in Rendering or logic errors, Sentry team wrote nice article about handling errors:
https://blog.getsentry.com/2016/01/04/client-javascript-reporting-window-onerror.html
And also, Sentry is very nice tool to handle React errors: https://getsentry.com/for/react/

How to hide error message in angularjs http request?

I have get a request from an API, some times I would get the EXIF information, but sometimes I will get error message {"error":"no exif data"} How can I hide this error message.
In chrome, the error is 400 (Bad Request)
$http.get(res.getQNUrl(domain, key, "exif"))
.success(function(data){
$scope.imageExifMap[key] = data
}).error(function(data,status,headers,config){})
The error message you mentioned above is browser specific. It is a browser logging functionality.
Well there is a workaround(not a solution since its not a problem) for it. I would not recommend it since its a built-in browser functionality you are trying to suppress from doing the task it is meant to do, but if that is what you want then here are couple of ways to achieve it.
Using a regular expression filter like so
^(?!.* 404 \(Not Found\))(?!.*[file name])
Using a Log filter like so
I have not explained it much because there is already an SO question that explains these in detail.
Please refer this SO for detailed explanation regarding the above mentioned workarounds.

Categories