Open StephanMeijer opened 1 year ago
@StefanTerdell I am looking forward to your feedback!
By and large it LGTM. Some thoughts:
label
should be called title
. label
sounds to me like it could be a description or a title, and we already have describe
.exemplify
sounds a little odd to me, but then I'm not a native speaker. I guess based on [3] you're not 100% sure either though 😅 exemplify
but is there precedence in the current Zod API somewhere? Can we come up with some reason not to use it? I guess these values would not be validated outside of their type, so an error message parameter isn't one of themexemplify
be typed against Input
, infer | Output
, either or none? I'm a bit biased towards Input
as zod-to-json-schema
reflects that (kind of) but typically in TS you'd be using Output
. I'd like to see Array<Input | Output>
but maybe this should even be flagged somehow, or be different functions, ie .examplifyInput
/ .examplifyOutput
notes
, tags
and units
: in my opinion label
, description
and examples
should cover most cases and aligns with JSON schema as well.@StefanTerdell Thank you for your review
By and large it LGTM. Some thoughts:
- IMHO
label
should be calledtitle
.label
sounds to me like it could be a description or a title, and we already havedescribe
.
Yeah but with what verb? Titleize? I'm really not sure how to follow naming conventions on this one.
exemplify
sounds a little odd to me, but then I'm not a native speaker. I guess based on [3] you're not 100% sure either though 😅
Yeah, couldn't come up with another verb except for addExample
, setExamples
, etc, but that doesn't really follow naming conventions.
- I like the spread array syntax for the params in
exemplify
but is there precedence in the current Zod API somewhere? Can we come up with some reason not to use it? I guess these values would not be validated outside of their type, so an error message parameter isn't one of them
My current PR does not implement it, but I think it's a good point of discussion.
- Would the values in
exemplify
be typed againstInput
,infer | Output
, either or none? I'm a bit biased towardsInput
aszod-to-json-schema
reflects that (kind of) but typically in TS you'd be usingOutput
. I'd like to seeArray<Input | Output>
but maybe this should even be flagged somehow, or be different functions, ie.examplifyInput
/.examplifyOutput
It would be typed against unknown
, as that follows the type signature of .parse
^1 and .parseAsync
^2
- Regarding
notes
,tags
andunits
: in my opinionlabel
,description
andexamples
should cover most cases and aligns with JSON schema as well.
I do agree.tags
would not be compliant with the OpenAPI Specification ^3, therefore I don't see a use-case for this. Same goes for notes
and units
. The only use-case I can think of might be to add metadata for following API specifications like FHIR ^4, I feel confidence in @colinhacks to consider this as he writes on his blog to be working in the healthcare API sector. ^5
examplify
sounds like a Harry Potter spell or something.
Since the input and output matters here, how just calling it .sampleInput
and .sampleOutput
?
Would be great if #2387 was included in this as well, if it isn't already. Especially having the label
available in the error map when generating error messages, would make it a lot easier to generate proper accessibility compliant error messages. It would make it possible to replace e.g. too short
with "Password" is too short
or The "Password" needs to be longer
.
Currently in our solution we've had to work around this by authoring all error messages in a way that they can always be appended to a label, and then it's stuck together by an error message component instead. But that's not very flexible, and the error messages sometimes become kind of awkward since it doesn't always make sense to have the label at the start. 😕
Great proposal @StephanMeijer !
I think something we haven't discussed yet is whether this metadata should have a well-known structure vs. just allowing arbitrary Record<string, string>
. Or maybe even Record<string | symbol, string>
and have Zod and other libraries publish their own Symbols?
My hesitation to support having a well-known structure is that then Zod becomes the intermediary between libraries who want to attach metadata, the end users, and between different libraries who might have different goals.
Definitely not a hard blocker, since I know other libraries have chosen the well-known structure route, but I think it would be useful to at least discuss the pros and cons from the perspective of Zod itself, library authors, and end users.
@StephanMeijer - Yeah but with what verb? Titleize? I'm really not sure how to follow naming conventions on this one.
True 🤔 Same issue with label
though
@Svish - Since the input and output matters here, how just calling it .sampleInput and .sampleOutput?
I like this syntax FWIW. Typing it to unknown seems a bit odd in this case and would invariably create stale examples.
@Svish - [...] would make it a lot easier to generate proper accessibility compliant error messages.
I think that idea has been considered and rejected already in #1767
@scotttrinh - I think something we haven't discussed yet is whether this metadata should have a well-known structure
Great point. As far as sample data goes I think it would be useful to have a typed interface based on input- and/or output types, since this could serve as inline documentation in the Zod schema code itself. It's a little harder to see the use-case for label/title, especially with the error message case being rejected. Serving the schema to a custom error message parser could be a future case for this but yeah.
However, one thing need not exclude the other. Collecting some well known keys such as the ones described here and having them typed but still allowing for additional keys containing whatever you want and collecting them into a meta
key could be one approach. Something like this:
type ZodMeta<Input, Output> = {
title?: string;
description?: string;
inputExamples?: Input[];
outputExamples?: Output[];
[key: string]: unknown;
};
The current describe
and description
props could simply point into this meta object as well for backwards compatibility.
Just a thought ofc
@Svish - [...] would make it a lot easier to generate proper accessibility compliant error messages.
I think that idea has been considered and rejected already in #1767
The idea considered and rejected in #1767 was the label
itself, regardless of its use, but that's exactly what this issue, #2548, is adding, or am I misunderstanding something? I just wish for that label to be available in the error handler, as it would make accessibility much easier to do.
@Svish That would be indeed a proper usecase, Shall I add it to the proposal?
@Svish That would be indeed a proper usecase, Shall I add it to the proposal?
Please do 😊👍
However, one thing need not exclude the other. Collecting some well known keys such as the ones described here and having them typed but still allowing for additional keys containing whatever you want and collecting them into a meta key could be one approach. Something like this:
type ZodMeta<Input, Output> = { title?: string; description?: string; inputExamples?: Input[]; outputExamples?: Output[]; [key: string]: unknown; };
@StefanTerdell I'd rather see an implementation where inputExamples
and outputExamples
can be bound to eachother.
I hereby request feedback from the following developers:
I think the proposal can possibly affect your implementation in positive sense, therefore I would like to know if I can ask for your feedback and take it into account for this proposal.
Would be nice to have both if we can't have .meta()
I was looking for something like this a while ago, my goal was to wire up a Zod schema as the source of truth for the validation and labels of a react hook form. Unfortunately there was no way to access the data I needed for this. Some form of metadata would be very useful for advanced use-cases like this.
I'm also a fan of codegen, and while I prefer to generate from a static schema (such as OpenAPI) generating TypeScript code is a bit of a minefield so with Zod in a project, it's nice to go the other way around (Zod -> code) and having additional metadata could help here.
To play devil's advocate however, this could be considered unnecessary bloat. There's already a way to get the name of a field, so why does a field need a second name defined? (namedString
and NamedString
in the first example)
+1. It'd be great to be able to, for example, on the server send through the Schema('s .shape) and then on the UI automatically build a form from that schema. Suggested keys and then custom keys sounds good.
Also, how would multiple meta be handled,
The former would be easier to work with (and probably people's first expectation), but the latter is more flexible (though I doubt people would need that level of granularity)
It's so odd to me why there is no .label() or alternative that works like Joi. How are my app users supposed to understand what is an Array ?
@bardouni
How are my app users supposed to understand what is an Array
For this use-case, you can set a custom error message as the last argument to most of the schema parts, so in this case you'd set .min(1, "Must contain at least one item")
for a more user-friendly non-technical error message.
@bardouni
How are my app users supposed to understand what is an Array
For this use-case, you can set a custom error message as the last argument to most of the schema parts, so in this case you'd set
.min(1, "Must contain at least one item")
for a more user-friendly non-technical error message.
Using custom error messages is not really feasible. For consistent error messages, it's much better to use a global error map.
The challenge is that error messages, to be accessible, should be referencing the name of the field it belongs to, which is not possible with zod because there's no label and even if it was, it's not available in the error map when generating the error message.
In our app we've currently worked around it by writing all error messages in a way that it can be appended to the field label, and then in the error component it will display label + ' ' + message
.
This kind of works, but isn't very flexible. Would be much better if there was a way to label schemas and a way to access that label in the error map when generating an error for that field.
Feature Proposal: Functionalities for adding label and example(s)
Introduction
This proposal aims to introduce new functionalities to Zod, drawing inspiration from the capabilities of Joi. The proposed enhancements will allow users to assign labels as well as ability to set or add input examples. The primary objective of these enhancements is to augment Zod's capabilities, enabling the extraction of vital data necessary for tasks such as constructing OpenAPI specifications.
Detailed Description
1. Setting name [^1][^3]
The proposed feature will allow users to set names for their schemas. This will provide more context about the data and make it easier for developers to understand the purpose of each schema.
In style of .describe I propose the following:
.name
Use property
name
via the constructor to add aname
property to the resulting schema.This can be useful for documenting a field, for example in a JSON Schema using a library like zod-to-json-schema).
This property is available in the error map when generating error messages.
2. Setting and Adding Example(s) [^2][^4]
In addition to setting descriptions and labels, the proposed feature will also allow users to set or add examples of input. This will provide a practical illustration of how the schema should be used, making it easier for developers to understand and implement.
In style of .describe I propose the following:
.exemplify
Use
.exemplify()
to add add anexamples
property to the resulting schema.This can be useful for documenting a field, for example in a JSON Schema using a library like zod-to-json-schema).
Benefits
The foremost benefit of this proposal is the enhanced ability to extract data from Zod. This is crucial for tasks such as building OpenAPI specifications. By providing more context about the data (through descriptions and labels) and practical examples of use, developers will find it easier to understand and use the schemas. This, in turn, will lead to more efficient development processes and higher-quality output.
Conclusion
The proposed enhancements to Zod, inspired by Joi, will significantly improve the platform's functionality and usability. By allowing users to set labels and examples of input, we can make Zod more intuitive and effective for developers. This will ultimately lead to better data extraction capabilities, which is crucial for tasks such as building OpenAPI specifications.
Earlier proposals
1439
1767
1443
1902
2387
Pull Requests made
2549
Points of discussion
notes
?[^5]tags
?[^6]unit
?[^7][^1]: For
name
we need other words, as the function cannot be the same as the property being set. [^2]: I am open for using another term. [^3]: Inspired by https://joi.dev/api/?v=17.9.1#anylabelname [^4]: Inspired by https://joi.dev/api/?v=17.9.1#anyexampleexample-options [^5]: Inspired by https://joi.dev/api/?v=17.9.1#anynotenotes [^6]: Inspired by https://joi.dev/api/?v=17.9.1#anytagtags [^7]: Inspired by https://joi.dev/api/?v=17.9.1#anyunitname