Closed IlyaSemenov closed 3 weeks ago
Instead of a string, you can also pass a function to any schema and validation action to dynamically generate the error message. The first argument of this function gives you access to the issue
object. Also, I will soon start working on a refine
action (issue #597) that will give you full control for such advanced cases.
const Schema = v.string((issue) => `Expected: ${issue.expected}`);
Thanks you for the heads up. However, this way of dynamically generating messages is quite limited. What I mean is, arguably, more often than not these dynamic messages will be based on validation context. In my example above, the message depends on extracted characters. This way, I basically need to repeat the logic twice, first in check
and then in the message generator.
In my real life use case, I am validating a textarea value which is supposed to store the whitespace delimited list of wallets where each wallet must be a valid base58-encoded public key. The validation is supposed to report the particular malformed string, or which keys are duplicate, or when it's not enough or too many of them and why — all and all, that are mostly context-dependent messages.
I hope refine
will make this possible!
Please have a look if rawCheck
solves this issue for you: https://github.com/fabian-hiller/valibot/issues/597#issuecomment-2168353406
It does:
const schema = v.pipe(v.string(), v.rawCheck(({ dataset, addIssue }) => {
if (dataset.typed) {
const [c1, c2, c3] = dataset.value
if (c1 === "f" && c2 !== c3) {
addIssue({ message: `Since the first letter is "${c1}", the second and third letters ("${c2}" and "${c3}") should equal.` })
}
}
}))
I'm still not really following why do we need the obligatory if (dataset.typed)
boilerplate in each and every check, but at least it gets things done, thank you.
It does
I think I was able to simplify your scheme. However, your version is probably a bit more readable.
import * as v from 'valibot';
const Schema = v.pipe(
v.string(),
v.check(
([c1, c2, c3]) => c1 !== 'f' || c2 == c3,
({ input: [c1, c2, c3] }) =>
`Since the first letter is "${c1}", the second and third letters ("${c2}" and "${c3}") should equal.`,
),
);
I'm still not really following why do we need the obligatory
if (dataset.typed)
boilerplate in each and every check, but at least it gets things done, thank you.
This is because I am working on validation actions that allow you to validate untyped data if the part of the data you want to validate is typed. This is really important for form validation. Without this functionality, we can't show errors that depend on multiple fields if any other field is untyped.
Thank you for the reply. Anyhow, this issue is fully resolved so I'm closing it.
As a developer using Valibot, I often want to generate validation error messages in runtime based on user input or other data. I didn't find a documented way to do so. In all examples, the error messages are predefined/hardcoded.
Consider the simplified schema:
Throwing
Error
orv.ValiError
doesn't work, the error is not captured andsafeParse
throws itself. Besides,ValiError
is not developer-friendly at all (one is supposed to pass 6 (!) non-optional non-obvious arguments).What I would expect, is some helper available in
v.check
andv.transform
callbacks, such as: