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

Support for custom validation #37

Closed
pierreis opened this issue Apr 22, 2020 · 7 comments
Closed

Support for custom validation #37

pierreis opened this issue Apr 22, 2020 · 7 comments

Comments

@pierreis
Copy link
Contributor

Is there any plan to support custom validation?
It could be of the form: z.string().validate(someValidationFunction).

That would be a great help to build advanced schemas.

This could also take the form of custom types, but for now, z.ZodType / z.ZodTypeDef not being exposed as part of the API make it a hack IMO.

@pierreis
Copy link
Contributor Author

pierreis commented Apr 23, 2020

One way to perform this would be to add in a method in ZodType of the form:

validate(fn: Predicate<Type>, msg: ErrorMsg<Type>) => ZodType<Type, Def>

With:

type ErrorMsg<T> = string | ((obj: T) => string)
type Predicate<T> = (t: Type) => boolean

Predicates could be passed to the parser, and checked after type validation.

This would be a strong base to implement Joi-like validation methods, while remaining compatible with the various libraries offering predicate-base data validation for the time being. It would ease the implementation of custom types:

const uuid = z.string().validate(isUUID, (v: string) => `${v} is not a UUID`)

This relates to #3.

@colinhacks
Copy link
Owner

This is doable. I'm working on a big rewrite currently (probably gonna be Zoe 2) and I'll include this in that release.

@pierreis
Copy link
Contributor Author

Sounds great. Do you need help in doing so?

@colinhacks
Copy link
Owner

The codebase is currently not fit for human eyes...

In the meantime I just implemented .refine which will let you accomplish this. Documented here. Give it a try and let me know if you have any issues. 👍

@jjhiggz
Copy link

jjhiggz commented Dec 3, 2021

I don't see it in the documentation on this for some reason, but I'm wondering if this got added somewhere.

I was poking around and found a .custom on the z object, and got it to work by doing the following.

const isValidPhoneNumber = (phonenumber: string) => phonenumber.length > 3

const SignupValidation = z.object({
  email: z.string().email(),
  cell: z
   // Input 1 seems to be your validator function, which should return true or false depending on the input
   // Input 2 seems to be how you control what messages show up
    .custom(isValidPhoneNumber, { message: "Not a valid phone number" })
    .transform(parseInt),
})

Obviously that's not a real phone validation, but the logic works for implementing a custom validation.
You can ignore the transform key, and also the email in the validation. I just like providing a little extra context with these answers.

Update

I think this approach using refine is probably better because then zod can first verify the type, then refine that type. As a side bonus you can use the input value to make your error message which seems cool

    const isPhoneNumber = (ph: string) => ph.length > 4;
    const phoneNumberSchema = z.string().refine(isPhoneNumber, (val) => ({
      message: `${val} is not a valid phone number`,
    }));

It also means you can infer the schema type which you can not do with z.custom

@slaesh
Copy link

slaesh commented Apr 4, 2023

so, is there something to add a "custom" validator which would then infer a "custom type" aswell?

imagine using zod in combination with prisma, having a JSONB field.. which should get a custom validation and should be properly typed for the app. :)

@slaesh
Copy link

slaesh commented Apr 4, 2023

probably found it: z.custom<{ arg: string }>

RobinTail added a commit to RobinTail/express-zod-api that referenced this issue Jan 10, 2024
I was dreaming about it.
Unfortunately `zod` does not provide any way to make a custom or branded
or third-party schema that can be identified as one programmatically.
Developer of `zod` also does not want to make any method to store
metadata in schemas, instead, recommends to wrap schemas in some other
structures, which is not suitable for the purposes of `express-zod-api`.
There are many small inconvenient things in making custom schema
classes, that I'd like to replace into native methods, and use
`withMeta` wrapper for storing proprietary identifier, so the generators
and walkers could still handle it.

Related issues:

```
colinhacks/zod#1718
colinhacks/zod#2413
colinhacks/zod#273
colinhacks/zod#71
colinhacks/zod#37
```

PR I've been waiting for months to merged (programmatically
distinguishable branding):

```
colinhacks/zod#2860
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants