zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

[Feature Request] support for field validation in zod plugin #477

Closed ymc9 closed 1 year ago

ymc9 commented 1 year ago

Today with the @core/zod plugin, you can generate Zod schema for validating the typing of model entities and the related types for creating, updating, filtering, etc.

The request here is for the additional ability to attach custom field validations, so that the generated schemas can be used for many interesting use cases like form validation, user data upload validation (e.g., csv).

Detailed Thoughts

  1. Support of the validation "primitives" offered by Zod, like length, email, etc.

    For a related note: ZenStack already defines a set of validation attributes that "mirror" Zod's primitives here. However, these are only recognized by access policies, but not Zod generation.

    E.g.:

    model Foo {
        email String @email @length(3, 256)
        age @gt(0, 'age must be positive')
    }
  2. Support for custom validation, like Zod's refine or superRefine

    This can allow validation involving the comparison of fields.

    E.g.:

    model Foo {
        x Int
        y Int
        @@validate(x > y && y < 100, 'custom error message')
    }
  3. Support for arithmetic operators and data predicate functions

    Custom validations can be more flexible if we support arithmetic operations: +-*/, and data functions, like startsWith, regex, etc.

Besides being generated into Zod schema, the @@validate attribute should also be recognized by ZenStack's policy engine and used to validate data when creating and updating entities at runtime.

Open Questions

  1. How do we deal with relation fields used in the validation rules?

    
    model Profile {
        age Int
        user User @relation(...)
        userId @unique
    }
    
    model User {
       profile Profile
       @@validate(profile.age > 0)
    }

    We should probably just ban them if we can't see a compelling use case.

  2. Potential confusion about different ways of handling validation rules and access policy rules

    Access policy rules are compiled to Prisma query syntax and injected at runtime into Prisma queries. E.g., @@allow('read', x > 0) is transformed to { x: { gt: 0 } }. This limits what can be allowed for such expressions - they must be able to be expressed in Prisma query. E.g., @@allow('read', x + y > z) cannot be transformed.

    However, validation rules are evaluated in Node.js runtime (with Zod), so theoretically, there's no limit on what it can do.

    Having two sets of rules for expressions depending on where they're used can be very confusing IMO.

sw34 commented 1 year ago

We are building a prototype for a new app, so far were super happy with Zenstack. Funny this was just posted, I had "assumed" this was already available and was just this AM seeing how to wire in zod to validate forms and thought i could use the output from Zenstack!

For now I will maintain a seperate zod schema for my form validation, but this would be a great addition.

ymc9 commented 1 year ago

We are building a prototype for a new app, so far were super happy with Zenstack. Funny this was just posted, I had "assumed" this was already available and was just this AM seeing how to wire in zod to validate forms and thought i could use the output from Zenstack!

For now I will maintain a seperate zod schema for my form validation, but this would be a great addition.

More motivated to work on it now 😄! I'll share the plan soon and please comment here for any specific needs that you care about.

ymc9 commented 1 year ago

Hi @sw34 , the support has been added in the latest "beta.3" release. https://github.com/zenstackhq/zenstack/releases/tag/v1.0.0-beta.3