I'm learning typescript and messing around with an API endpoint, I've created a method which takes a value, makes a request to an external API and gets the data, populates the model PortalDetail and returns it back to the front end.
However, the returned data is always null. I have checked the portalUrl
and the value exists, so I'm not sure what I'm doing wrong here:
Here is the code in question:
const CheckUri = async (organisationCode: string): Promise<PortalDetail | null> => {
await fetch(`${uris.appCode}${organisationCode}`)
.then(async (data) => {
const portalUrl = await data
.text()
.then((html) => html)
.catch(() => null)
console.log(portalUrl); // This has a value
console.log(data); // So does this
if (data?.status === 200 && portalUrl) {
console.log("inside if"); // This also gets printed
return new PortalDetail(portalUrl, organisationCode);
}
})
.catch(() => {
})
.finally(() => {
})
return null;
}
Here is the code calling the method:
const CheckOrgnisationCode = async (orgCode: string) => {
if (!orgCode || orgCode.includes(' ')) {
return;
}
console.log("before checkuri method")
var portalDetails = await CheckUri(orgCode);
console.log("finiahes ");
console.log(portalDetails);
if (portalDetails?.portalUrl) {
await StoreData(saved.portalURL, portalDetails?.portalUrl);
await StoreData(saved.portalCode, orgCode);
}
}
Can someone please explain where I'm going wrong?
CodePudding user response:
You are always returning null, no matter the result of the fetch call - see the last line of the function:
return null
You have two options:
- Return the
fetch
call directly:
return fetch(...);
- Store the
fetch
call return value in a variable and return that variable:
const response = await fetch(...);
return response;
Both options are equivalent.
And since you are using an async function, you can use try/catch like in sync code like in the following really simplified example:
try {
const response = await fetch('url');
const html = await response.text();
// note: fetch doesn't throw for status codes >= 400
if (response?.status === 200) {
return html;
} else {
throw Error('Server error');
}
} catch (error) {
return null
}
CodePudding user response:
You are confused with async/await
and Promises
.
- Never call
await
&.then
simultaneously on aPromise
- Use
try/catch
insideasync
functions when you want to handle errors.
const CheckUri = async (organisationCode: string): Promise<PortalDetail | null> => {
try {
const resp = await fetch(`${uris.appCode}${organisationCode}`)
if (!resp.ok) { // almost same as resp.status !== 200
throw resp
// or
// const text = await resp.text()
// throw text
}
const portalUrl = await resp.text()
return new PortalDetail(portalUrl, organisationCode)
} catch (err) {
// console.error(err)
return null
}
}
CodePudding user response:
You are mixing promise.then with async/await. And it usually it gets to such results. Choose one - async/await is more readable.
The issue is in the first .then
you return something. You await the call but you do not assign it to anything
.then(async (data) {
if (data?.status === 200 && portalUrl) {
//this return will not return the result to the CheckUri
return new PortalDetail(portalUrl, organisationCode);
}
});
Here is what you should to to your code
const CheckUri = async (organisationCode: string): Promise<PortalDetail | null> => {
const RESLUT = await fetch(`${uris.appCode}${organisationCode}`)
//...
return RESULT;
Here is your code with async.await which I believe is more readable.
const CheckUri = async (organisationCode: string): Promise<PortalDetail | null> => {
try {
const fetchResult = await fetch(`${uris.appCode}${organisationCode}`);
const portalUrl = await fetchResult.text();
if (fetchResult.status === 200 && portalUrl) {
return new PortalDetail(portalUrl, organisationCode);
}
else {
return null;
}
} catch(e) {
//handle the error
console.error("We couldn't check the URI", e);
return null
} finally {
//do the cleanup logic
}
}