kubb-labs / kubb

The ultimate toolkit for working with APIs.
https://kubb.dev
MIT License
668 stars 53 forks source link

Allow specifying which types to coerce [plugin-zod] #1281

Open ChilloManiac opened 10 hours ago

ChilloManiac commented 10 hours ago

What is the problem this feature would solve?

I'm using Kubb for a serverless API, and i use to to generate Zod-schemas from my OpenApiSpec.

In this case I'm making use of the coerce feature of Zod. However this works better for some data-types than others.

In my case i would like to coerce for numbers (z.coerce.number()) and not strings, since they behave pretty badly ref.

Here's my current config

import { defineConfig } from '@kubb/core';
import { pluginOas } from '@kubb/plugin-oas';
import { pluginZod } from '@kubb/swagger-zod';

export default defineConfig({
  input: {
    path: './test/openapi-spec.yaml',
  },
  output: {
    path: './test/generated',
  },
  plugins: [
    pluginOas({
      output: {
        path: '.json-schemas',
      },
      validate: true,
    }),
    pluginZod({
      output: {
        path: 'schemas',
      },
      typedSchema: true,
      dateType: 'stringOffset',
      unknownType: 'unknown',
      coercion: true,
      importPath: 'zod',
    }),
  ],
});

I would like to add another option to the Zod plugin

export type Options = {
   ...
   coerceTypes: { // Default value would be true for all, to be backwards compatible
     date: boolean
     strings: boolean
     number: boolean
   },
   ...
}

And then use that in conjuction with the coercion option, to enabled coercion.

I'd be down to write the PR as well, if you accept this enhancement.

stijnvanhulle commented 10 hours ago

This was already something that was requested before so I was planning to add this as part of Kubb v3. More people needs this so happy to see some ideas here.

What if we just use one option to specify the coercion:

When true it will reuse the same logic as of today but you can then also allow an object where an user of Kubb can specify what primitive needs coercion.

This means that behind the scenes we will transform true into an object { date: true, string: true, number: true }

export type Options = {
   ...
   coercion: boolean | {
     date?: boolean
     string?: boolean
     number?: boolean
   },
   ...
}

Thoughts and thanks in willing to take this up?

ChilloManiac commented 10 hours ago

That was actually my original thought, but was unsure if i should propose it as such, as i was unsure if putting new logic into an existing option would be frowned upon. So i'll agree with that.

I'll give it a go, if the implementation becomes too clunky, i'll reach out 😄 and nice project you've gotten here, happy to help

stijnvanhulle commented 9 hours ago

@ChilloManiac Aha great to hear, with v3(which is now being used on the master branch) we will already have a major bump so I'm not seeing issues in doing it this way(can also be added to v2 if needed). coercion is already passed through so probably changing the type with some changes in plugin-zod/src/parser/index.ts will workout.