edgedb-js icon indicating copy to clipboard operation
edgedb-js copied to clipboard

RFC: New generator: Zod

Open spigelli opened this issue 3 years ago • 5 comments

The ability to opt in to zod schema generation would be awesome not sure how $infer works behind the scenes (if it has runtime type understanding)

I'm wanting this for trpc but it has a lot of other benefits (bit more validation than just a type and others I'm sure)

the trpc use-case:

export const t = initTRPC();
 
/*
type Movie {
  required property id -> uuid;
  required property title -> str;
  required property release_year -> int16;
}
*/

const select = {
  title: true,
  release_year: true
}

const insertMovie = e.params(
  einfer(e.Movie, select), // this would be cool but not really the point of this example
  (params) => {
    return e.insert(e.Movie, params);
  }
);

const zodMovie = zinfer(e.Movie);
const zodSchemaWithJustId = zodMovie.pick({ id: true });
const zodInput = zodMovie.pick({ title: true, release_year: true });

/*
zod move is
z.object({
  id: z.uuid,
  title: z.string,
  release_year: z.number().positive().int().max(65535) // max for unsigned 16 bit int is 65535
});
*/

// trpc v10
const movieProcedure = t.procedure.input(zodSchemaWithJustId);
 
const appRouter = t.router({
  createMovie: movieProcedure,
    .input(zodInput)
    .mutation(({ input }) => {
      return insertMovie.run(client, input);       
    }),
});

spigelli avatar Aug 31 '22 23:08 spigelli

I like this idea a lot, I feel like it would play nicely with this RFC: https://github.com/edgedb/edgedb-js/issues/361. In fact Zod is mentioned in the RFC.

Sikarii avatar Sep 01 '22 01:09 Sikarii

This is not just wanted, but actually REQUIRED

hanayashiki avatar Feb 07 '23 01:02 hanayashiki

One tricky bit here is not depending on Zod itself and having it be a peerDependency and tracking changes to Zod here: changes to Zod's API would have potentially breaking changes to the generator. Definitely doable and I see a lot of value in being able to map EdgeDB types -> Zod. The other way around is pretty lossy, so we'll need to define exactly what the supported use cases and user flows we would want are.

Probably some prior art with similar projects we can lean into and learn from here.

scotttrinh avatar May 03 '23 16:05 scotttrinh

+1 Hoping to have generated constraints/validations that are consistent with EdgeDB, which can then be used by Zod, Typebox and other tooling.

grokwich avatar Aug 18 '23 12:08 grokwich

There is a zod schema generator for prisma.

I find it useful for form validation that works both in the client and server. Of course the server will have extra validation.

But there are many open questions:

  • How to customize the validation of a field. In this library, it's done in comments 🧐
    • to customize error messages
    • to change the type
  • How to customize the validation of a type (e.g Bytes is treated as Buffer which isn't native in the browser): in this lib, it's currently not possible, the workaround is to install buffer and add a comment 🧐 with import
/// @zod.import(["import Buffer from 'buffer'"])
model MyModel {
  myField String /// @zod.string.min(3, { message: "min error" }).max(10, { message: "max error" }).[...chain more validators]
}

The prisma generator throws when there is an error, which is nice.

Pros

  • It's nice to have Form (data) validation within the schema which makes it easier to maintain and also better understand the constraints (a string is actually an email, an IBAN ...)
  • Can use most of Zod validation goodies.

Cons

  • it's not "clean" to have code live in comments. This could be made a bit better if the tooling detects errors in vscode and has autocomplete, but still ...
  • Filling the schema with form validation (very long) comments makes it ... unreadable :/

For edgedb

One possible way is to implement the same things using annotations ... But I'm not really fond of it, as it will have the same cons. What I would like to do is to actually implement form validation at the schema level using edgeql and be able to generate a client side form validator in wasm that I could use in the client (browser, mobile ...). In the server side, I'd lean on EdgeDB to do validation natively.

This is probably NOT possible since some EdgeDB standard functions are defined in SQL. But it should be possible to do with an extension, especially if there is a wasm extension that enables running wasm in edgeql.

I think it's important for the db and the schema to ACTUALLY be the source of truth. And data/form validation are part of that "truth"

haikyuu avatar Sep 14 '23 06:09 haikyuu