Reputation: 1894
I wrote a util wrapper for an API I'd like to consume. The wrapper handles request buidling and token fetching.
import refreshToken from './refreshToken'
/**
* Fetch util handles errors, tokens and request building for the wrapped API calls
* @param {string} url Request URL e.g. /chargehistory
* @param {string} requestMethod Request Method [GET, POST, PUT, DELETE]
* @param {object} requestBody Request Body as JSON object
* @param {object} retryFn The caller function as object reference to retry
* @private This function is only used as util in this class
* @async
*/
const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
// Block thread if the token needs to be refetched
if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
refreshToken()
}
let request = {
method: requestMethod,
headers: {
'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
}
if(requestMethod === 'POST' || requestMethod === 'PUT') {
request.body = JSON.stringify(requestBody)
}
fetch(`${process.env.REACT_APP_API}${url}`, request)
.then(response => {
if(response.ok) {
return response.json()
} else if(response.status === 401) {
refreshToken().then(() => retryFn())
} else {
console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
}
})
.then(json => {
console.log(json)
return json
})
.catch(error => console.error(error))
}
This works and prints some json to the console once it is resolved. Next I built functions to consume utilize this abstraction:
/**
* Get a list of all completed charge sessions accessible by the current user matching the filter options.
*/
const getChargehistory = (installationId) => {
console.log(fetchUtil(`/chargehistory?options.installationId=${installationId}`, 'GET', {}, getChargehistory))
}
Which prints undefined
I can somewhat understand that although I did expect a function reference or a promise.
I tried adding async
before the fetchUtil and the caller and await
the fetchUtil. This gave me an error to not calling await on undefined. I also tried reweriting it into a hook which did not work at all.
I would need the data in the useEffect
hook of a component:
const Cockpit = () => {
const { t } = useTranslation()
const [chargehistory, setChargehistory] = useState(undefined)
const [installationreport, setInstallationreport] = useState(undefined)
useEffect(() => {
setChargehistory(getChargehistory)
setInstallationreport(getInstallationreport)
}, [])
}
Why am I getting undefined
and how can I resolve this?
Upvotes: 0
Views: 589
Reputation: 399
Inside your fetchUtil
function, it ends with no return value, which means your fetchUtil
function is going to implicitly return undefined
.
You said
fetch(`${process.env.REACT_APP_API}${url}`, request)
.then(response => {
if(response.ok) {
return response.json()
} else if(response.status === 401) {
refreshToken().then(() => retryFn())
} else {
console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
}
})
.then(json => {
console.log(json) // (1)
return json
})
.catch(error => console.error(error))
inside this function, (1)
part works well, right?
I think if you change your code like below it would work.
First, update your fetchUtil
code like this. Return fetch.
const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
// Block thread if the token needs to be refetched
if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
refreshToken()
}
let request = {
method: requestMethod,
headers: {
'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
}
if(requestMethod === 'POST' || requestMethod === 'PUT') {
request.body = JSON.stringify(requestBody)
}
// return fetch here! it will return a promise object.
return fetch(`${process.env.REACT_APP_API}${url}`, request)
.then(response => {
if(response.ok) {
return response.json()
} else if(response.status === 401) {
refreshToken().then(() => retryFn())
} else {
console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
}
})
.then(json => {
console.log(json)
return json
})
.catch(error => console.error(error))
}
Second, update your getChargehistory
like this.
const getChargehistory = async (installationId) => {
const result = await fetchUtil(`/chargehistory?options.installationId=${installationId}`, 'GET', {}, getChargehistory)
console.log(result);
}
Because I don't have full access to your code, there still might be errors left, but I hope this helps!
Upvotes: 1