Migrating to Kubb v3
New Features
Static Class Client
You can now generate API clients as classes with static methods using clientType: 'staticClass' in @kubb/plugin-client. This allows you to call API methods directly on the class without instantiating it:
// Before
const client = new Pet()
await client.getPetById({ petId: 1 })
// After
await Pet.getPetById({ petId: 1 })See the plugin-client documentation for details and usage notes.
Generators
TIP
Generators are a replacements of templates
See Generators.
kubb.config.ts
2 extra options have been added to the output:
output.extension
In the latest Node.js version, file extensions are required, so we automatically add .ts to every file. However, not all projects use the latest Node.js configuration for extensions. With this option, you can remove the extension or use .js instead.
See output.extension.
output.barrelType
Specify how index.ts files should be created, this will work for the root index.ts file. On plugin level there is also a new option to define this.
See output.barrelType.
Rewrite of the CLI
| Left: v3 | Right: v2 |
|---|
The CLI and core have been revamped for improved speed and in v3 it will also display more relevant information.
- Progressbar for the execution of plugins.
- Progressbar for the writing of files.
- Timestamps next to every command that is being executed.
- Better support for CI tools
- Use of TypeScript Strict
- 20-30% faster overall execution
- Debug mode(
--debug) that will create 2 log files.kubb/kubb-DATE_STRING.log.kubb/kubb-files.log
- All issues can be seen here: Kubb v3 ideas
Breaking Changes
Plugin renames
We previously used the name swagger to indicate that we only supported Swagger files. However, we now also support OpenAPI v3 and v3.1. This change allows for the potential integration of additional specifications beyond just OpenAPI files in the future.
TIP
Default imports are also being removed in v3 so you need to import a plugin as follow(support for better treeshaking for ESM):
import { pluginReactQuery } from '@kubb/plugin-react-query'
@kubb/swagger-clientbecomes@kubb/plugin-client@kubb/swagger-fakerbecomes@kubb/plugin-faker@kubb/swagger-mswbecomes@kubb/plugin-msw@kubb/swaggerbecomes@kubb/plugin-oas@kubb/plugin-tanstack-querybecomes@kubb/plugin-react-queryfor React@kubb/plugin-tanstack-querybecomes@kubb/plugin-solid-queryfor Solid@kubb/plugin-tanstack-querybecomes@kubb/plugin-svelte-queryfor Svelte@kubb/plugin-tanstack-querybecomes@kubb/plugin-react-queryfor Vue@kubb/swagger-redocbecomes@kubb/plugin-redoc@kubb/swagger-swrbecomes@kubb/plugin-swr@kubb/swagger-tsbecomes@kubb/plugin-ts@kubb/swagger-zodbecomes@kubb/plugin-zod@kubb/swagger-zodiosbecomes@kubb/plugin-zodios
Tanstack-query
We will discontinue support for (Tanstack-Query](https://tanstack.com/query/latest/docs/framework/react/overview) v4 in favor of v5. If you still require generation for v4, you can use Kubb v2. Additionally, each framework will now be packaged separately instead of being included in a single package that contains code for all frameworks.
| Framework | Packages |
|---|---|
'react' | '@kubb/plugin-react-query' |
'solid' | '@kubb/plugin-solid-query' |
'svelte' | '@kubb/plugin-svelte-query' |
'vue' | '@kubb/plugin-vue-query' |
import { defineConfig } from '@kubb/core'
import { pluginOas } from '@kubb/plugin-oas'
import { pluginTanstackQuery } from '@kubb/swagger-tanstack-query'
import { pluginReactQuery } from '@kubb/plugin-react-query'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginTs(),
pluginTanstackQuery({
output: {
path: './hooks',
},
framework: 'react',
}),
pluginReactQuery({
output: {
path: './hooks',
},
}),
],
})MSW
We will discontinue support for (MSW](https://mswjs.io/) v1 in favour of using v2. If you still need to generate mocks for v1, you could use Kubb v2.
Output
output.banner: Add some code in the beginning of every fileoutput.footer: Add some code in the end of every fileoutput.exportType: Behavior stayed the same, we renamed the option tooutput.barrelTypeand simplified the values.
import { defineConfig } from "@kubb/core"
import { pluginOas } from "@kubb/plugin-oas"
import { pluginTs } from "@kubb/plugin-ts"
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
root: '.',
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginClient({
output: {
exportType: false,
barrelType: false,
},
}),
pluginClient({
output: {
exportType: 'barrel',
barrelType: 'all',
},
}),
pluginClient({
output: {
exportType: 'barrelNamed',
barrelType: 'named',
},
}),
],
})output.extName: Rather than defining this in every plugin, we chose to move it tooutput.extension.
import { defineConfig } from "@kubb/core"
import { pluginOas } from "@kubb/plugin-oas"
import { pluginTs } from "@kubb/plugin-ts"
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
root: '.',
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
extension: {
'.ts': '.js',
},
},
plugins: [
pluginOas(),
pluginClient({
output: {
path: './clients/axios',
extName: '.js',
},
}),
],
})output.exportAs: This property was only usable for@kubb/plugin-clientwhere we aimed to consolidate the functionality into one single controller. In v3, usinggroupwill already create the controller file.
import { defineConfig } from "@kubb/core"
import { pluginOas } from "@kubb/plugin-oas"
import { pluginTs } from "@kubb/plugin-ts"
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
root: '.',
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginClient({
output: {
path: './clients/axios',
exportAs: 'clients'
},
group: {
type: 'tag',
name({ group }){
return `${group}Controller`
}
}
}),
],
})import { addPet } from './addPet.js'
import { deletePet } from './deletePet.js'
export function petService() {
return { addPet, deletePet }
}Group
group.output: Removed in favour of usinggroup.name, the output will automatically be created based on theroot,output.pathandoutput.pathof the selected plugin.
import { defineConfig } from "@kubb/core"
import { pluginOas } from "@kubb/plugin-oas"
import { pluginTs } from "@kubb/plugin-ts"
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
root: '.',
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginClient({
group: {
type: 'tag',
output: './clients/axios/{{tag}}Service',
name: ({ group }) => `${group}Service`,
},
}),
],
})group.exportAs: This property was only usable for@kubb/plugin-clientwhere we aimed to consolidate the functionality into one single controller. In v3, usinggroupwill already create the controller file.
import { defineConfig } from "@kubb/core"
import { pluginOas } from "@kubb/plugin-oas"
import { pluginTs } from "@kubb/plugin-ts"
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
root: '.',
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginClient({
output: {
path: './clients/axios',
},
group: {
exportAs: 'clients',
name({ group }){
return `${group}Controller`
}
}
}),
],
})import { addPet } from './addPet.js'
import { deletePet } from './deletePet.js'
export function petService() {
return { addPet, deletePet }
}More
- Minimal support of Node 20
- Refactor of grouping(use of name instead of output) and output based on
outputof the current plugin - Removal of the Zodios plugin
Plugin Specific changes
@kubb/plugin-oas
We used openapi-format before to already filter out some Operations or Paths but in v3 this has been removed in favour of using https://github.com/thim81/openapi-format before using your Swagger/OpenAPI in Kubb.
experimentalFilterexperimentalSort
See Filter And Sort.
@kubb/plugin-client
client.importPathbecomesimportPathoperationswill control the creation of a file with all operations grouped by methods.parserwill make it possible to chose between using no parser(client) or using Zod(zod).paramsTypewill make it possible to have one object to pass your pathParams, params, headers and data.
@kubb/plugin-ts
enumSuffixwill be'enum'by default.mappercan be used to override which TypeScript TsNode that should be used.
@kubb/plugin-zod
typedSchemabecomesinferredoperationswill control the creation of a file with all operations grouped by methods.mappercan be used to override which Zod primitives that should be used.
@kubb/plugin-faker
mappercan be used to override which Faker functionality that should be used.
@kubb/plugin-swr
dataReturnTypebecomesclient.dataReturnTypepathParamsTypesame as in@kubb/plugin-clientparsersame as in@kubb/plugin-clientqueryKeysame as in@kubb/plugin-react-queryquery.methodssame as in@kubb/plugin-react-queryquery.importPathsame as in@kubb/plugin-react-querymutationKeysame as in@kubb/plugin-react-querymutation.methodssame as in@kubb/plugin-react-querymutation.importPathsame as in@kubb/plugin-react-queryparamsTypewill make it possible to have one object to pass your pathParams, params, headers and data.
@kubb/plugin-react-query
dataReturnTypebecomesclient.dataReturnTypepathParamsTypesame as in@kubb/plugin-clientparsersame as in@kubb/plugin-clientqueryOptionshas been removed as an optionmutate.methodsbecomesmutation.methodsmutate.importPathbecomesmutation.importPath- Mutations will include a generated
mutationkey enabledwill be generated based on which params are required- Support for
signal, this makes it possible to cancel a request - Removal of
mutate.variablesTypeand use'mutate'as default paramsTypewill make it possible to have one object to pass your pathParams, params, headers and data.
@kubb/plugin-msw
parserto switch between using Faker('faker') for your data or define your own data with'data'.- By default, use of a function with
dataas parameter to override the response of MSW.
export const addPetHandler = http.post('*/pet', function handler(info) {
return new Response(JSON.stringify(createAddPetMutationResponse()), {
headers: {
'Content-Type': 'application/json',
},
})
})
export function addPetHandler(data?: AddPetMutationResponse) {
return http.post('*/pet', function handler(info) {
return new Response(JSON.stringify(createAddPetMutationResponse(data)), {
headers: {
'Content-Type': 'application/json',
},
})
})
}