Duplicates
Latest version
Summary 💡
Allow for semantic error handling with server actions.
This is a continuation of solidjs/solid-router#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 not 200.
- handle such responses in code with reactive
useSubmission().error when 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:
https://github.com/solidjs/solid-router/blob/e773947b85ac78281816e86621a2cdb6735ae95a/src/data/action.ts#L149
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.
Duplicates
Latest version
Summary 💡
Allow for semantic error handling with server actions.
This is a continuation of solidjs/solid-router#365 discussion, but focused on
solid-startserver actions.The goal is to allow:
200(401,500, etc) responses from server actions for observability platforms to monitor how many responses are not200.useSubmission().errorwhen using without the form.Proposal: use Response.ok to populate
useSubmission().error.If the action returns non-
Errordata, the action does not fail:Examples 🌈
In the app, users can scan a QR code, when valid code is scanned –
actionis executed. If scanned code is invalid – error message is shown with Retry logic:Motivation 🔦
Right now, to return non-200 response from a server action, one needs to use custom
Response:This, however, makes
useSubmission(action).errorto be empty, because the response is a validResponse:https://github.com/solidjs/solid-router/blob/e773947b85ac78281816e86621a2cdb6735ae95a/src/data/action.ts#L149
Making the
datatype from the action ambiguous:{ correctResponse } | { error }, which makes handling of the response complicated:So, another option is to make sure
submission.erroris populated,throwan error from the action.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 (?). So500, but all queries are revalidated (?) andsubmission.errorempty.