vine icon indicating copy to clipboard operation
vine copied to clipboard

Discussion for a new feature - Accept native FormData

Open okalil opened this issue 1 year ago • 4 comments

Context

Although it is not a web standard, it is common to use dot/bracket syntax to represent arrays and nested objects. Some frameworks like Adonis and Express (with body parser) handle that automatically. However, with Remix or RSC actions, that expose a native FormData object without any extra preprocessing, handling arrays and objects is not so straightforward and we would need to manually parse the FormData (or use some lib) before forwarding it to the vine validator.

async function myAction(formData: FormData) {
  const form = preprocessFormData(formData)
  const data = await vine.validate({ data: form, schema })
}

Solutions

Since it's a common case for frameworks that use the native FormData, it would be nice if vine could handle that without extra libs / developer work. I'm not sure what would be the best way to do it though, here are some ideas:

  1. The data option accepts FormData objects:
       await vine.validate({ data: formData, schema })
    
    In this case the validate method would check if formData is instanceof FormData and then apply the preprocessing before matching the schema.
  2. External method
      await vine.validate({ data: vine.process(formData), schema })
    
    Include a new method or function (name is up to discussion) to preprocess the formData before calling validate.

okalil avatar Dec 07 '24 12:12 okalil

I was very surprised that vinejs doesn't (it seems) support this already. Vine's docs seem to indicate that it should be stupid simple to handle form data:

Built for validating form data and JSON payloads Serializing an HTML form to FormData or a ‌JSON object comes with its own set of quirks. For example:

Numbers and booleans are serialized as strings Checkboxes are not booleans And empty fields are represented as empty strings VineJS handles all these quirks natively, and you never have to perform manual normalization in your codebase.

And yet when I try to simple run the following code:

const authSchema = vine.object({
  email: vine.string().email(),
  password: vine.string().minLength(8).maxLength(32),
});

const authValidator = vine.compile(authSchema);

const data = await authValidator.validate(formData);

I receive an error with messages:

{
    message: 'The email field must be defined',
    rule: 'required',
    field: 'email'
  },
  {
    message: 'The password field must be defined',
    rule: 'required',
    field: 'password'
  }

DNWCloud avatar Dec 14 '24 03:12 DNWCloud

Yeah.. For now I created a separate class to parse the body:

const data = bodyParser.parse(formData) // handles nested fields with dot/bracket notation
const { email, password } = await vine.validate({ data, schema })

But it would be great if there was a built in function for that.

okalil avatar Dec 14 '24 15:12 okalil

Could we add a 1-liner like this somewhere?

data = data instanceof FormData ? Object.fromEntries(data.entries()) : data;

DNWCloud avatar Dec 15 '24 14:12 DNWCloud

The issue will be nested data/array indexes. For example: How would data.entries() will look like for the following HTML inputs.

<div>
  <label for="email-1"> Email 1 </label>
  <input type="email" id="email-1" name="users[0]['email']">
 </div>

 <div>
  <label for="email-2"> Email 2 </label>
  <input type="email" id="email-2" name="users[1]['email']">
</div>

thetutlage avatar Dec 23 '24 13:12 thetutlage

Closing this for now. If anyone knows a util that can properly convert form data to objects including nested properties, then please share it and we will see how it can be incorporated within VineJS

thetutlage avatar Oct 16 '25 05:10 thetutlage