ciscoheat / sveltekit-superforms

Making SvelteKit forms a pleasure to use!
https://superforms.rocks
MIT License
2.11k stars 62 forks source link

better server error handling #402

Open macmillen opened 4 months ago

macmillen commented 4 months ago

Is your feature request related to a problem? Please describe. Currently the handling of server side errors is a big pain. Our situation is that we have server errors like these:

  let errors = [
    {
      path: "settings.stripe.testSignatureKey",
      messages: ["Wrong API key"],
    },
  ];

and we want to automatically set form errors based on these server errors.

We can't do this:

superForm.errors.update((errors) => ({
  ...errors,
  newError,
}))

because the errors vanish as soon as someone modifies an input field.

I also tested other hacky solutions like this one with a recursive refine that checks for errors in the error store that match with a field of the zod schema:

const refineAllPaths = (
  validators: ZodValidation<AnyZodObject>,
  paths: string[] = zodKeys(validators),
): ZodValidation<AnyZodObject> => {
  if (paths.length === 0) return validators;

  const [path, ...restPaths] = paths;

  return refineAllPaths(
    validators.refine(
      () => {
        const errors = get(serverErrorStore);
        const error = errors.find((error) => error.path === path);
        if (error) {
          console.log("error found", error);
          return false;
        }
        return true;
      },
      () => ({
        message: "Error",
        path: path!.split("."),
      }),
    ),
    restPaths,
  );
};

But here we have a separate errorStore where we store all server errors after submit but like that we have race conditions because refine runs before the errors are set. and it generally feels really hacky.

Describe the solution you'd like It would be really nice if we had a nice way to let superforms handle these things natively or provide a way to make the manually set errors not vanish on form modifications.

Describe alternatives you've considered

ciscoheat commented 4 months ago

I'd suggest making a derived/proxy store for this, based on $errors, but will store a list of errors that have been added manually, and replace them for those paths.

macmillen commented 3 months ago

I see what you mean, unfortunately I don't see a way for this to work with customValidity enabled which I decided to use for simplicity's sake. Do you have an idea on how to achieve this?

I have the feeling it would be much easier to handle this internally like providing a way to merge server errors with superForms errors or otherwise I feel like there will be a lot of side-effects.

macmillen commented 3 months ago

Now I managed to display server errors with setCustomValidity enabled but there is still the issue that only one and not all input fields get a validity state applied. Is there a way to trigger setCustomValidity on all input elements?

I created a repro to demonstrate the issue: https://www.sveltelab.dev/2b04shwpzvgw2li