-
-
Notifications
You must be signed in to change notification settings - Fork 98
Add strict option #296
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
Add strict option #296
Conversation
|
Thank you! I'll check this out locally soon, just added a comment. The documentation is here: https://github.com/ciscoheat/superforms-web |
|
Thank you for doing this, I think the feature is useful, but there's one difficult problem, which is that z.object({
foo: z.string() // string, not string | undefined
})Then data cannot be
Any ideas? I'll make some updates to the PR meanwhile. |
Cleaned up redundant parameter.
|
You are very welcome :) I think my clear preference would be to throw an exception. Basically "enforce" that the consumer provides the shape of data that the endpoint requires. It also makes sense from a debugging perspective ("oh if failed let me inspect the input data to see what's missing" coercing would remove that) I agree that it put's a larger burden on the consumer, however as it is opt-in I think that would be fine? It also gives the ability to integration test your endpoints since you can test that a consumer providing nonsense will be rejected. Do you have any outstanding work on the branch? or should I attempt to rewrite it to fail instead? |
|
Just adding one thing. Would be really great to have something like Playwright component test to capture/describe/test this behaviour (that we eventually decide on) |
|
Sounds good! There's a SuperFormError error class that you can use for that here. I've made a PR to your PR, if you can merge that then it's up to speed: 21RISK#1 Also, it would be interesting to hear your thoughts about what to do in non-strict mode when invalid data is posted. The scenario I have in mind is this: const schema = z.object({
len: z.string().transform((val) => val.length).pipe(z.number().min(5));
})
type T = z.infer<typeof schema>Now if {
valid: true,
data: T,
// ...
} | {
valid: false,
data: Partial<T>,
// ...
}And only populate the correct data fields, if valid is false. Then if a field doesn't exist in |
Options takes priority over zod schema key.
ddd094d to
4083708
Compare
|
Hi @ciscoheat - while working on the branch, I've had some insights into why you initially built it in the way you did. And I have shifted my opinion 180 Towards not throwing an error but instead having This makes it easier to implement your own error handling in load functions if My implementation here is straight forward, When strict is true we parse the input data 2 times, with defaults and without defaults - This way we can in the strict case do our schema parsing on the data without defaults, and still return the data with sensible defaults In this way the output data will always adhere to the schema using the defaults you have created, however the parsing of errors and valid will in strict mode happen on an object without these defaults. For example in this test case The input data is an empty object, so the defaults are applied to the output object, however because strict is true, valid is false, and errors indicate that foo was missing in the input. One thing to note is, that to my eyes currently the strict=false scenario does not implement defaults if the input is a POJO is this intentional? I've created a small block for this is strict=true to not break anything but should this be the default everywhere? I would have preferred to break the flow of |
|
I've added tests for non-strict mode as well. Can you review the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the changes look solid.
In the near future we could always dicuss if it would make sense to add some "debugging" meta on the return-type, but that's out of scope for now.
I will test it against our internal integration tests in 21RISK, and hopefully everything will be green 😎
@AndreasHald was not feeling well yesterday - so let's check with him when he's back
Yes, this was my reasoning for doing that as well. It's complicated to reconstruct the whole SuperValidated structure if an exception is thrown and you're left with nothing.
I updated the code to create both of these in the same run.
Sounds good, that should give us the best of both worlds.
Yes, thinking back, I decided earlier that any POJO sent to
The superValidate function is partitioned into a few functions, and I don't like to break out coupled code just for the sake of it, especially if it's not going to be reused. It will be rewritten in v2 anyway, so I see no need. But thank you for asking, of course! |
|
I'm back :) - this looks great!
Much better.
Ah I see, yeah it's probably best not to introduce such a breaking change until v2, I was simply wondering. Personally I'm a big advocate of consistency, so I would argue the behaviour would be "better" if both flows (POJO and FormData) behave the same, And it's simply a matter of representing data as either
All good :) We've tested this branch against our internal integration tests and everything looks good - so on my end we are clear to merge 👍 |
|
Nice, will merge soon and release a new version within a week or so, together with some other fixes! |
|
I think you should wait before merging this. There is an issue with When calling I think this is a rather bad API design, I would strongly expect A solution could be to ignore the |
|
With no data at all, errors won't be displayed, but it would make sense to make the errors flag default to |
That sounds like a great solution. Did you ever think about having 2 functions, one dedicated to the load function and one function dedicated to the form-action? @AndreasHald and I have used a considerable amount of time understanding how different the function calls to superValidate right now are in the 2 scenarios. For example; when would you ever call |
I have, but the difference would be so small that it's better to keep the API simple.
You can parse |
Sure, but there is no scenario where you don't want to parse in data. I would argue that the API today is almost too simple, as it does not guide the developer on what arguments to pass in. But again, it's another discussion 🤔 |
|
I will have a fix added soon. |
|
Nice catch @alexbjorlig, I like how this turned out! Will be very useful for v2 as well. |
Hi @ciscoheat based on the discussion here Alex and I have attempted to add a strict option to superValidate
The attempt was to get superValidate to return errors if the input does not satisfy the provided schema. The heavy lifting is still done by Zod this PR just removes default values when strict=true so that the input is parsed directly.
We've added several tests which is probably the best way to examine our intention.
I tried to find the documentation, so I could add that as part of this PR - but I could not find it? is it in another project?