URL.fetch() fails to fail

Is it possible to retrieve the HTTP response code with URL.fetch()? Fetch() has a failure callback but it seems to only be triggered by a network level issue (e.g. bad domain name). A failed HTTP request, e.g 404 not found or 401 not authorized seems to be incorrectly calling the success callback and I can’t seem to find the status code on the response object it passes in.

This code demonstrates the issue:

u = URL.fromString("https://www.google.com")
u.fetch(ret => {console.log("1 Passed correctly.")}, ret => {console.log("1 Failed incorrectly.")})
u = URL.fromString("https://www.googllllllllllllllllllle.com/")
u.fetch(ret => {console.log("2 Passed incorrectly.")}, ret => {console.log("2 Failed correctly.")})
u = URL.fromString("https://www.google.com/invalid_path") // 404
u.fetch(ret => {console.log("3 Passed incorrectly.")}, ret => {console.log("3 Failed correctly.")})

Console output:
1 Passed correctly.
2 Failed correctly.
3 Passed incorrectly.

It is also an interesting design choice that fetch() uses callbacks but find() uses a Promise.

I’m very new to OmniJS, but as a web developer it isn’t too surprising that URL.fetch() errors for DNS issues but does not error for HTTP 4XX or 5XX responses.

First, it’s worth noting that this mirrors the behavior of XMLHttpRequest, the historical tool used to make network requests on the web.

Second, it’s not possible for the runtime to throw an error in a way that a callback function could react to. The problem is that when the HTTP response is received, the script has already completed the synchronous execution block where URL.fromString() was called. Instead, they would have to pass an object with properties that indicates an error occurred (e.g. what XMLHttpRequest does), pass an error parameter into the callback (e.g. the prevalent pattern in the Node.js ecosystem), or allow callers to provide a separate callback for error handling (e.g. what Promises do).

Third, it’s worth noting that fetch() also doesn’t reject for HTTP 4XX and 5XX responses. For both XMLHttpRequest and fetch, HTTP “errors” are not represented as JavaScript errors because the HTTP layer is behaving as expected and the response may contain useful information.

If you’d prefer to use a promise based API, it looks like you can substitute URL.fromString for URL.FetchRequest.fromString. Here’s a code sample from the docs:

var jiraBaseURL = "https://my_jira_url"
var jiraParameters = "/rest/api/2/search?jql=assignee=currentuser()…etc"
var jiraURLString = jiraBaseURL + jiraParameters
var accountName = "ACCOUNT-NAME"
var accountPassword = "ACCOUNT-PASSWORD"
var data = Data.fromString(accountName + ":" + accountPassword)
var credentials = data.toBase64()

var request = URL.FetchRequest.fromString(jiraURLString)
request.method = 'GET'
request.cache = "no-cache"
request.headers = {"Authorization": "Basic" + " " + credentials}

var requestPromise = request.fetch()

requestPromise.then(response => {
    var responseCode = response.statusCode
    if (responseCode >= 200 && responseCode < 300){
		if(response.mimeType == "application/json"){
			var responseJSON = JSON.parse(response.bodyString)
			// processing statements
		} else {
			console.error("INCORRECT MIMETYPE:", response.mimeType)
		}
    } else {
    	new Alert(String(responseCode), "An error occurred.").show()
    	console.error(JSON.stringify(response.headers))
    }
})

This is an old thread you are reviving. The FetchRequest you suggest didn’t exist when it was posted.