@kubb/plugin-client
Generate API client code for handling API requests.
By default, this plugin uses Axios, but you can add your own client. See Use of Fetch for an example.
Installation
bun add -d @kubb/plugin-clientpnpm add -D @kubb/plugin-clientnpm install --save-dev @kubb/plugin-clientyarn add -D @kubb/plugin-clientOptions
output
Specify the export location for the files and define the behavior of the output.
output.path
Path to the output folder or file that contains the generated code.
TIP
if output.path is a file, group cannot be used.
| Type: | string |
|---|---|
| Required: | true |
| Default: | 'clients' |
output.barrelType
Specify what to export and optionally disable barrel file generation.
TIP
Using propagate will prevent a plugin from creating a barrel file, but it will still propagate, allowing output.barrelType to export the specific function or type.
| Type: | 'all' | 'named' | 'propagate' | false |
|---|---|
| Required: | false |
| Default: | 'named' |
export * from "./gen/petService.ts"export { PetService } from "./gen/petService.ts"output.banner
Add a banner comment at the top of every generated file.
| Type: | string | (oas: Oas) => string |
|---|---|
| Required: | false |
output.footer
Add a footer comment at the end of every generated file.
| Type: | string | (oas: Oas) => string |
|---|---|
| Required: | false |
output.override
Whether Kubb overrides existing external files that can be generated if they already exist.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
contentType
Define which content type to use.
By default, Kubb uses the first JSON-valid media type.
| Type: | 'application/json' | (string & {}) |
|---|---|
| Required: | false |
group
Grouping combines files in a folder based on a specific type.
For example, with this configuration:
group: {
type: 'tag',
name({ group }){
return `${group}Controller`
}
}This generates the following structure:
.
├── src/
│ └── petController/
│ │ ├── addPet.ts
│ │ └── getPet.ts
│ └── storeController/
│ ├── createStore.ts
│ └── getStoreById.ts
├── petStore.yaml
├── kubb.config.ts
└── package.jsongroup.type
Specify the property to group files by.
| Type: | 'tag' |
|---|---|
| Required: | true |
'tag': Uses the first tag fromoperation.getTags().at(0)?.name
group.name
Return the name of a group based on the group name, this will be used for the file and name generation.
| Type: | (context: GroupContext) => string |
|---|---|
| Required: | false |
| Default: | (ctx) => '${ctx.group}Controller' |
importPath
Path to the client used for API calls. Supports both relative and absolute paths.
When to use importPath
Use importPath when you want to:
- Customize the HTTP client: Provide your own client implementation with custom configurations (e.g., baseURL, headers, interceptors)
- Add authentication: Include authentication tokens or other security mechanisms in your client
- Override default behavior: Replace the default Kubb client with your own implementation
Default behavior
When importPath is not specified:
- If
bundle: false(default): Uses@kubb/plugin-client/clients/${client}where client is eitheraxiosorfetch - If
bundle: true: Bundles the client into.kubb/fetch.ts
Import structure
Generated code imports:
- Client as default import
- Types as named type imports
Example for axios client:
/**
* Generated by Kubb (https://kubb.dev/).
* Do not edit manually.
*/
import client from '${client.importPath}'
import type { RequestConfig, ResponseErrorConfig } from '${client.importPath}'
// ... rest of generated fileIMPORTANT
When using importPath with query plugins such as @kubb/plugin-react-query, @kubb/plugin-vue-query, @kubb/plugin-svelte-query, @kubb/plugin-solid-query, or @kubb/plugin-swr, the generated hooks also import type Client from the custom module:
import type { Client, RequestConfig, ResponseErrorConfig } from '@/lib/client'Your custom client module must export these three types. If any of them is missing, TypeScript will report an unresolvable import error.
export type RequestConfig<TData = unknown> = {
url?: string
method: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE'
params?: object
data?: TData | FormData
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
signal?: AbortSignal
headers?: HeadersInit
}
export type ResponseConfig<TData = unknown> = {
data: TData
status: number
statusText: string
}
export type ResponseErrorConfig<TError = unknown> = TError
// The Client type alias is required when using query plugins
export type Client = <TData, _TError = unknown, TVariables = unknown>(
config: RequestConfig<TVariables>
) => Promise<ResponseConfig<TData>>
export const client: Client = async (config) => { /* ... */ }
export default clientExample configuration with custom client:
import { defineConfig } from '@kubb/core'
import { pluginClient } from '@kubb/plugin-client'
export default defineConfig({
// ...
plugins: [
pluginClient({
importPath: './src/client.ts' // Path to your custom client
}),
],
})TIP
Learn more about defining a custom client here.
| Type: | string |
|---|---|
| Required: | false |
operations
Create operations.ts file with all operations grouped by methods.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
dataReturnType
Return type used when calling the client.
| Type: | 'data' | 'full' |
|---|---|
| Required: | false |
| Default: | 'data' |
'data'returns ResponseConfig[data].'full'returns ResponseConfig.
export async function getPetById<TData>(
petId: GetPetByIdPathParams,
): Promise<ResponseConfig<TData>["data"]> {
...
}export async function getPetById<TData>(
petId: GetPetByIdPathParams,
): Promise<ResponseConfig<TData>> {
...
}urlType
Export urls that are used by operation x
| Type: | 'export' | false |
|---|---|
| Required: | false |
| Default: | false |
'export'will make them part of your barrel filefalsewill not make them exportable
export function getGetPetByIdUrl(petId: GetPetByIdPathParams['petId']) {
return `/pet/${petId}` as const
}paramsType
Defines how parameters are passed to generated functions. Switch between object-style parameters and inline parameters.
| Type: | 'object' | 'inline' |
|---|---|
| Required: | false |
| Default: | 'inline' |
TIP
When paramsType is set to 'object', pathParams will also be set to 'object'.
'object'returns params and pathParams as an object.'inline'returns params as comma-separated params.
export async function deletePet(
{
petId,
headers,
}: {
petId: DeletePetPathParams['petId']
headers?: DeletePetHeaderParams
},
config: Partial<RequestConfig> = {},
) {
...
}export async function deletePet(
petId: DeletePetPathParams['petId'],
headers?: DeletePetHeaderParams,
config: Partial<RequestConfig> = {}
){
...
}paramsCasing
Transform parameter names to a specific casing format for path, query, and header parameters in generated client code.
IMPORTANT
When using paramsCasing, ensure that @kubb/plugin-ts also has the same paramsCasing setting. This option automatically maps transformed parameter names back to their original API names in HTTP requests.
| Type: | 'camelcase' |
|---|---|
| Required: | false |
| Default: | undefined |
'camelcase'transforms parameter names to camelCase
// Function parameters use camelCase
export async function deletePet(
petId: DeletePetPathParams['petId'], // ✓ camelCase
headers?: DeletePetHeaderParams,
config: Partial<RequestConfig> = {}
) {
// Automatically maps back to original name for the API
const pet_id = petId
return fetch({
method: 'DELETE',
url: `/pet/${pet_id}`, // Uses original API parameter name
...
})
}// Parameters use original API naming
export async function deletePet(
pet_id: DeletePetPathParams['pet_id'], // Original naming
headers?: DeletePetHeaderParams,
config: Partial<RequestConfig> = {}
) {
return fetch({
method: 'DELETE',
url: `/pet/${pet_id}`,
...
})
}TIP
The client automatically generates mapping code to convert camelCase parameter names back to the original API format. You write code with developer-friendly camelCase names, but HTTP requests use the exact parameter names from your OpenAPI specification.
pathParamsType
Defines how pathParams are passed to generated functions.
| Type: | 'object' | 'inline' |
|---|---|
| Required: | false |
| Default: | 'inline' |
'object'returns pathParams as an object.'inline'returns pathParams as comma-separated params.
export async function getPetById (
{ petId }: GetPetByIdPathParams,
) {
...
}export async function getPetById(
petId: GetPetByIdPathParams,
) {
...
}parser
Parser used before returning data.
| Type: | 'client' | 'zod' |
|---|---|
| Required: | false |
| Default: | 'client' |
'zod'uses@kubb/plugin-zodto parse data.'client'returns data without parsing.
client
Client used for HTTP calls.
| Type: | 'axios' | 'fetch' |
|---|---|
| Required: | false |
| Default: | 'axios' |
'axios'uses@kubb/plugin-client/templates/axiosto fetch data.'fetch'uses@kubb/plugin-client/templates/fetchto fetch data.
clientType new in 4.18.0
Defines the client code generation style.
| Type: | 'function' | 'class' | 'staticClass' |
|---|---|
| Required: | false |
| Default: | 'function' |
'function'generates standalone functions for each operation.'class'generates a class with instance methods for each operation.'staticClass'generates a class with static methods for each operation. Use this style to call methods likePet.getPetById(...)without instantiating the class.
WARNING
When using clientType: 'class' or clientType: 'staticClass', these are not compatible with query plugins like @kubb/plugin-react-query, @kubb/plugin-vue-query, @kubb/plugin-solid-query, @kubb/plugin-svelte-query, or @kubb/plugin-swr. These plugins are designed to work with function-based clients. If you need to use both class-based or static-class clients and query hooks, configure separate pluginClient instances: one with clientType: 'class' or clientType: 'staticClass' for your needs, and another with clientType: 'function' (or omit it for the default) that the query plugins will reference.
import { defineConfig } from '@kubb/core'
import { pluginClient } from '@kubb/plugin-client'
import { pluginOas } from '@kubb/plugin-oas'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginTs(),
pluginClient({
output: {
path: './clients',
},
clientType: 'staticClass',
group: {
type: 'tag',
},
}),
],
})import fetch from '@kubb/plugin-client/clients/fetch'
import type { GetPetByIdQueryResponse, GetPetByIdPathParams, GetPetById400, GetPetById404 } from '../../../models/ts/petController/GetPetById.js'
import type { AddPetMutationRequest, AddPetMutationResponse, AddPet405 } from '../../../models/ts/petController/AddPet.js'
import type { RequestConfig, ResponseErrorConfig } from '@kubb/plugin-client/clients/fetch'
export class Pet {
static #client: typeof fetch = fetch
/**
* @description Returns a single pet
* @summary Find pet by ID
* {@link /pet/:petId}
*/
static async getPetById(
{ petId }: { petId: GetPetByIdPathParams['petId'] },
config: Partial<RequestConfig> & { client?: typeof fetch } = {}
) {
const request = this.#client || fetch
const { client: _request = this.#client, ...requestConfig } = config
const res = await request<GetPetByIdQueryResponse, ResponseErrorConfig<GetPetById400 | GetPetById404>, unknown>({
method: 'GET',
url: `/pet/${petId}`,
...requestConfig,
})
return res.data
}
/**
* @description Add a new pet to the store
* @summary Add a new pet to the store
* {@link /pet}
*/
static async addPet(
data: AddPetMutationRequest,
config: Partial<RequestConfig<AddPetMutationRequest>> & { client?: typeof fetch } = {}
) {
const request = this.#client || fetch
const { client: _request = this.#client, ...requestConfig } = config
const requestData = data
const res = await request<AddPetMutationResponse, ResponseErrorConfig<AddPet405>, AddPetMutationRequest>({
method: 'POST',
url: '/pet',
data: requestData,
...requestConfig,
})
return res.data
}
}import { Pet } from './gen/clients/Pet'
// Get a pet by ID
const pet = await Pet.getPetById({ petId: 1 })
// Add a new pet
const newPet = await Pet.addPet({
name: 'Fluffy',
status: 'available'
})'class'generates a class with methods for each operation.
WARNING
When using clientType: 'class', it is not compatible with query plugins like @kubb/plugin-react-query, @kubb/plugin-vue-query, @kubb/plugin-solid-query, @kubb/plugin-svelte-query, or @kubb/plugin-swr. These plugins are designed to work with function-based clients. If you need to use both class-based clients and query hooks, configure separate pluginClient instances: one with clientType: 'class' for your class-based needs, and another with clientType: 'function' (or omit it for the default) that the query plugins will reference.
import { defineConfig } from '@kubb/core'
import { pluginClient } from '@kubb/plugin-client'
import { pluginOas } from '@kubb/plugin-oas'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginTs(),
pluginClient({
output: {
path: './clients',
},
clientType: 'class',
group: {
type: 'tag',
},
}),
],
})import fetch from '@kubb/plugin-client/clients/fetch'
import type { GetPetByIdQueryResponse, GetPetByIdPathParams, GetPetById400, GetPetById404 } from '../../../models/ts/petController/GetPetById.js'
import type { AddPetMutationRequest, AddPetMutationResponse, AddPet405 } from '../../../models/ts/petController/AddPet.js'
import type { RequestConfig, ResponseErrorConfig } from '@kubb/plugin-client/clients/fetch'
export class Pet {
#client: typeof fetch
constructor(config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
this.#client = config.client || fetch
}
/**
* @description Returns a single pet
* @summary Find pet by ID
* {@link /pet/:petId}
*/
async getPetById(
{ petId }: { petId: GetPetByIdPathParams['petId'] },
config: Partial<RequestConfig> & { client?: typeof fetch } = {}
) {
const { client: request = this.#client, ...requestConfig } = config
const res = await request<GetPetByIdQueryResponse, ResponseErrorConfig<GetPetById400 | GetPetById404>, unknown>({
method: 'GET',
url: `/pet/${petId}`,
...requestConfig,
})
return res.data
}
/**
* @description Add a new pet to the store
* @summary Add a new pet to the store
* {@link /pet}
*/
async addPet(
data: AddPetMutationRequest,
config: Partial<RequestConfig<AddPetMutationRequest>> & { client?: typeof fetch } = {}
) {
const { client: request = this.#client, ...requestConfig } = config
const requestData = data
const res = await request<AddPetMutationResponse, ResponseErrorConfig<AddPet405>, AddPetMutationRequest>({
method: 'POST',
url: '/pet',
data: requestData,
...requestConfig,
})
return res.data
}
}import { Pet } from './gen/clients/Pet'
const petClient = new Pet()
// Get a pet by ID
const pet = await petClient.getPetById({ petId: 1 })
// Add a new pet
const newPet = await petClient.addPet({
name: 'Fluffy',
status: 'available'
})wrapper
Generate a wrapper class that composes all tag-based client classes into a single entry point.
wrapper.className
Name of the generated wrapper class.
| Type: | string |
|---|---|
| Required: | true |
import { defineConfig } from '@kubb/core'
import { pluginClient } from '@kubb/plugin-client'
import { pluginOas } from '@kubb/plugin-oas'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginTs(),
pluginClient({
output: {
path: './clients',
},
clientType: 'class',
group: {
type: 'tag',
},
wrapper: {
className: 'PetStoreClient',
},
}),
],
})import type { Client, RequestConfig } from './.kubb/fetch.js'
import { Pet } from './petController/Pet.js'
import { Store } from './storeController/Store.js'
import { User } from './userController/User.js'
export class PetStoreClient {
readonly pet: Pet
readonly store: Store
readonly user: User
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
this.pet = new Pet(config)
this.store = new Store(config)
this.user = new User(config)
}
}import { PetStoreClient } from './gen/clients/PetStoreClient'
const client = new PetStoreClient({ baseURL: 'https://petstore.swagger.io/v2' })
// Access operations through tag-based properties
const pets = await client.pet.findPetsByTags({ tags: ['available'] })
const user = await client.user.getUserByName({ username: 'john' })bundle
Controls whether the HTTP client runtime is copied into the generated .kubb directory.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
trueadds a.kubb/fetch.tsfile containing the selected client template (fetch or axios). Generated clients remain self-contained.falsekeeps generated clients slim by importing the shared runtime from@kubb/plugin-client/clients/{client}.- Override this behavior by providing a custom
client.importPath.
baseURL
Sets a custom base URL for all generated calls.
| Type: | string |
|---|---|
| Required: | false |
include
Array containing include parameters to include tags, operations, methods, paths, or content types.
| Type: | Array<Include> |
|---|---|
| Required: | false |
export type Include = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
}exclude
Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
| Type: | Array<Exclude> |
|---|---|
| Required: | false |
export type Exclude = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
}override
Array containing override parameters to override options based on tags, operations, methods, paths, or content types.
| Type: | Array<Override> |
|---|---|
| Required: | false |
export type Override = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
options: PluginOptions
}generators
See Generators for more information on how to use generators.
| Type: | Array<Generator<PluginClient>> |
|---|---|
| Required: | false |
transformers
transformers.name
Customize the names based on the type that is provided by the plugin.
| Type: | (name: string, type?: ResolveType) => string |
|---|---|
| Required: | false |
type ResolveType = 'file' | 'function' | 'type' | 'const'Example
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({
input: {
path: './petStore.yaml',
},
output: {
path: './src/gen',
},
plugins: [
pluginOas(),
pluginTs(),
pluginClient({
output: {
path: './clients/axios',
barrelType: 'named',
banner: '/* eslint-disable no-alert, no-console */',
footer: ''
},
group: {
type: 'tag',
name: ({ group }) => `${group}Service`,
},
transformers: {
name: (name, type) => {
return `${name}Client`
},
},
operations: true,
parser: 'client',
exclude: [
{
type: 'tag',
pattern: 'store',
},
],
pathParamsType: "object",
dataReturnType: 'full',
client: 'axios'
}),
],
})