graphql
graphql copied to clipboard
Integrate with graphql-code-generator and validation libraries
Is your feature request related to a problem? Please describe. I would love to use my Neo4j GraphQL schemas as the single source of truth for all my frontend forms as well as anything that can go into the db.
Currently I have to:
- create constraints in the db manually using Cypher
- basically clone my neo4j
.graphql
model to something like Zod to use on the frontend
Describe the solution you'd like It would be amazing if Neo4j's GraphQL offering just tightly integrated with a modern validation lib like Zod so I could write my schema files in one place like so:
input ExampleInput {
email: String! @required(msg: "Hello, World!") @constraint(minLength: 50, format: "email")
message: String! @constraint(startsWith: "Hello")
}
And these constraints would be valid in the db, and I could use the generated type in my frontend forms.
Describe alternatives you've considered
I've tried to use a few libraries to do something similar to this:
- https://github.com/withshepherd/graphql-codegen-zod (buggy, unmaintained, and doesn't work with graphql@16)
- https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema (a great project that tries to work with everything, but I still can't get its custom directives to work with my introspected graphql api)
Additional context
It seems like there is a big lack of modern validation going on with Neo4j (it's really something that has me worried about diving in). I think you can do it with Cypher and creating constraints, but even then you have to be on an "Enterprise" plan to get relationship constraints?
Is there any way for the little startup to get relationship constraints?
Is there any hope of a clean (something like Zod) way to add validation/constraints to our graphql schemas that are honored by the database?
We love this idea and it's been on our minds for a long time!
If we were to implement this in the library, I think constraints applied at the GraphQL make the most sense - essentially input validation on Mutations which would modify the database, and throwing an error if the input violates the constraints.
It might not make it's way into our planned work for a little while due to competing demands, however, we always welcome community collaboration if a contributor wants to pick this up!
Maybe. I'm on the fence about where validation should live.
I think it'd be better as Zod models that simply worked with Neo4j GraphQL. There are already tons of integrations with these validation libraries and other stuff. For instance check out this library where you can make a Zod model and then just pass it into react-hook-form to easily create clientside errors https://github.com/react-hook-form/resolvers and this library to get backend Express validation from the same Zod model https://www.npmjs.com/package/zod-express-middleware
If there was a way to do something like
import {SomeZodModel} from '~/YourZodModels'
export default gql`
input SomeNeo4jType {
email: String! @validationModel(SomeZodModel)
}
`
And use that same validation model in other places:
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import {SomeZodModel} from '~/YourZodModels'
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(SomeZodModel),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="submit" />
</form>
);
};
That would be amazing.
Maybe Neo4j GraphQL could just straight-up copy some open-source and package it up as part of core Neo4j GraphQL to offer the same functionality (and make some integrations with things like react-hook-form, Express, etc), but built into the GraphQL type? I'm not sure how that'd look and it seems like more work than simply
email: String! @validationModel(SomeZodModel)`
What are your thoughts? If we can figure this out and I can get some guidance I might be up for working on this.
There's some good ideas here for an eventual solution, but going to close this in favour of #138 which has been around for (a lot) longer and really the principal is the same. Thanks!