panzerdp / dmitripavlutin.com-comments

7 stars 0 forks source link

/javascript-fetch-async-await/ #83

Open panzerdp opened 3 years ago

panzerdp commented 3 years ago

Written on 09/11/2020 07:17:46

URL: https://dmitripavlutin.com/javascript-fetch-async-await/

neillindberg commented 3 years ago

bows const result = *await* fetch(... saved my day!

neillindberg commented 3 years ago

Ah! I cannot edit. But, thanks for actually the await with the call to result.json()

panzerdp commented 3 years ago

Ah! I cannot edit. But, thanks for actually the await with the call to result.json()

You're welcome @neillindberg. It was a surprise for me too that result.json() returns a promise!

By the way, you can edit your comment on GitHub.

lightninginmyhands commented 3 years ago

Great write-up! I'm dropping a link to MDN API for Response just in case anyone wants to know more https://developer.mozilla.org/en-US/docs/Web/API/Response

panzerdp commented 3 years ago

Great write-up! I'm dropping a link to MDN API for Response just in case anyone wants to know more https://developer.mozilla.org/en-US/docs/Web/API/Response

Thanks! Good idea about the Response link.

AlexRToledo commented 3 years ago

Very helpful article and good approaches

panzerdp commented 3 years ago

Very helpful article and good approaches

Thanks @AlexRToledo.

rowild commented 3 years ago

Wooooooow!!!! Awesome article! Never read anything so clear about fetch and so much in depth. Thank you very much!

panzerdp commented 3 years ago

Wooooooow!!!! Awesome article! Never read anything so clear about fetch and so much in depth. Thank you very much!

You're welcome @rowild.

BenjaminDaSilva commented 3 years ago

return await response.json(); in title image?

BenjaminDaSilva commented 3 years ago

Cool article btw. ;)

panzerdp commented 3 years ago

return await response.json(); in title image?

@BenjaminDaSilva Why not?

BenjaminDaSilva commented 3 years ago

Isn't the return await inside an async function redundant, as it returns a promise implicitly? So there's no observable difference but maybe a memory overhead because of an intermediate promise?

Also see this discussion: https://stackoverflow.com/a/42750371

panzerdp commented 3 years ago

Isn't the return await inside an async function redundant, as it returns a promise implicitly? So there's no observable difference but maybe a memory overhead because of an intermediate promise?

Also see this discussion: https://stackoverflow.com/a/42750371

Yes, most of the time it doesn't make a difference.

However:

Cool article btw. ;)

Thanks!

BenjaminDaSilva commented 3 years ago

@panzerdp,

in your first mail response I've received a more in depth explanation on why you prefer using the await here, I find this valuable additional information, hope it's OK to quote it here:

"By using await response.json() I want the potential error thrown by response.json() (in case if the server returns invalid JSON) to be thrown from inside of fetchMovies() function. That would give a more accurate stack trace of the error, particularly it will indicate that error has happened inside the fetchMovies()."

ghost commented 3 years ago

Hi, great article! Let's say that I would retry your Promise.all code X times before it throws an error, how would you do it?

BenjaminDaSilva commented 3 years ago

@jetolu - I think you could use Promise.allSettled() in fetchMoviesAndCategories() and in the then-function check with an if-condition if one of them has returned rejected status, in which case you can have a number of retries per rejected promise with an async/await while loop for instance until the maximum number if retries has been reached.

rexwebmedia commented 3 years ago

thanks 🤗

pavanjoshi914 commented 3 years ago

approach you mentioned for error handling is not handling 404 though

panzerdp commented 3 years ago

approach you mentioned for error handling is not handling 404 though

@pavanjoshi914 Can you provide more details or a demo?

AhmedEzzat12 commented 3 years ago

Thanks, well written article :D

panzerdp commented 3 years ago

Thanks, well written article :D

Thanks @AhmedEzzat12!

pavanjoshi914 commented 3 years ago

approach you mentioned for error handling is not handling 404 though

@pavanjoshi914 Can you provide more details or a demo?

Great article @panzerdp ! regarding using fetch API article is great :tada:. In my case I shifted with ES6 methods for loading as fetch API wont play good in offline apps!

SiR-PENt commented 2 years ago

Can I use fetch to get data from that already has a .json extension?. For example, I am working on a project that already has a data.json supplied to me? Can I import that to my project with fetch?

BenjaminDaSilva commented 2 years ago

@sukodes ,

sure, for example (excerpt from a vue project of mine):

async fetchConfigFile() { const confFile = await fetch("config.json"); const confJson = await confFile.json(); return confJson; }

After assigning the response.json() to a const or var you have an object and can also reach it's properties regularly like confJson.property1 or confJson.array1[3] or sth.

mkc73 commented 2 years ago

How do I check for errors in the : const movies = await response.json(); process?

BenjaminDaSilva commented 2 years ago

@mkc73, here is a generic apiCall method as example:

const apiCall = async (method, url, authString, payload) => {  
    const response = await fetch(url, {
        method: method, 
        headers: {
            Authorization: authString,
            'Content-Type': 'application/json'},
        body: JSON.stringify(payload)
        });
    if (!response.ok) {
        const message = `An error has occured: ${response.status} - ${response.message}`;
        throw new Error(message);
    }
    const r = await response.text();    
    return r ? JSON.parse(r) : {};
}
mkc73 commented 2 years ago

