-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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 runtime validation to models #3528
Comments
We would need the ability to add custom validation rules. |
so.... until that happens.... what is the best way to do model validation today with prisma 2 ? |
Hey @orenmizr 👋🏼, Prisma validates input at runtime and throws an exception if validation fails (and the input data doesn't match the type in the Prisma schema) This is very useful in both JavaScript projects where there are no compile-time checks and TypeScript projects where payload/input data cannot be type-checked at compile time. ExampleGiven the following Prisma schema: This is the error that will be thrown with mistyped input in a JavaScript node.js script using Prisma Client:
|
thanks for replying 🙏
|
I'm unsure why this is not a thing - every good ORM should have the ability for easy validation, are there any 3rd party libraries that interface cleanly with Prisma for this? |
I guess another workaround is using something like |
is there any news on this? |
Yes, I think Prisma should have some method to go for runtime validation. |
It's worth noting here that even if Prisma were to provide an interface for runtime model validation, Prisma's type system is not quite as complex as the one a validation library would have. Prisma's type system is designed to abstract the various nuances between databases thereby simplifying the development experience and providing rich type safety. If it were to expose a model-based validation, changes to the PSL (Prisma schema language) would be necessary to validate things like email. Because for the Prisma schema to remain the source of truth, it would need to be able to represent this kind of information. |
How about configure the PrismaClient when insatiate it and pass joi objects, each object will represent a model, PrismaClient will run the validation and either thrown an error if validation failed or complete the execution if it succeed. As far as I know PrismaClient also do some basic validation and with joi integration we can get include the result of these validation in the same response, I am not sure but unique value validation might be done here and it is great to have unique value errors here. |
I also would like to see best practices regarding validation with prisma. :) |
Could be supercool if we could add metadata for generators to fields |
+1 for custom metadata. There is an issue #3102 but no movement there |
The ideas presented in #3102 seems really good, like: directive Email {
type String
validate <email regex here>
}
directive Salary {
type Number
validate v => v > 0
} Then being used like this: model User {
id Int @id
email String @unique @email
salary Number @salary
} An implicit conversion, say, a numeric string to a number (like mongoose does) would also be nice to prevent from manually having to cast the values or being too strict about types that JS considers "interchangeable" in some cases |
@GCastilho that's a great solution. Another option is to set these types when initiating |
@mmahalwy you mean like passing this validators when instantiating the |
As most of you know there is a widely powerful, standardized, spread, accepted specification for schema validation which is JSON Schema, thus not taking that solution/ecosystem into account for Prisma validations would be a mistake IMO. Since Prisma would never be able to replace data validation on all abstractions of a complete system, one would end up with writing validations and/or validation schema generators in more than one place if Prisma would implement an internal validator DSL, which would be unfortunate for such great potential of ecosystem. |
has anyone tried https://typegraphql.com/ ? thoughts ? |
I'm using it because it generates Classes instead of Types for model objects (works with https://github.com/clayrisser/nestjs-crud-prisma), but it doesn't add runtime validation. Actually, there is an issue mentionning it MichalLytek/typegraphql-prisma#35 |
In prisma-nestjs-graphql generator has implemented feature custom decorators which allow add |
Consider config option to generate raw types (like now) or zod-schemas (with runtime req/resp validation) or joi-schemas etc. |
We just wrote some documentation on how to add custom validation with Prisma: https://www.prisma.io/docs/concepts/components/prisma-client/custom-validation We do plan to implement this feature into the Prisma Client eventually, but this is meant to help you along in the meantime. If you'd like to chat about this topic or you have any questions, feel free to book some time with me. |
Prisma is an ORM which is responsible for managing database, not validations. We can live without it but If Prisma can make the experience better. That would be great. No Harm done! |
I have an use-case where I am trying work on a dynamic query language for my app. It is going to be used with But the object I am building is dynamic and I wish to validate the final object with the type based on table name. F.e. if table name is |
@2color I agree with your original suggested approach, it will be beneficial for a lot of cases. I would also like to have
|
My thoughts exactly, Prisma already makes types based on its models accessable, there are libraries that can build validations based on those types like class-validator or typescript-ts. Fun fact, I have been ORM hopping for the last few weeks, from Sequelize to TypeORM to here and imho Prisma has the most unique take on what an ORM should be concerned with, I like it the way it is, it's lean and mean, like Rocky right before he knocks out Ivan 😁 |
I think the big selling point of @prisma is that it is a one-stop solution for many database interaction features. If validators could be used on the frontend, it would mean less work for devs to keep validation in sync since we can use 1 source of truth, which would make Prisma the more valuable. I agree with the point that there are great validation libs out there which should be used in Prisma to hit the ground running instead of reinventing the wheel. It would be amazing if we could just import the validation rules from joi (or otherwise) and use the same rules for |
Just found out about Generators and community plugins. These might be what we are looking for: Especially:
Would be great if the guide would have an explicit page on how to convert validation to be used for front end form validation using generate and community plugins. @matthewmueller |
Here's how apollo is tackling the exact same problem: https://www.apollographql.com/blog/backend/validation/graphql-validation-using-directives/ |
Hey everyone, we just shared a proposal about Prisma Client Extensions. While this isn't going to perform validations via the schema, it will provide a way for you to store custom validation functions on your models (and perhaps create a generic one). Here's how it would work: const prisma = new PrismaClient().$extends({
$model: {
User: {
validate(user: object) {
// ... Use Joi, or Yup here
},
},
}
})
await prisma.user.validate(randomData) I am interested in receiving your feedback and suggestions in the Prisma Client Extensions proposal. Thanks! |
Good to see Prisma is taking this issue seriously! |
Thanks for the shoutout @MentalGear Recently, I have been thinking about doing validations in Prisma like this:
When generating the client, it also generates full crud schemas of the provider specified above, in the output directory also specified. Once they get generated, we can then incorporate them inside the suggested model methods way to do validations. It would be as simple as importing and executing them. Relying on known libraries like Joi, Zod, Yup, etc helps reduce the amount of work required to redo what they have been doing for years. So I see it as a plus for the Prisma team. Possible structure
AUTO_RUN ModeWhen this mode is selected all generated schemas will be run automatically before actions Which helps abstracting the entire validation layer away from the user and let them focus on the business logic instead. GENERATE_ONLY ModeThis mode does exactly what it means; generate the validations schemas and stop there.
Because this user either wants access to validation results or to customize/add more schemas. This can be done using the validate method described in the proposal: import { UserCreateOneSchema } from "./validations"
const prisma = new PrismaClient().$extends({
$model: {
User: {
async validate(user: object, opName: string) {
try {
if (opName === "createSuperCustomOne") {
const result = await UserCreateOneSchema.validateAsync(user);
return { result, error: null };
}
} catch (error) {
return { result: null, error };
}
},
},
}
})
const { result, error } = await prisma.user.validate(randomData) The example above should not completely replace the validate method defined by Prisma under the hood; it's just meant to add to whatever already there. So, default actions won't be affected unless overriding them was intentional. Maybe it would make more sense to rename the method to Also, the Prisma client or the generator in charge of generating the validation schemas, should not delete any custom schemas made by the user. Would love to hear your thoughts on this. |
Would be better if the prisma client can export both type and jsonschema (something like typebox), such that the user can choose their own library, like ajv or so, for validation. The query method can be configured such that the returned values are validated. |
Any updates / feedback on validation, @millsp ? |
A bunch of runtime validation API ideas: Model-level validationprisma.User.$useValidation({
name: (value) => {
// Custom validation logic here (Use whatever... zod, joi, etc.)
// Throw with error message if invalid or return if valid
}
// ...optionally define other fields
}) Support async validationprisma.User.$useValidation({
name: async (value) => {
// Perform async queries before making a decision
}
}) Native integrations with popular validation libraries for even better DXFor inspiration, see how tRPC supports this feature https://trpc.io/docs/v10/procedures#with-zod // E.g. with zod
import { z } from 'zod'
prisma.User.$useValidation({
name: z.string().min(2).max(100)
})
// Alternative
prisma.User.$useValidation(
z.object({
name: z.string().min(2).max(100)
})
) Bonus (prob overkill): support user-injected context object// Example use case: you might inject a request object
// ...or maybe your validation of one field depends on other the value of another field...
prisma.User.$useValidation({
name: async (value, ctx) => {
// Same as above
}
})
// Then when calling a method optionally inject context
await prisma.User.update({
// ...specify update inputs
context: { req } // E.g. include context object
}) Schema-level validation declarationsAn even better solution might be to support schema-level validation declarations like so: model User {
id Int @id @default(autoincrement())
email String @unique @validate('isEmail') @validate('min', 2) @validate('max', 100) // Declare runtime validations
email2 String @unique @validate('isEmail', ['min', 2], ['max', 100]) // Or combined syntax
name String?
// Support compound validations ??
@@validate('emailsHaveSameDomain', [email, email2])
} This way, you get closer to having a single source of truth. Then, when instantiating the client, the user must provide these definitions or the PrismaClient constructor will throw const prisma = new PrismaClient({
validations: {
isEmail: value => {
// Throw with error message if invalid
},
// OR with first-class support for popular validation libraries (e.g. zod)
isEmail: z.string().email()
}
})
// Alternate registration syntax
PrismaClient.useValidator('isEmail', () => {}) In other words, allow runtime validation declarations to exist on the schema, and leave implementation details to the end user at the time of client instantiation. |
IMHO this is not a bonus, but very important for i18n - e.g. when you have a multilingual application you must somehow pass information about the current user: i.e. the language, date-time format, number format (decimal separator, etc.). |
The problem I've run into mostly, is that I have to manually redefine classes/objects. I can write my own validation checks, but I don't think it makes sense to manually define a class or object to validate against. If the Prisma types that are exposed were classes or objects instead of interfaces, I'd be able to make comparisons against it. As it stands now, I'd have to manually create an object that mimicks the model/interface, and update it whenever the schema changes, thus losing the "single source of truth". |
|
Can we please make it in a way that I write the validation once and I can use it on the DB, the resolvers, and in the frontend? Meaning one single source of truth that can and should be used for validation everywhere. Thank you! |
Actually in a mono repo workspace you can write a single library for your type validation and use it on all apps found within the workspace |
I think you could use this from the documentation https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions/model#add-a-custom-method-to-all-models-in-your-schema |
Hi 👋 , I've just released a middleware called prisma-validation-middleware that validates data when creating or updating records, including when doing so through a relation. For example it's possible to validate the await client.post.update({
where: { id: 1 },
data: {
comments: {
connectOrCreate: {
where: { id: 2 },
create: [comment data you want to validate]
},
},
},
}); It is built to support a javascript validation function and supports using Zod, Superstruct or other 3rd party validation libraries. There are some examples for Zod and Superstruct in the readme. While this does mean that the Prisma schema is not the only source of truth, it does enable global validation of data while we wait for the I hope people find it useful! Please don't hesitate to raise any issues / feature requests. 🙏 p.s. If you are curious how it is handling nested write operations using middleware check out prisma-nested-middleware which this is built upon 😄 |
What's the status of this request. Has it been implemented? |
Problem
Before saving data to the database, it's common to perform validation.
When using Prisma to save user data (in an API), Prisma will perform runtime validation before saving to the database and throw an error if the user data doesn't match the type.
Even with TypeScript, these checks cannot happen at compile time because the user data is not known.
Since there are situations where you want to validate the data as a separate step to saving to the database, it'd be nice if Prisma exposed the same validation functionality as a standalone method on models.
Suggested solution
Provide a validate function for models which is based on the Prisma schema:
API ideas:
The idea is that If the input is valid, then the error will be undefined. If the input is invalid,
error
is assigned an Error object providing more information.OR
Additional context
For inspiration, Joi's validation errors might be useful (albeit more extensive as Joi has richer validation rules).
The text was updated successfully, but these errors were encountered: