I am building a Confluence app that pulls images from Imgur api and displays them in Confluence pages.
Here is the JSX
import ForgeUI, { render, Fragment, Macro, Text, Image, useProductContext, useState, useEffect } from "@forge/ui";
import { fetch } from '@forge/api';
const IMGUR_API_ENDPOINT = 'https://api.imgur.com/3/gallery/hot/viral/0.json';
const App = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(IMGUR_API_ENDPOINT, {
headers: {
'Authorization': 'Client-ID <client-id>' // Replace with your Client-ID
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
console.log("Received data:", result); // Log received data
setData(result.data);
setLoading(false);
} catch (err) {
console.error("Error occurred:", err); // Log any error
setError(err);
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <Text>Loading images...</Text>;
if (error) return <Text>Error: {error.message}</Text>;
return (
<Fragment>
<Text>Hot Images from Imgur:</Text>
{data && data.map(image => (
<Fragment key={image.id}>
<Image src={image.link} alt={image.title} />
<Text>{image.title}</Text>
</Fragment>
))}
</Fragment>
);
};
export const run = render(
<Macro
app={<App />}
/>
);
and here is the manifest.yml
modules:
macro:
- key: imgur-gallery-macro
function: main
title: Imgur Gallery Viewer
description: View hot images from Imgur in Confluence.
function:
- key: main
handler: index.run
app:
id: ari:cloud:ecosystem::app/<removed>
permissions:
external:
fetch:
backend:
- 'https://api.imgur.com/*'
I keep getting the error even though I have added the URL. At a loss on how to resolve this error.
message: 'URL not included in the external fetch backend permissions: https://api.imgur.com/3/gallery/hot/viral/0.json. Visit go.atlassian.com/forge-egress for more information.',
name: 'REQUEST_EGRESS_ALLOWLIST_ERR',
status: 403
}
I have read and re-read the Forge egress article go.atlassian.com/forge-egress. I have tried formatting the URL with a wild card and without, with and without quotes, and as the full URL. I have gone through the steps of forge upgrade and forge tunnel and forge deploy after making changes. I am unsure what else I need to do to make this work. This is a API endpoint that allows anonymous users so it shouldn't require the full OAuth workflow or am wrong in saying that?
I posted the same question above to the Atlasssian developer forums https://community.developer.atlassian.com/t/custom-app-external-fetch-backend-permissions-error/72674 and based on the feedback there I was able to resolve the issue.
The gist is that I needed to adjust the useEffect function - adding async and await
const fetchData = async () => {
// ... same as before
};
await fetchData();
}, []);
I also made a change in the Imgur image feed I was pulling; I changed it to the earthporn subreddit so I'd render some pretty naturescapes as opposed to some of the weird and disturbing stuff that was popping up on the hot and viral feed.
Here is the final code
import ForgeUI, { render, Fragment, Macro, Text, Image, useProductContext, useState, useEffect } from "@forge/ui";
import { fetch } from '@forge/api';
const IMGUR_API_ENDPOINT = 'https://api.imgur.com/3/gallery/r/earthporn/0';
const App = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(async () => {
const fetchData = async () => {
try {
const response = await fetch(IMGUR_API_ENDPOINT, {
headers: {
'Authorization': 'Client-ID <client-id>' // Replace with your Client-ID
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
console.log("Received data:", result); // Log received data
setData(result.data);
setLoading(false);
} catch (err) {
console.error("Error occurred:", err); // Log any error
setError(err);
setLoading(false);
}
};
await fetchData();
}, []);
if (loading) return <Text>Loading images...</Text>;
if (error) return <Text>Error: {error.message}</Text>;
return (
<Fragment>
<Text>Our beautiful Earth from Imgur:</Text>
{data && data.map(image => (
<Fragment key={image.id}>
<Image src={image.link} alt={image.title} />
<Text>{image.title}</Text>
</Fragment>
))}
</Fragment>
);
};
export const run = render(
<Macro
app={<App />}
/>
);
Also I added the images url to the manifest yml
external:
images:
- 'https://i.imgur.com/*'