I may be confused about what is happening with fetch but my question was that in the async function there are two await function calls - errors in the the first are caught by checking response.ok - can there subsequently be an error in the second call and if so what is the syntax for checking and reporting it ? The code above fails gracefully without reporting an error.

Many thanks for your great article and response.

BenjaminDaSilva commented 2 years ago

@mkc73 , not sure if you're referring to my code sample or @panzerdp's movie code sample, could you elaborate a bit, maybe including the code sample you're referring to?

By "two await function calls in the async funtion", you mean the response.text() method of the fetch API? If so, I presume the text() method also throws an error if sth. goes wrong and you can catch that error when calling the function and do with it whatever you want, like:

const myResult = await apiCall('GET', 'https://myApi/myResource').catch(error => {
  console.log(error.message);
  // any other code doing sth. with the error message
});
BenjaminDaSilva commented 2 years ago

@mkc73 , I think I get what you mean now, in my example, if r is undefined, an empty object is returned with that ternary operator. I think one could just add a catch block:

const apiCall = async (method, url, authString, payload) => {  
    const response = await fetch(url, {
        method: method, 
        headers: {
            Authorization: authString,
            'Content-Type': 'application/json'},
        body: JSON.stringify(payload)
        });
    if (!response.ok) {
        const message = `An error has occured: ${response.status} - ${response.message}`;
        throw new Error(message);
    }
    const r = await response.text().catch(error => {
            throw new Error(error);
    });

    return r;
}
raldugin commented 2 years ago

Hello. Good Tutor, thans!!!

But... how does it work with Class???

Need to store async fetch result in the cvariable..... but after creation instance of class Class Authorization variable CSRF_KEY is Inderfined (((((

Class Authorization { constructor() { this.get_token().then((data) => { this.CSRF_KEY = data.CSRF_KEY }) }

async get_token(options = {}) {
    let response = await fetch('token.php', options);
    return await response.json();
}

}

let auth = new Authorization( {} ) console.log( auth.CSRF_KEY ) // UNDEFINED

BenjaminDaSilva commented 2 years ago

@raldugin , you might want to read this: https://dev.to/somedood/the-proper-way-to-write-async-constructors-in-javascript-1o8c

raldugin commented 2 years ago

@BenjaminDaSilva Thanks a lot!!!!!

raldugin commented 2 years ago

@BenjaminDaSilva You save my mind )))

uguryediveren commented 2 years ago

Thanks! You helped me a lot.

openHBP commented 2 years ago

I've been searching for 2 days for such clear explanation. I was able to do the call through ajax but I wanted to understand fetch() and Promise()... https://javascript.info/fetch did not work! .then() chaining https://dev.to/ramonak/javascript-how-to-access-the-return-value-of-a-promise-object-1bck. is not clear. Cannot figure out how to do deal with geoJsonObject fetched!

BenjaminDaSilva commented 2 years ago

@openHBP, some code samples would have been helpful, so some guesses / hints

fetch('https://www.boredapi.com/api/activity', 
    {
    method: 'GET'
    }).then( 
    response => {
        const r = response.json();
        console.log(r); // pending promise
      return r;
    },
    error => {
        console.log(error);
    }  
  ).then( json => {
    // in the 2nd .then() the promise is resolved
    console.log(json);
  })

Or you just use an async success callback in the then block:

fetch('https://www.boredapi.com/api/activity', 
    {
    method: 'GET'
    }).then( 
    async response => {
        const r = await response.json();
        console.log(r); // returns resolved promise, so the repsonse as json
    },
    error => {
        console.log(error);
    }  
  )
openHBP commented 2 years ago

Many thanks but it worked fine with the explanations of the blog https://dmitripavlutin.com/javascript-fetch-async-await/. The links I mentioned is about examples that didn't work for me. Your blog is crystal clear and I achieved to do it and your last 2 examples make things even clearer! Thanks again.

BenjaminDaSilva commented 2 years ago

@openHBP ,

it's not my blog, I'm just a random dude commenting here =)

But I agree - kudos to @panzerdp for this nice blog.

wsw70 commented 11 months ago

Very good post, thank you.

You mention at some point that

When I was familiarizing with fetch(), I was surprised that fetch() doesn't throw an error when the server returns a bad HTTP status,

This actually makes sense: the fetch() command was successful because the web server responded successfully. What the response was is not a concern for fetch() - it did its job and everything was fine.

The server responded that it could not serve the content (response value ≥ 300) for some reason. Why exactly the content could not be served is more or less described by the return code (404 in the case of /oops). The codes are not written in stone, you could respond with a 200 to say that the database is missing but it would be confusing, especially if someone relies on the codes to make a decision.

There are more and more web services that rely only partially on the codes. They would for instance send back a 200 (OK), a 400 (something wrong on your side), and a 500 (something is wrong on my side) - and provide detailed information as part of the response. It will allow the client to make more reasonable decisions (I must back off, I need to add an extra foo parameter, ...).

OTOH, a failure to even reach the web server will cause fetch to fail and the problem must be further investigated. In any case, this is not good news because of an organic problem with the connection. The client's reaction will be different and often requires human intervention (or just retry and hope for the best if this seems to be "network related" (as opposed to, say, a typo in the URI)