ciscoheat / sveltekit-superforms

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

Zod and form-level errors #80

Closed abastardi closed 1 year ago

abastardi commented 1 year ago

According to the documentation, errors is of type Record<string, string[]>. However, if a refine or transform is added to the top-level Zod schema and results in a validation failure, errors becomes a string[]. For example:

const form = await superValidate(request, schema.refine((v) => false, 'Form-level error');

Given the above, errors will end up being ['Form-level error'] rather than an object.

This works fine and is a useful way of managing form-level errors (i.e., errors not associated with a specific field in the form), but if this is intentional, it would be a good idea to document it so it can be relied upon as a way of checking for form-level errors (e.g., a check for Array.isArray($errors) indicates there are form-level errors).

If this is not the expected behavior and will be changed, is there an alternative way of handling form-level errors? One alternative I have considered is something like:

  form.valid = false;
  form.message = 'There was a problem';
  return fail(400, { form });

and then checking for !$valid && $message in the template.

ciscoheat commented 1 year ago

I've been thinking about updating that for a long time! But I'm working on the documentation site, so it will soon be fixed.

$errors is not a Record<string, string[]>, but a nested object that mirrors $form, but every "leaf" of the object is a string[] instead of the form value (with some crazy types that handles the inference). For example:

{
  user: {
    posts: {
      "0": { 
        title: ['The title is too short'] 
      }
    }
  }
}

I haven't considered that errors may be added to the form itself like you do, and errors should not be an array instead of an object. So I think the Zod approach could work - adding an _errors property to the object. That's what's done with array errors already, so it's not much extra work.

Using form.message is perhaps more for a flash message than actual validation errors, but if you want to use it, have you seen the new message helper method: https://github.com/ciscoheat/sveltekit-superforms/discussions/76

abastardi commented 1 year ago

So I think the Zod approach could work - adding an _errors property to the object. That's what's done with array errors already, so it's not much extra work.

Yes, that would be a good approach. It might also be a good idea to enable manually adding to $errors._errors by calling setError without specifying a field (e.g., setError(form, null, 'There was a form-level problem')).

Using form.message is perhaps more for a flash message than actual validation errors, but if you want to use it, have you seen the new message helper method: https://github.com/ciscoheat/sveltekit-superforms/discussions/76

Didn't know about that. Thanks.

ciscoheat commented 1 year ago

@abastardi In the upcoming 0.6.7 version, this will be added. Thank you for a good suggestion!