Jump to content

Error Handling in Fetch


gw1500se
 Share

Recommended Posts

I have the following script that does a fetch:

function requests(url) {
   return fetch(url).then(function(response) {
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }         
       return response.json();
   });
}

There is one error that is occasionally expected:

Failed to load resource: net::ERR_FILE_NOT_FOUND

I need to handle that error and return something that indicates it to an async calling function.

If I understand the code the error is coming from fetch(url) not function(response). I think I need to add a .catch somewhere to handle that error, right?

As an aside, will function(response) ever really return a false for response.ok?

Link to comment
Share on other sites

Yes, your function should be called when hitting a 404 error and response.ok would be false.  To detect if the error is a 404 vs something else, you can inspect the response.status property.

function requests(url) {
   return fetch(url).then(function(response) {
      if (response.ok){
        return response.json();
      } else if (response.status === 404){
        //Do something
      } else {
        throw new Error(`Request failed with status ${response.status}`);
      }
   });
}

 

Link to comment
Share on other sites

Is this a request to a website or is it a request for some internal file in your extension?  It might behave differently, not sure.

In any event, if it's triggering the .catch method instead of your .then method, then you probably just need to restructure things slightly.  If you return a value from the .catch, and put a .then after it then you can ignore the error.  Essentially like doing try/catch.   For example:

function requests(url){
    return fetch(url).catch(function(error){
        if (/*use error to determine if it's a is 404*/){
            return null; //Return some value to continue
        } else {
            throw error; //Otherwise forward the error
        }
    }).then(function(response){
        return response?response.json():null;
    });
}

I don't know how you'd check for the specific error you want to ignore, but if you console.log(error) and look at it's properties you can probably figure something out.

Link to comment
Share on other sites

Why not catch the "error"?

    /* Handle General Errors in Fetch */
    const handleErrors = function (response) {
        if (!response.ok) {
            throw (response.status + ' : ' + response.statusText);
        }
        return response.json();
    };

    /* Success function utilizing FETCH */
    const UISuccess = function (parsedData) {
        /* Successfully Load & No Errors */
    };

    /* If Database Table fails to load then hard code */
    const UIError = function (error) {

        console.log("Database Table did not load", error);
        
        /* Do Something like even run more code? */

    };

   /* create FETCH request */
    const createRequest = (url, succeed, fail) => {
        fetch(url)
            .then((response) => handleErrors(response))
            .then((data) => succeed(data))
            .catch((error) => fail(error));
    };

	createRequest(url, UISuccess, UIError);

 

Edited by Strider64
Link to comment
Share on other sites

I'm getting the error and catching it. I don't want the error thrown. Here is my code:

function requests(url) {
   return fetch(url).catch(function(error) {
      console.log("caught error: "+error);
   })
   .then(function(response) {
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }         
       return response.json();
   });
}

async function myExtension() {
   const data = await requests("https://worker.mturk.com/projects.json");
   for (let item of data.results) {
      console.log(item.accept_project_task_url);
      const data = await requests(item.accept_project_task_url);
      console.log(data);
      break;
   }
}

myExtension();

This is the console result:

/projects/3YATNUOYWPGCVB7NH3IDJB44X40R53/tasks/accept_random.json?ref=w_pl_prvw
projects/3YATNUOYWPGCVB7NH3IDJB44X40R53/tasks/accept_random.json?ref=w_pl_prvw:1          Failed to load resource: net::ERR_FILE_NOT_FOUND
auto_select.js:3 caught error: TypeError: Failed to fetch
auto_select.js:6 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'ok')
    at auto_select.js:6:21
    at async myExtension (auto_select.js:17:20)

 

Only the bold line is what I expected to show up so I can handle it. Is there a coding error that is causing the rest?

Link to comment
Share on other sites

If you catch the error then whatever value you return from the .catch method will be passed to your .then method as response.  Since you're not returning anything, response is undefined.

You can either check that response has a value (like I did in the example) or return a mock response object with .ok set to false.

function requests(url) {
   return fetch(url).catch(function(error) {
     console.log("caught error: "+error);
     return {ok: false};
   })
   .then(function(response) {
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }         
      return response.json();
   });
}

 

Link to comment
Share on other sites

57 minutes ago, kicken said:

If you catch the error then whatever value you return from the .catch method will be passed to your .then method as response.  Since you're not returning anything, response is undefined.

You can either check that response has a value (like I did in the example) or return a mock response object with .ok set to false.

function requests(url) {
   return fetch(url).catch(function(error) {
     console.log("caught error: "+error);
     return {ok: false};
   })
   .then(function(response) {
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }         
      return response.json();
   });
}

 

but if you handle errors first

    /* Handle General Errors in Fetch */
    const handleErrors = function (response) {
        if (!response.ok) {
            throw (response.status + ' : ' + response.statusText);
        }
        return response.json();
    };

and do this

   /* create FETCH request */
    const createRequest = (url, succeed, fail) => {
        fetch(url)
            .then((response) => handleErrors(response)) // Check for errors
            .then((data) => succeed(data))
            .catch((error) => fail(error)); // Catch the errors
    };

aren't you do the same thing with promises ?  Fetch to me can be confusing.

Link to comment
Share on other sites

4 minutes ago, Strider64 said:

Fetch to me can be confusing

There are multiple ways to deal with errors, it depends on what you need / want.  This isn't necessarily anything unique to fetch() in particular, this is just how Promises in general work (which many things make use of these days).

The approach I did allows the .then function to still run, just without a response (or the fake response) which might be handy if you have logic in there you want to perform whether the request is successful or not.

If you want to just bypass the .then function entirely if there is an error, you can put the .catch after it instead of before it.

If you don't want to do any error handling here, then exclude the .catch in this function and leave it up to the caller to add a .catch of their own to handle errors.

A quick rundown of how things work if it helps:

  1. A promise is created and returned by some function, that function then will do something in the background and either resolves (success) or rejects (error) the promise.
  2. Calling .then registers a function that will accept the resolved value of the promise and returns a new promise which will resolve with whatever the function returns
  3. Calling .catch registers a function that will accept the rejected value of the promise and returns a new promise which will resolve with whatever the function returns.
  4. Throwing an exception in either of your .then or .catch handlers will result in the next promise being rejected with what exception as the value.

So when you get a promise back from a function, can create a chain of .then/.catch processing to either simply do something with the results, or to transform the result in some way.  It can take a bit of time to get used to the syntax/logic flow, and some people just find it too confusing or too messy.  That's why async/await were created, to help bring to code back to a more traditional style and flow.  They come with their own confusion though if you don't understand how promises in general work, as such I suggest learning .then/.catch and once comfortable with that moving on to async/await if you want.

 

Link to comment
Share on other sites

Close but I'm still getting an error in the console. Maybe it doesn't matter but I can't seem to eliminate or catch this error:

 

/projects/3U8PAUGKO25K6476BGLE7U090QYNCN/tasks/accept_random.json?ref=w_pl_prvw
projects/3U8PAUGKO25K6476BGLE7U090QYNCN/tasks/accept_random.json?ref=w_pl_prvw:1          Failed to load resource: net::ERR_FILE_NOT_FOUND

 

Is that simply not possible and there is not way to suppress it. Otherwise everything seems to be working.

Link to comment
Share on other sites

The console might report the error simply because it's failed network request and thus something a developer might be interested in.  All that you should really be concerned with is if your code is working as expected or not.  A clean console log isn't really that important (or always possible).

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.