Custom paths for custom validation errors #948
Replies: 5 comments
-
You can already return custom error messages per field and different error messages per field. The way I solved this is to simply throw a custom error within the validation code you use inside of your Refine function. Just pass the field and the error message for each validation branch to your custom error and then wrap your call to Check in a try/catch clause. A typeguard function using instanceof will ensure you are catching your custom error and from there on you have all the information present in the custom error instance. This approach works well for me, however I'm not using react-hook-form, as that lib ships with Zod and I prefer @sinclairzx81's lib. (Please excuse the ping but I thought you might want to intervene in case this approach is an anti-pattern.) |
Beta Was this translation helpful? Give feedback.
-
@matjaeck That's not generic, I think the best way to accomplish this it to add 'errorMessage' to Type.String({ minLength: 10, errorMessage: 'Message too short'}) |
Beta Was this translation helpful? Give feedback.
-
Hi @Lonli-Lokli I did this, but if you have a union of objects, the typeboxResolver will only show an error for the union, not the specific fields, as @peguerosdc described in point 3. @peguerosdc, did you manage to find any solutions? Our codebase relies heavily on TypeBox, and we would love to use it in React as we are transitioning from Angular to React. |
Beta Was this translation helpful? Give feedback.
-
@abuaboud exactly, that doesn't work either. I couldn't fully resolve it with TypeBox and ended up having to manually validate the more complex parts of my schema, directly appending the results to the output of react-hook-form (which is not coupled to If you're using this library too and are okay with the trade-offs, you'll need to set up a custom resolver like this: import { Resolver } from "react-hook-form";
import { Static, Type } from "@sinclair/typebox";
import { typeboxResolver } from "@hookform/resolvers/typebox";
const schema = Type.Object({...});
type SchemaType = Static<typeof schema>;
export const myResolver: Resolver<SchemaType> = async (
data,
context,
options,
) => {
const baseResult = await typeboxResolver(schema)(data, context, options);
return {
values: baseResult.values,
errors: {
...baseResult.errors,
// This is the result of my custom validation:
rootField: {
validatedField: {
type: "required",
message:
"This is my custom error to show up for field 'rootField.validatedField'",
},
},
},
};
}; Optionally, if you need to call it without react-hook-form's hook, you can do: const data: SchemaType = {...};
const errors = (await myResolver(
data,
{},
{ fields: {}, shouldUseNativeValidation: undefined },
)).errors; Would be great to have a library that supports all of this natively AND is as fast and efficient as TypeBox. I hope this feature can be included, although I understand if it's beyond the intended scope. Btw: you could pull this off with |
Beta Was this translation helpful? Give feedback.
-
@peguerosdc @Lonli-Lokli @abuaboud @matjaeck Hi! Apologies for the delay in reply here (I've been exceptionally busy with other project as of late) So, I may convert this issue into a discussion as I think there is value in talking about better custom errors in TypeBox. Currently the following is TypeBox's answer to custom error messages. import { SetErrorFunction, DefaultErrorFunction } from '@sinclair/typebox/errors'
SetErrorFunction(params => params.schema.errorMessage ?? DefaultErrorFunction(params))
const T = Type.Union([
Type.Literal('A'),
Type.Literal('B'),
Type.Literal('C'),
], {
errorMessage: 'Expected A, B, C'
})
console.log(Value.Errors(T, 'D').First()) // { message: 'Expected A, B, C' } While the above works, I do think TypeBox could be doing a better job with Union error messages. Unfortunately things do get very sophisticated when working with nested Unions of Objects (where errors may originate deep within the Union), and at this point in time, there is no obvious / concise / ordered way to handle them. Consider const T = Type.Union([
Type.Object({ a: Type.Number(), x: Type.Number() }),
Type.Object({ a: Type.Number(), y: Type.Number() }),
Type.Object({ a: Type.Number(), z: Type.Number() })
])
Value.Errors(T, { a: 1 }).First() // what should the first error be?
// should this generate a invalid object error(s)?
// should x, y, z be generated as sub property errors?
// should all errors be wrapped in a outer error?
// - is there potential for DoS attack collecting all errors? This said, the above structures are very common (and I expect they would be quite common in forms). It's just that in order to produce something better, the above questions need some consideration so I know what to build :) Hope this brings a bit of insight into where things are currently at. Will convert to discussions for now, happy to field any questions on this, as well as take on suggestions as to how things could be improved. Cheers all! |
Beta Was this translation helpful? Give feedback.
-
Hi! Given the recent discussions on conditional validations (aka Refine) in the repo, I would like to share my use-case to expose one more need that is highly related and that I think would be a great addition to fully exploit their potential:
Context
I use
typebox
to do form validation using shadcn/ui + react-hook-form and I have been many times in the situation where I need to:How far can I get with typebox?
I have tried implementations with this Refine type and Unions and I am able to meet requirement 1, but not 2 and 3.
Both threads discuss about errors being too generic and provide a workaround that works for requirement 2 using
SetErrorFunction
, but still doesn't cover 3.Trying to be more concrete: I need to not only customize the error message, but also the path to which the error is related. This would allow me to highlight the specific form fields in the UI to catch the user's attention. In fact,
shadcn/ui
already does it but depends on the path.Based on what I have read in the repository I understand that this feature might not be considered soon, but if someday you think about Refine again (or any other more complex validation strategy), I hope you can consider this :)
Beta Was this translation helpful? Give feedback.
All reactions