-
-
Notifications
You must be signed in to change notification settings - Fork 156
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
Allow user handling of format
strings in OpenAPI
#1859
Comments
Hey @ntjess, just to understand, what do you want to do with this information? Are you trying to modify the runtime code? Types? Other? |
Correct -- the goal would be to ensure types autogenerated by In a perfect world, I can indicate in my OpenAPI spec that an argument's Current behavior: // In types.gen.ts
export type Metadata = {
Id?: string;
// Other fields...
} Desired optional behavior: // Intercept a `format: uuid` string and coerce its type into a branded alias.
// These types would be provided by the user, and IDString would be used by hey-api instead
export type IdTemplate = `${string}-${string}-${string}-${string}-${string}`;
export type IDString<T extends IdTemplate = IdTemplate> = T & {
readonly __brand: unique symbol;
};
// Resulting in this hey-api generated type:
export type Metadata = {
Id?: IDString;
// Other fields...
} With this change, I get helpful type errors passing non id-like strings to this API function. The same |
Ooh, I see. No runtime transformation needed? As long as it's scoped to types like this, it shouldn't be too difficult to add. Do you have a preference around how you'd want to define these types? Should it be handled perhaps out of the box? |
Indeed, no runtime transform needed. Just a mapping of I think it would be hard to define out of the box:
But, if you only considered branded types out-of-box, it might be doable. E.g. The downside is, calling these API functions would require: sdk.myEndpoint("1-2-3-4-5" as uuid)
// ^^^^^^^ explicit cast which is why not every client would want it by default. I prefer it, since explicit casting like this prevents user error when e.g. passing an email string instead of UUID string. In an ideal world, I could also control certain aspects of the autogeneration (for instance, exporting the name UUID instead of uuid). These could be extra args in the plugin configuration. |
Ok so you'll be doing casting like shown above? Do you need |
There's a few ways I can see this feature working:
// file openapi-ts.formats.ts
type UUID = string & { readonly __brand: unique symbol};
type Email = `${string}@${string}.${string}`;
export interface FormatHooks {
uuid: UUID;
email: Email;
duration: `${string} seconds`
// Add more formats here
}; // file openapi-ts.config.ts
plugins: [... "@hey-api/branded-formats"] This plugin would search for a file named I'm not sure if there's an easier way for the user to pass type information to the config, since ts doesn't allow passing an interface directly to a config. Thoughts? |
I like the plugin approach, though I'd be looking at keeping the configuration within |
Minor note: If this feature is natively supported, it would be nice if the generated Zod models also included the string-specific formats: https://zod.dev/?id=strings So including the |
Description
From OpenAPI docs:
The referenced JSON schema includes this:
TLDR: It's a way for generic types like
string
to be given more semantic meaning (by defining aformat: uuid
as an example).It would be great if
openapi-ts
allowed intercepting of commonformat
s (as defined in the JSON spec referenced above), allowing clients to handle them as branded types / custom classes/validators / etc.Here's one example that would be useful for me:
OpenAPI spec snippet:
I'm not sure what a middleware spec inside hey-api would look like, but hopefully this issue gets the ball rolling on client-defined conversion of known subtypes of primitives like
string
/number
.Thanks for considering!
The text was updated successfully, but these errors were encountered: