Skip to content
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

feat: support more validation libraries #6

Open
juliusmarminge opened this issue Apr 25, 2023 · 19 comments
Open

feat: support more validation libraries #6

juliusmarminge opened this issue Apr 25, 2023 · 19 comments
Labels
PRs Accepted Feel free to pick this up and make a PR

Comments

@juliusmarminge
Copy link
Member

juliusmarminge commented Apr 25, 2023

Instead of

createEnv({
  server: {
    KEY: z.string(),
  }
});

it should be

createEnv({
  server: z.object({
    KEY: z.string(),
  })
});

and it should not be tied to zod, meaning something like scale-ts could work for example:
import * as $ from 'scale-codec';

createEnv({
  server: $.object(
    $.field('text', $.str)
  ),
});

this would require some more considerations for typings as we'd need to pull out the shape of each to get access to the raw keys to compare against the client prefix

Should probably implement #169 first in some half-generic way 🤔

@juliusmarminge juliusmarminge added the PRs Accepted Feel free to pick this up and make a PR label Apr 25, 2023
@chungweileong94
Copy link
Contributor

Probably need an adapter for each validator, for couple of reasons:

  • To tell the core how to extract the typing, mainly for validating client prefix, and type infer in general
  • To tell the core how to parse the env values. As we call .safeParse in zod, but we need to do it in different way for other validator.

@juliusmarminge
Copy link
Member Author

juliusmarminge commented Apr 26, 2023

We support a bunch of validators in tRPC:

https://github.com/trpc/trpc/blob/main/packages/server/src/core/parser.ts

https://github.com/trpc/trpc/blob/main/packages/server/src/core/internals/getParseFn.ts

But separate entrypoints could also work i guess:

import { createEnv } from "@t3-oss/env-core/zod";
const env = createEnv({
  // ...
  server: {
    FOO: z.string(),
  }
})

import { createEnv } from "@t3-oss/env-core/scale";
const env = createEnv({
  server: $.object(
    $.field('FOO', $.str)
  ),
});

@taylorallen0913
Copy link

Can I look into integrating Yup as an option alongside Zod?

@juliusmarminge
Copy link
Member Author

sure!

@aalakoski
Copy link

aalakoski commented Apr 28, 2023

Will it also export zod / other validators from within t3-env or would you still need to add zod as a dependency?
If not, could it be done?

Something like:

import { createEnv, z } from "@t3-oss/env-core/zod";

const env = createEnv({
  server: {
    FOO: z.string(),
  }
})

@chungweileong94
Copy link
Contributor

chungweileong94 commented Apr 28, 2023

@aalakoski Most probably no.

@SeanCassiere
Copy link

SeanCassiere commented Apr 29, 2023

Tanner's pattern of validating the router search params, could be something to consider here.

The process in t3-env would look like this.

  1. Make the client and server keys in the init of createEnv accept validation functions, that receive the values of
    process.env (or import.meta, ... etc.) as its argument.
  2. Then call the user-defined client and server validation functions to the ensure the values are adhere to the schema.

Code-example with zod:

import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

const env = createEnv({
  server: z.object({ FOO: z.string().min(1) }).parse,
  client: z.object({ BAR: z.string().min(1) }).parse
});

Code example with a custom validator

import { createEnv } from "@t3-oss/env-core";

// custom validator which could be swapped for Yup, Joi, etc....
type ServerVars = { FOO: string }
function serverValidator(values: any): ServerVars {
  // validation magic
  return { FOO: "FOOOOOOOOO" }
};

type ClientVars = { BAR: string }
function clientValidator(values: any): ClientVars {
  // validation magic
  return { BAR: "BOOOOOOOOO" }
};

const env = createEnv({
  server: serverValidator, // (values) => serverValidator(values)
  client: clientValidator // (values) => clientValidator(values)
});

This pattern completely opens it up to the user to bring their own validation libraries and logic into the picture, with t3-env making use of the type-safety returned by the defined validators as well as the libs' client-server separation stuff.

@juliusmarminge
Copy link
Member Author

Will it also export zod / other validators from within t3-env or would you still need to add zod as a dependency? If not, could it be done?

Something like:

import { createEnv, z } from "@t3-oss/env-core/zod";

const env = createEnv({
  server: {
    FOO: z.string(),
  }
})

No - we won't bundle the validator

@Bekacru
Copy link

Bekacru commented Jun 2, 2023

why does it need validation library tho isn't is simple enough task to do plainly? what am I missing?

@mattddean
Copy link

mattddean commented Jul 31, 2023

Did a very naiive valibot replacement.
Obviously it doesn't accomplish the goal here of not shipping a validation library, but it might be useful to someone.
https://github.com/mattddean/t3-env-valibot/tree/feature/valibot

@kaptinlin
Copy link

any plan support more validation libraies? i want use valibot instead of zod

@estubmo
Copy link

estubmo commented Aug 28, 2023

Did a very naiive valibot replacement. Obviously it doesn't accomplish the goal here of not shipping a validation library, but it might be useful to someone. https://github.com/mattddean/t3-env-valibot/tree/feature/valibot

This seems to be no longer working, as parse is no longer a function of schemas.

@stunaz
Copy link

stunaz commented Aug 28, 2023

why not using the patterns as in https://github.com/react-hook-form/resolvers/tree/master ?

@chungweileong94
Copy link
Contributor

why not using the patterns as in https://github.com/react-hook-form/resolvers/tree/master ?

Yeah, maybe we have to, as Valibot provides a separate parse method instead of from the scheme. Of course I also aware that they do have method from the scheme called _parse, but it's for internal use only, and I heard that it only provides some raw behavior.

@AlexisWalravens
Copy link

I just stumbled upon this issue, and maybe this could be useful https://typeschema.com ?
next-safe-action just implemented it in it's last version, allowing people to use almost every schema validator.

@Talent30
Copy link

I just stumbled upon this issue, and maybe this could be useful https://typeschema.com ? next-safe-action just implemented it in it's last version, allowing people to use almost every schema validator.

but it only supports async parse

@decs
Copy link

decs commented Feb 23, 2024

would you guys be open to making createEnv an async function? there are some considerations regarding top-level awaits, but maye we can figure something out

@juliusmarminge
Copy link
Member Author

I think we'd make a createEnvAsync in that case

@mwskwong
Copy link

mwskwong commented Apr 9, 2024

why not using the patterns as in https://github.com/react-hook-form/resolvers/tree/master ?

Yeah, maybe we have to, as Valibot provides a separate parse method instead of from the scheme. Of course I also aware that they do have method from the scheme called _parse, but it's for internal use only, and I heard that it only provides some raw behavior.

+1 for this pattern. It also opens for opportunity for contributors to contribute to more resolvers for various schema validation libraries, once the API of the resolver has been standardized.

BTW, is this the next big thing the team is planning? Is there any rough target date for making it happen? I would be happy to contribute (I really want a Valibot resolver) if this is the route the team is going.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PRs Accepted Feel free to pick this up and make a PR
Projects
None yet
Development

No branches or pull requests