t3-env
t3-env copied to clipboard
feat: support more validation libraries
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 🤔
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.
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)
),
});
Can I look into integrating Yup as an option alongside Zod?
sure!
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(),
}
})
@aalakoski Most probably no.
Tanner's pattern of validating the router search params, could be something to consider here.
The process in t3-env would look like this.
- Make the
client
andserver
keys in the init ofcreateEnv
accept validation functions, that receive the values ofprocess.env
(orimport.meta
, ... etc.) as its argument. - Then call the user-defined
client
andserver
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.
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
why does it need validation library tho isn't is simple enough task to do plainly? what am I missing?
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
any plan support more validation libraies? i want use valibot instead of zod
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.
why not using the patterns as in https://github.com/react-hook-form/resolvers/tree/master ?
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.
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.
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
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
I think we'd make a createEnvAsync
in that case
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.