Ensuring Type Safety in GraphQL Mutations with GenQL and Zod

By
Explore our comprehensive approach to ensuring type safety in Composabase, where we leverage the power of GenQL and Zod, enabling you to confidently connect GraphQL to your applications for enhanced reliability. Once you experience the benefits of a typesafe world, there's no turning back!

In our previous article: "Remix and GraphQL: A match made in heaven with type-safety DX", we did explore some benefits of using GenQL in Remix for efficient data loading in GraphQL. Let’s now dive into the writing part of GraphQL. We'll use the Zod library to discover how to enforce type safety while working with mutations using GenQL.

Defining Mutations:

Mutations in GraphQL allow us to create, update, or delete data. Let's consider an example mutation for making a movie:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mutation { movies { createOneMovie( data:{ title:"Spider-Man" director:"Sam Raimi" year: 2002 synopsis:"Peter Parker's life changes when he is bitten by a genetically altered spider and gains superpowers" cast:"Tobey Maguire, Kirsten Dunst, Willem Dafoe" genre:{ connect:{ name:"Thriller" } } } ){ id title } } }

With the help of Composabase, we can have a standard input depending on the types inferred from your data source. In the previous example, the year expects to receive an integer value, while the title or director needs a string; but the genre, a connection with other models, requires a more complex object.
 

Introducing Zod:

Maintaining end-to-end type safety when working with mutations can be challenging. For example, in Remix applications, type validation needs to happen at runtime rather than during compilation in TypeScript. How can we enforce typing in this scenario? We could build the validations by hand but that can be  tedious and error-prone.

We can leverage the power of the Zod library to create schemas that define the expected types and bounds of our data. Let's consider an example schema for making a movie:

1 2 3 4 5 6 7 8 const createMovieSchema = z.object({ director: z.string().min(1).max(255), genre: z.string().min(1).max(255), synopsis: z.string().min(1), cast: z.string().min(1), year: z.number().min(1900).max(2021), title: z.string().min(1).max(255), });

 

Using Zod for Validation:

With the help of Zod, we can now validate input objects against our schema, passed in the method parse of our createMovieSchema constant. For example:

1 2 3 4 5 6 7 8 const result = createMovieSchema.parse({ director: "Quentin Tarantino", genre: "Crime", synopsis: "The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption.", cast: "John Travolta, Uma Thurman, Samuel L. Jackson", year: 1994, title: "Pulp Fiction", });

If all the properties match the schema, the result object will contain the validated data. However, if any property is missing or fails the validation, Zod will throw an exception at runtime, allowing us to handle unexpected scenarios and prevent potential bugs.

1 2 3 4 5 6 const result = createMovieSchema.parse({ director: "Quentin Tarantino", genre: "Crime", year: 1994, title: "Pulp Fiction", });

 

Building Type-Safe Mutations:

We can confidently build the GenQL mutation with the validated result object, ensuring type safety throughout the process. Here's an example of how we can construct the mutation using the result object:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const result = createMovieSchema.parse(inputObject) const mutation = client.mutation({ movies: { createOneMovie: { __args: { data: { director: result.director, genre: { connect: { id: result.genre, }, }, title: result.title, synopsis: result.synopsis, year: result.year, cast: result.cast, }, }, id: true, }, }, });

By using the validated properties from the result object, we can build the mutation confidently, knowing that the data passed to the server adheres to the expected types and constraints.


Wrapping Up:

Ensuring type safety in GraphQL mutations is crucial for maintaining data integrity and preventing runtime errors. By combining the power of GenQL and the Zod library, we can enforce type validation during runtime, allowing us to build type-safe mutations confidently. Incorporating Zod schemas also allows extending type safety to the front end, streamlining form validation. By leveraging these tools, we can enhance the robustness and reliability of our GraphQL applications.

At Composabase, we take type safety further by leveraging Zod schemas to build forms based on these validations. This approach allows us to achieve front-end validation by writing the logic only once, saving time and reducing the likelihood of errors, but that's a story for another day!
 

Share with others

Try Composabase Now!

Find how to improve your DX by leveraging the true potential of GraphQL.