S
SolidJS5mo ago
MikeM42

createResource doesn't seem to be catching errors.

I have been at this for a while now and can't figure it out. I am calling a fetcher from a createResource, the fetcher does a pretty basic fetch(URL) request for which I have purposefully brought down the backend server. As a result I get a timeout on the HTTP POST request, which results in a TypeError, but that error doesn't seem to result in data.error (data is the name of the resource I created) to be set at any point. I've tried to handle the eror by using Promise.reject in a .then(...).catch(return Promise.reject("it failed')) I've also tried to just let the erorr happen, or tried something like if (!response.ok) then {throw new Error("It failed")} bt none of these solutions seem to yield data.error being set. I inspired myself to an extent from this article, https://www.thisdot.co/blog/how-to-handle-async-data-fetching-using-createresource-in-solidjs which makes it sound real easy but doesn't seem to apply to my problem.
6 Replies
lxsmnsyc
lxsmnsyc5mo ago
Can you please show the code you've done?
MikeM42
MikeM425mo ago
Sure. Here you go... this is the core function
function Content() {
const [text, setText] = createSignal("")
const [query, setQuery] = createSignal("");

const handleChange = (event: Event) => {
const {value} = event.currentTarget as HTMLInputElement;
console.log("Change is:" + value)
setText(value)
}

const handleSubmit = (event: Event) => {
event.preventDefault()
setQuery(text())
}

const [data] = createResource(query, getURLs);

return (
<div class={styles.App}>
<header class={styles.header}>
<h1 class={"title is-1 has-text-grey-light"}>Speech Creation Assistant</h1>
<div>
<Show when={(data.latest ?? [] as URL[]).length == 0}>
<form onSubmit={handleSubmit}>
<input class="input" type="text" placeholder="Enter the topic" name="text"
value={text()} onChange={handleChange}/>
<button class="button is-primary" type="submit">Submit</button>
</form>
</Show>
</div>
<div>
{data.loading && (
<p>Loading urls ...</p>
)}
{data.error && (
<div>
<p>Error searching for relevant articles</p>
</div>
)}
{data() && (
<URLList urls={data() ?? [] as URL[]} query={query()}/>
)}
</div>
</header>
</div>
);
}
function Content() {
const [text, setText] = createSignal("")
const [query, setQuery] = createSignal("");

const handleChange = (event: Event) => {
const {value} = event.currentTarget as HTMLInputElement;
console.log("Change is:" + value)
setText(value)
}

const handleSubmit = (event: Event) => {
event.preventDefault()
setQuery(text())
}

const [data] = createResource(query, getURLs);

return (
<div class={styles.App}>
<header class={styles.header}>
<h1 class={"title is-1 has-text-grey-light"}>Speech Creation Assistant</h1>
<div>
<Show when={(data.latest ?? [] as URL[]).length == 0}>
<form onSubmit={handleSubmit}>
<input class="input" type="text" placeholder="Enter the topic" name="text"
value={text()} onChange={handleChange}/>
<button class="button is-primary" type="submit">Submit</button>
</form>
</Show>
</div>
<div>
{data.loading && (
<p>Loading urls ...</p>
)}
{data.error && (
<div>
<p>Error searching for relevant articles</p>
</div>
)}
{data() && (
<URLList urls={data() ?? [] as URL[]} query={query()}/>
)}
</div>
</header>
</div>
);
}
And here is the fetcher, I've left in comments a few different ways I've tried the fetcher.
interface URLs {
urls: URL[]
}

export async function getURLs(query: string): Promise<URL[]> {
if (query.trim() === "") {
return [];
}
console.log("Retrieving URLs for: " + query)
// const result = await fetch(HOST_URL + "/api/news/urls", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(
// {"query" : query})
// })
// .then(response => response.json())
// .then(json => json as URLs)
// .catch((error) => {
// console.log("Shit went sideway: " + error)
// return Promise.reject("Shit went sideways");
// });

// const response = await fetch(HOST_URL + "/api/news/urls", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(
// {"query" : query})
// });
// if (!response.ok) {
// console.log("Houston there is a problem");
// throw new Error("The server encountered errors: " + response.statusText);
// }
// const result: URLs = await response.json();

const response = await fetch(HOST_URL + "/api/news/urls", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(
{"query" : query})
});

const result: URLs = await response.json();
return result.urls;
interface URLs {
urls: URL[]
}

export async function getURLs(query: string): Promise<URL[]> {
if (query.trim() === "") {
return [];
}
console.log("Retrieving URLs for: " + query)
// const result = await fetch(HOST_URL + "/api/news/urls", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(
// {"query" : query})
// })
// .then(response => response.json())
// .then(json => json as URLs)
// .catch((error) => {
// console.log("Shit went sideway: " + error)
// return Promise.reject("Shit went sideways");
// });

// const response = await fetch(HOST_URL + "/api/news/urls", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(
// {"query" : query})
// });
// if (!response.ok) {
// console.log("Houston there is a problem");
// throw new Error("The server encountered errors: " + response.statusText);
// }
// const result: URLs = await response.json();

const response = await fetch(HOST_URL + "/api/news/urls", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(
{"query" : query})
});

const result: URLs = await response.json();
return result.urls;
Note, that I was able to hook to a debugger and can see that data.error is being set, but for some reason the DOM is not reacting properly, as if it didn't render when the error occurs.
Grahf
Grahf5mo ago
I've never gotten createResource to display errors from the function passed to it. Interested to see if you can get it to work
lxsmnsyc
lxsmnsyc5mo ago
did you have a Suspense or ErrorBoundary?
MikeM42
MikeM425mo ago
I did not int he code I pasted but I tried to put an ErrorBoundary around the form afterwards and it didn't help. I have not tried using Suspense. As I mentioned above also, the data.error does get set, and it would seem from my debug session that the code does get called as well, its just that the DOM doesn't change. I've also tried using Switch / Match instead of the structure I have in the code above but the behavior is the same. I'll try and put together a super simple example based on my latest code so that you can reproduce locally hopefully. (Side not I am running this in Edge)
MikeM42
MikeM425mo ago
I was able to make it work by putting an ErrorBoundary around the form, I figured that probably that is when the error gets generated, hence probably where I should have an overal catch. I then had to wrapper the form in a component so that it could be both the fallback as well as the main component. This gives me mostly the behaviour I want. The one funky thing I had to do was to set the query twice in handleSubmit, so that the resource would reflect the change, which wasn't too bad.