What I'm trying to do is: from my single page application, get data from an API using fetch. If the JWT is expired, ask the API for a new JWT and then renew the request for data.
I tried to implement this with 3 functions: getData calls fetchData. If fetchData returns a JWT expired message, a function getjwt is called (also from within getdata) and then (only then) fetchData again.
The application calls getData (upon page load - but that's irrelevant here)
I have a function getjwt:
async function getjwt() {
// posts a refresh token and gets a jwt in headers
let adresse = `${baseUrl}/auth/getjwt`
let headers = { 'Content-Type': 'application/json' }
postData(adresse, refresh.value, headers)
.then((response) => {
if (response.status === 200) {
jwt.value = response.headers.get('__auth__')
}
})
.catch((err) => alert(err))
}
and the functions fetchData and getData:
async function fetchData (url = '', headers = {}) {
let r = await fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'include',
headers: headers,
redirect: 'follow',
referrerPolicy: 'no-referrer',
})
return r
}
async function getData(url = '', headers = {}) {
let r = await fetchData(url, headers)
if (r.status === 409) {
console.log("Oh no! My token has expired.")
getjwt()
let r = await fetchData(url, headers)
return r.json()
}
return r.json()
}
On purpose, first time fetchData is called, the jwt is expired. getjwt is called and the jwt get properly renewed (in a Pinia store). BUT: the order of execution is: getData gets called twice, and then getjwt is called.
Maybe I'm missing something about asynchroneous operations and Promise, but how can I force getjwt to be called and finish getting the new jwt before getData is called a second time.
Problem with the
getJwtfunction is that the promise returned by it doesn't wait for the asynchronous operation inside it to finish. As a result, the promise it returns gets resolved beforepostDatagets completed.You can fix this by returning the promise from
postDataas shown below:Adding a
returnbefore thepostDatacall fixes the issue becausereturnensures that the promise returned by thegetJwtfunction gets resolved to the promise returned byreturn postData(...). One promisep1getting resolved to another promisep2simply means that the promisep1will wait forp2to settle (fulfil or reject). Ifp2fulfils,p1fulfils with the same value. Ifp2gets rejected,p1also gets rejected with the same rejection reason.Note the change in the
catchmethod. Thethrow erris needed to avoid implicitly converting the promise rejection into promise fulfilment.As you aren't using the
awaitkeyword inside the function, you might as well just remove theasynckeyword from the function signature.And finally, to make it work, you need to
awaitthe call to thegetJwtfunction inside thegetDatafunction.I would refactor your code by making the following two improvements:
catchmethod call and handle the error in the function that calls thegetJwtfunction.async-await