[Feature?]: Error Handling with solid-router
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 5.9k
- Forks
- 426
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 11
Description
Duplicates
- I have searched the existing issues
Latest version
- I have tested the latest version
Summary 💡
Allow for semantic error handling with server actions.
This is a continuation of https://github.com/solidjs/solid-router/discussions/365 discussion, but focused on solid-start server actions.
The goal is to allow:
- return non-
200(401,500, etc) responses from server actions for observability platforms to monitor how many responses are not200. - handle such responses in code with reactive
useSubmission().errorwhen using without the form.
Proposal: use Response.ok to populate useSubmission().error.
const serverAction = action(() => {
'use server';
try {
return perform();
} catch(error) {
// Error is serialised, no queries are revalidated (unless specified otherwise)
// Response.ok is `false`, so `submission.error` is serialised Error.
// This will make the action use to fail (as the error is rethrown), so needs try/catch
return json(new Error('Something went wrong'), { code: 500 });
}
});
const Component = () => {
const performAction = useAction(serverAction);
const submission = useSubmission(serverAction);
// See example, QR Code scanning
const userActionWithoutForm = () => {
try {
await performAction(); // same as fetch().catch() when the request has failed
} catch {}
}
return (
<Switch>
<Match when={submission.pending}>Checking</Match>
<Match when={submission.error}>Retry with another input</Match>
<Match when={true}>Perform action</Match>
</Switch>
)
}
If the action returns non-Error data, the action does not fail:
// action, does not throw an Error
return json('Something went wrong', { code: 500 });
// Component
// similar to fetch(response => response.json()) without checking for response.ok
await performAction();
// rely on submission.error being populated with 'Something went wrong' string
Examples 🌈
In the app, users can scan a QR code, when valid code is scanned – action is executed. If scanned code is invalid – error message is shown with Retry logic:
const checkCode = action(async code => {
"use server";
try {
return validity(code);
} catch(error) {
// ===Unclear===
}
});
// component:
const submission = useSubmission(checkCode);
const checkCode = useAction(checkCode);
const onScanned = code => {
try {
await checkCode(code);
} catch(error) {
// do something, or just ignore it, same way we would do with using fetch directly.
}
}
return (
<Switch>
<Match when={submission.pending}>Checking</Match>
<Match when={submission.error}>Wrong code</Match>
<Match when={true}><QRScanner onSuccess={onScanned} /></Match>
</Switch>
);
Motivation 🔦
Right now, to return non-200 response from a server action, one needs to use custom Response:
'use server';
return Response({ error: 'Something went wrong' }, { code: 500 });
This, however, makes useSubmission(action).error to be empty, because the response is a valid Response:
Making the data type from the action ambiguous: { correctResponse } | { error }, which makes handling of the response complicated:
const performAction = useAction(serverAction);
const submission = useSubmission(serverAction);
const [error, setError] = createSignal(null);
const someUserAction = () => {
try {
const data = performAction();
if (data.error) {
// do nothing, rely on submission.result.error
// but submission.error !== submission.result.error
// by design to distinguish failures?
} else {} // success logic
} catch(error) {
// will never get here
}
}
So, another option is to make sure submission.error is populated, throw an error from the action.
const serverAction = action(() => {
'use server';
throw new Error('Something went wrong');
});
This works for useSubmission().error, but the HTTP Response status is now 200, so one needs custom metrics to monitor how the API is performing.
Doing return json(new Error('error'), { status: 500, revalidate: [] }) is making action to fail itself (?). So 500, but all queries are revalidated (?) and submission.error empty.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/data/action.ts at the linked line and trace how action responses populate useSubmission().error and how non-200 responses are handled. Compare the behavior against the server-action examples in the issue, then define tests for Error and non-Error response data, HTTP status preservation, revalidation, and reactive submission state.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100