Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parseFormData #672

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

frenzzy
Copy link

@frenzzy frenzzy commented Jun 23, 2024

This PR introduces new primitives:

  • safeParseFormData(schema, formData, config) - Parses FormData input based on a schema.
  • parseFormData(schema, formData, config) - Similar to safeParseFormData but throws a FormError in case of errors.
  • decodeFormData(schema, formData) - Decodes FormData without input validation.
  • FormError - Similar to ValiError, but contains flattened error messages for forms.
  • isFormError - A type guard to check if an error is a FormError, similar to ValiError.

Currently, I use a similar implementation in userland. However, since it heavily depends on valibot internals, I believe it is better to include it in the core package. These primitives are simple and align with the modular approach of the valibot library. This PR provides an alternative solution to the suggestions in #539 and #544. Please let me know your thoughts. I can add tests and documentation if the overall approach is approved.

Usage example:

import { parseFormData } from 'valibot';

async function server(formData: FormData) {
  const data = parseFormData(MySchema, formData)
}

For the following FormData:

<form enctype="multipart/form-data" method="post">
  <input name="title" type="text" value="Red apple" />
  <input name="price" type="number" value="0.89" />
  <input name="created" type="date" value="2024-04-12T07:00:00.000Z" />
  <input name="active" type="checkbox" value="true" />
  <input name="tags" type="text" value="fruit" />
  <input name="tags" type="text" value="healthy" />
  <input name="tags" type="text" value="sweet" />
  <input name="images.0.title" type="text" value="Close up of an apple" />
  <input name="images.0.created" type="date" value="2024-04-12T07:01:00.000Z" />
  <input name="images.0.file" type="file" value="a.jpg" />
  <input name="images.0.tags" type="text" value="foo" />
  <input name="images.0.tags" type="text" value="bar" />
  <input name="images.1.title" type="text" value="Our fruit fields at Lake Constance" />
  <input name="images.1.created" type="date" value="2024-04-12T07:02:00.000Z" />
  <input name="images.1.file" type="file" value="b.jpg" />
  <input name="images.1.tags" type="text" value="baz" />
</form>

Using the following schema:

import * as v from 'valibot';

const MySchema = v.object({
  title: v.string(),
  price: v.number(),
  created: v.date(),
  active: v.boolean(),
  tags: v.array(v.string()),
  images: v.array(
    v.object({
      title: v.string(),
      created: v.date(),
      file: v.blob(),
      tags: v.array(v.string())
    })
  ),
});

Will output the following result:

const data = {
  title: 'Red apple',
  price: 0.89,
  created: Date,
  active: true,
  tags: ['fruit', 'healthy', 'sweet'],
  images: [
    {
      title: 'Close up of an apple',
      created: Date,
      file: File,
      tags: ['foo', 'bar'],
    },
    {
      title: 'Our fruit fields at Lake Constance',
      created: Date,
      file: File,
      tags: ['baz'],
    },
  ],
};

@fabian-hiller
Copy link
Owner

Thanks for the PR! I am still unsure how to proceed with this functionality. In general, it makes sense to provide an advanced decodeFormData schema. But I am not sure if it should be part of the core package.

The reason for this is that I prefer the core package to have a clear focus on our basic functionality. This makes it more controllable for me, especially in the coming months. Also, if I read your code correctly, decodeFormData is not able to handle any schema. Do union, variant and intersect work?

I think it is better at the moment to release decodeFormData as a separate package via @valibot/..., @decode-formdata/valibot or completely by the community. This will allow the maintainer to fully focus on its functionality and also document which schemas of the core package are supported. I am happy to review the code, but I will not have time to work on it myself.

If you decide to release it as your own community package, I will be happy to add it to our ecosystem and share it on X.

@fabian-hiller fabian-hiller self-assigned this Jun 23, 2024
@fabian-hiller fabian-hiller added enhancement New feature or request question Further information is requested labels Jun 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants