Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

[Feature?]: Error Handling with solid-router #1434

@LexSwed

Description

@LexSwed

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 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions