david-plugge / typed-formdata

MIT License
3 stars 1 forks source link

Support coercion of primitives #8

Open lorefnon opened 1 year ago

lorefnon commented 1 year ago

Interesting project - thanks for creating this.

I think one additional feature that this would benefit from is auto coercion of primitive types.

All values coming from form data are strings, eg. in the example in the README even though we have satisfaction: number the extracted form data contains a string value for satisfaction. Similarly if we have checkboxes we will get a string value 'on' where as we'd likely want a boolean.

I propose that we provide few helpers to embed the type info too into the name value so that when extracting we can correctly coerce the value.

<input type="text" name={asStr(f.frameworks[0].name)}/> <!-- name="f.frameworks[0].name:string" -->
<input type="number" name="{asNum(f.frameworks[0].satisfaction)}"/> <!-- name="f.frameworks[0].satisfaction:number" -->

<input type="checkbox" name="{asBool(f.frameworks[1].isActive)}"/>  <!-- name="f.frameworks[0].isActive:boolean -->

This can be made type safe so that something like asNum(f.frameworks[0].name) is a compile time error. Let me know what you think.

david-plugge commented 1 year ago

The helper creates the form input name, which is always just a string. Not sure if there is any benefit to this. If there is i´d prefer something like .number() and .string() (more zod-ish)

In addition, there is a new library for forms in sveltekit that you should prefer over this one: https://github.com/ciscoheat/sveltekit-superforms

If you want to get input name generation and type safety i´d rather create an issue over there or publish a new package which adds just that functionality to superforms.

lorefnon commented 1 year ago

there is a new library for forms in sveltekit that you should prefer over this one

I am not using svelte though.

The helper creates the form input name, which is always just a string. Not sure if there is any benefit to this.

The idea is that the extractor will also be aware of the suffix, and will perform the coercion based on the type suffix.

i´d prefer something like .number() and .string() (more zod-ish)

I don't mind this, but this may cause confusion because you are currently using function invocation for arrays in proxy.

So f.frameworks[0].name.string() results in f.frameworks[0].name:string or f.frameworks[0].name.string[]

david-plugge commented 1 year ago

I am not using svelte though.

Good to know, i built this library for my svelte projects, nice to see that it´s not limited to svelte! Let me know what framework/stack you are using and how this library helps you.

The idea is that the extractor will also be aware of the suffix, and will perform the coercion based on the type suffix.

Ah interesting idea, i assumed it was just about type safety. However it´s probably not safe. Someone might mess with the input name to "hack" your site.

Instead, you're better off using a validation library to coerce, validate, and type your form data on the server. I thought long and hard about how to implement the extractor because I wanted it to be completely independent, since not everyone wants to use zod. That in mind i decided not to implement coercing.

david-plugge commented 1 year ago

I agree that first class coercing is a very valuable feature, but it´s also hard to get right. If it's ok that zod is a required peer dependency and the only validation library supported, then I'm happy to implement it.

lorefnon commented 1 year ago

Let me know what framework/stack you are using and how this library helps you.

So, my goal is to extract values from a form (composed of shoelace components) and submit that to a GraphQL API. There will be many such forms so ideally I wouldn't want to go through the process of defining a model/validator for each form parallel to the graphql schema I already have.

I already generate ts types from graphql so if I have a way to easily transform the form data into an object of same type that would be ideal.

I am not too concerned about malicious actor tinkering with names, as I am extracting the values on client side and the server anyways validates them against the graphql schema. I am just trying to avoid having to structure my GraphQL api around the limitations of form data.

I can also share a PR with a PoC of what I had in mind if you are generally open to the idea. I don't mind zod being a dependency either.

david-plugge commented 1 year ago

Alright got it, thanks for the clarification.

Adding this on top of the current api should be pretty easy. If you want to takle this feel free to open a PR, otherwise i´ll work on it next week.