@kubb/plugin-client 5.0.0-beta.3 → 5.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +24 -4
  2. package/dist/clients/axios.cjs +25 -3
  3. package/dist/clients/axios.cjs.map +1 -1
  4. package/dist/clients/axios.d.ts +9 -2
  5. package/dist/clients/axios.js +25 -3
  6. package/dist/clients/axios.js.map +1 -1
  7. package/dist/clients/fetch.cjs +20 -2
  8. package/dist/clients/fetch.cjs.map +1 -1
  9. package/dist/clients/fetch.d.ts +9 -2
  10. package/dist/clients/fetch.js +20 -2
  11. package/dist/clients/fetch.js.map +1 -1
  12. package/dist/index.cjs +524 -301
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +150 -84
  15. package/dist/index.js +525 -302
  16. package/dist/index.js.map +1 -1
  17. package/dist/templates/clients/axios.source.cjs +1 -1
  18. package/dist/templates/clients/axios.source.js +1 -1
  19. package/dist/templates/clients/fetch.source.cjs +1 -1
  20. package/dist/templates/clients/fetch.source.js +1 -1
  21. package/extension.yaml +1293 -0
  22. package/package.json +11 -17
  23. package/src/clients/axios.ts +41 -7
  24. package/src/clients/fetch.ts +30 -3
  25. package/src/components/ClassClient.tsx +17 -19
  26. package/src/components/Client.tsx +68 -51
  27. package/src/components/StaticClassClient.tsx +17 -19
  28. package/src/components/Url.tsx +7 -9
  29. package/src/components/WrapperClient.tsx +9 -5
  30. package/src/functionParams.ts +8 -8
  31. package/src/generators/classClientGenerator.tsx +40 -38
  32. package/src/generators/clientGenerator.tsx +32 -35
  33. package/src/generators/groupedClientGenerator.tsx +14 -8
  34. package/src/generators/operationsGenerator.tsx +12 -6
  35. package/src/generators/staticClassClientGenerator.tsx +34 -32
  36. package/src/plugin.ts +24 -11
  37. package/src/resolvers/resolverClient.ts +31 -8
  38. package/src/types.ts +90 -53
  39. package/src/utils.ts +30 -53
  40. package/templates/clients/axios.ts +0 -73
  41. package/templates/clients/fetch.ts +0 -96
  42. package/templates/config.ts +0 -43
package/extension.yaml ADDED
@@ -0,0 +1,1293 @@
1
+ $schema: https://kubb.dev/schemas/extension.json
2
+ kind: plugin
3
+ id: plugin-client
4
+ name: Client
5
+ description: Generate type-safe HTTP clients (axios or fetch) from OpenAPI — one async function per operation, fully typed end to end.
6
+ category: client
7
+ type: official
8
+ npmPackage: '@kubb/plugin-client'
9
+ docsPath: /plugins/plugin-client
10
+ repo: https://github.com/kubb-labs/plugins
11
+ maintainers:
12
+ - name: Stijn Van Hulle
13
+ github: stijnvanhulle
14
+ compatibility:
15
+ kubb: '>=5.0.0'
16
+ node: '>=22'
17
+ tags:
18
+ - api-client
19
+ - axios
20
+ - fetch
21
+ - http-client
22
+ - codegen
23
+ - openapi
24
+ dependencies:
25
+ - plugin-ts
26
+ resources:
27
+ documentation: https://kubb.dev/plugins/plugin-client
28
+ repository: https://github.com/kubb-labs/plugins
29
+ issues: https://github.com/kubb-labs/plugins/issues
30
+ changelog: https://github.com/kubb-labs/plugins/blob/main/packages/plugin-client/CHANGELOG.md
31
+ codesandbox: https://codesandbox.io/p/github/kubb-labs/plugins/main/examples/client
32
+ featured: true
33
+ icon:
34
+ light: https://kubb.dev/feature/axios.svg
35
+ intro: |
36
+ # @kubb/plugin-client
37
+
38
+ Generate HTTP client functions for every operation in your OpenAPI spec. Each generated function has typed path params, query params, body, and response — call the API like any other typed function.
39
+
40
+ Ships with `axios` and `fetch` runtimes out of the box. Bring your own client (auth, retries, custom base URL) by pointing `importPath` at your module.
41
+ options:
42
+ - name: output
43
+ type: Output
44
+ required: false
45
+ default: "{ path: 'clients', barrel: { type: 'named' } }"
46
+ description: Where the generated client files are written and how they are exported.
47
+ properties:
48
+ - name: path
49
+ type: string
50
+ required: true
51
+ description: |
52
+ Folder (or single file) where the plugin writes its generated code. The path is resolved against the global `output.path` set on `defineConfig`.
53
+
54
+ Use a folder to keep each generator's output isolated (`'types'`, `'clients'`, `'hooks'`). Use a single file when you want everything in one place, for example `'api.ts'`.
55
+ tip: |
56
+ When `output.path` points to a single file, the `group` option cannot be used because every operation ends up in the same file.
57
+ examples:
58
+ - name: kubb.config.ts
59
+ files:
60
+ - lang: typescript
61
+ twoslash: false
62
+ code: |
63
+ import { defineConfig } from 'kubb'
64
+ import { pluginTs } from '@kubb/plugin-ts'
65
+
66
+ export default defineConfig({
67
+ input: { path: './petStore.yaml' },
68
+ output: { path: './src/gen' },
69
+ plugins: [
70
+ pluginTs({
71
+ output: { path: './types' },
72
+ }),
73
+ ],
74
+ })
75
+ - name: Resulting tree
76
+ files:
77
+ - lang: text
78
+ twoslash: false
79
+ code: |
80
+ src/
81
+ └── gen/
82
+ └── types/
83
+ ├── Pet.ts
84
+ └── Store.ts
85
+ default: "'clients'"
86
+ - name: barrel
87
+ type: "{ type: 'named' | 'all', nested?: boolean } | false"
88
+ required: false
89
+ default: "{ type: 'named' }"
90
+ description: |
91
+ Controls how the generated `index.ts` (barrel) file re-exports the plugin's output.
92
+
93
+ - `{ type: 'named' }` re-exports each symbol by name. Best for tree-shaking and explicit imports.
94
+ - `{ type: 'all' }` uses `export *`. Smaller barrel file, but exports everything.
95
+ - `{ nested: true }` creates a barrel in every subdirectory, so callers can import from any depth.
96
+ - `false` skips the barrel entirely. The plugin's files are also excluded from the root `index.ts`.
97
+ tip: |
98
+ Pick `'named'` when consumers care about which symbols they import (better tree-shaking, friendlier auto-import). Pick `'all'` when the file count is small and you want a one-line barrel.
99
+ examples:
100
+ - name: "'named' (default)"
101
+ files:
102
+ - name: kubb.config.ts
103
+ lang: typescript
104
+ twoslash: false
105
+ code: |
106
+ import { defineConfig } from 'kubb'
107
+ import { pluginTs } from '@kubb/plugin-ts'
108
+
109
+ export default defineConfig({
110
+ input: { path: './petStore.yaml' },
111
+ output: { path: './src/gen' },
112
+ plugins: [
113
+ pluginTs({
114
+ output: { barrel: { type: 'named' } },
115
+ }),
116
+ ],
117
+ })
118
+ - name: src/gen/types/index.ts
119
+ lang: typescript
120
+ twoslash: false
121
+ code: |
122
+ export { Pet, PetStatus } from './Pet'
123
+ export { Store } from './Store'
124
+ - name: "'all'"
125
+ files:
126
+ - name: kubb.config.ts
127
+ lang: typescript
128
+ twoslash: false
129
+ code: |
130
+ import { defineConfig } from 'kubb'
131
+ import { pluginTs } from '@kubb/plugin-ts'
132
+
133
+ export default defineConfig({
134
+ input: { path: './petStore.yaml' },
135
+ output: { path: './src/gen' },
136
+ plugins: [
137
+ pluginTs({
138
+ output: { barrel: { type: 'all' } },
139
+ }),
140
+ ],
141
+ })
142
+ - name: src/gen/types/index.ts
143
+ lang: typescript
144
+ twoslash: false
145
+ code: |
146
+ export * from './Pet'
147
+ export * from './Store'
148
+ - name: nested
149
+ files:
150
+ - name: kubb.config.ts
151
+ lang: typescript
152
+ twoslash: false
153
+ code: |
154
+ import { defineConfig } from 'kubb'
155
+ import { pluginTs } from '@kubb/plugin-ts'
156
+
157
+ export default defineConfig({
158
+ input: { path: './petStore.yaml' },
159
+ output: { path: './src/gen' },
160
+ plugins: [
161
+ pluginTs({
162
+ output: { barrel: { type: 'named', nested: true } },
163
+ }),
164
+ ],
165
+ })
166
+ - name: Generated tree
167
+ lang: text
168
+ twoslash: false
169
+ code: |
170
+ src/gen/types/
171
+ ├── index.ts # re-exports ./petController and ./storeController
172
+ ├── petController/
173
+ │ ├── index.ts # re-exports Pet, Store, ...
174
+ │ └── Pet.ts
175
+ └── storeController/
176
+ ├── index.ts
177
+ └── Store.ts
178
+ - name: 'false'
179
+ files:
180
+ - name: kubb.config.ts
181
+ lang: typescript
182
+ twoslash: false
183
+ code: |
184
+ import { defineConfig } from 'kubb'
185
+ import { pluginTs } from '@kubb/plugin-ts'
186
+
187
+ export default defineConfig({
188
+ input: { path: './petStore.yaml' },
189
+ output: { path: './src/gen' },
190
+ plugins: [
191
+ pluginTs({
192
+ output: { barrel: false },
193
+ }),
194
+ ],
195
+ })
196
+ - name: Result
197
+ lang: text
198
+ twoslash: false
199
+ code: |
200
+ # No index.ts is generated for this plugin.
201
+ # Its files are also excluded from the root index.ts.
202
+ - name: banner
203
+ type: 'string | ((node: RootNode) => string)'
204
+ required: false
205
+ description: |
206
+ Text prepended to every generated file. Useful for license headers, lint disables, or `@ts-nocheck` directives.
207
+
208
+ Pass a string for a static banner. Pass a function to compute the banner from each file's `RootNode` (the AST root containing path, schema, and operation context).
209
+ examples:
210
+ - name: Static banner
211
+ files:
212
+ - name: kubb.config.ts
213
+ lang: typescript
214
+ twoslash: false
215
+ code: |
216
+ import { defineConfig } from 'kubb'
217
+ import { pluginTs } from '@kubb/plugin-ts'
218
+
219
+ export default defineConfig({
220
+ input: { path: './petStore.yaml' },
221
+ output: { path: './src/gen' },
222
+ plugins: [
223
+ pluginTs({
224
+ output: {
225
+ banner: '/* eslint-disable */\n// @ts-nocheck',
226
+ },
227
+ }),
228
+ ],
229
+ })
230
+ - name: Generated file
231
+ lang: typescript
232
+ twoslash: false
233
+ code: |
234
+ /* eslint-disable */
235
+ // @ts-nocheck
236
+ export type Pet = {
237
+ id: number
238
+ name: string
239
+ }
240
+ - name: Dynamic banner
241
+ files:
242
+ - name: kubb.config.ts
243
+ lang: typescript
244
+ twoslash: false
245
+ code: |
246
+ import { defineConfig } from 'kubb'
247
+ import { pluginTs } from '@kubb/plugin-ts'
248
+
249
+ export default defineConfig({
250
+ input: { path: './petStore.yaml' },
251
+ output: { path: './src/gen' },
252
+ plugins: [
253
+ pluginTs({
254
+ output: {
255
+ banner: (node) => `// Source: ${node.path}\n// Generated at ${new Date().toISOString()}`,
256
+ },
257
+ }),
258
+ ],
259
+ })
260
+ - name: footer
261
+ type: 'string | ((node: RootNode) => string)'
262
+ required: false
263
+ description: |
264
+ Text appended at the end of every generated file. The mirror of `banner` — use it for closing comments, re-enabling lint rules, or marker lines.
265
+
266
+ Pass a string for a static footer, or a function that receives the file's `RootNode` and returns the footer text.
267
+ examples:
268
+ - name: Re-enable lint after a banner disable
269
+ files:
270
+ - name: kubb.config.ts
271
+ lang: typescript
272
+ twoslash: false
273
+ code: |
274
+ import { defineConfig } from 'kubb'
275
+ import { pluginTs } from '@kubb/plugin-ts'
276
+
277
+ export default defineConfig({
278
+ input: { path: './petStore.yaml' },
279
+ output: { path: './src/gen' },
280
+ plugins: [
281
+ pluginTs({
282
+ output: {
283
+ banner: '/* eslint-disable */',
284
+ footer: '/* eslint-enable */',
285
+ },
286
+ }),
287
+ ],
288
+ })
289
+ - name: override
290
+ type: boolean
291
+ required: false
292
+ default: 'false'
293
+ description: |
294
+ Allows the plugin to overwrite hand-written files that share a name with a generated file.
295
+
296
+ - `false` (default): Kubb skips a file if it already exists and is not marked as generated. This protects manual edits.
297
+ - `true`: Kubb overwrites any file at the target path, including hand-written ones.
298
+ warning: |
299
+ Enable this only when you are sure the target folder contains nothing you need to keep. Local edits are lost on the next generation.
300
+ examples:
301
+ - name: kubb.config.ts
302
+ files:
303
+ - lang: typescript
304
+ twoslash: false
305
+ code: |
306
+ import { defineConfig } from 'kubb'
307
+ import { pluginTs } from '@kubb/plugin-ts'
308
+
309
+ export default defineConfig({
310
+ input: { path: './petStore.yaml' },
311
+ output: { path: './src/gen' },
312
+ plugins: [
313
+ pluginTs({
314
+ output: { override: true },
315
+ }),
316
+ ],
317
+ })
318
+ - name: contentType
319
+ type: "'application/json' | (string & {})"
320
+ required: false
321
+ description: |
322
+ Selects which request/response media type the generator reads from the OpenAPI spec.
323
+
324
+ When omitted, Kubb picks the first JSON-compatible media type it finds (`application/json`, `application/vnd.api+json`, anything ending in `+json`). Set this when your spec defines multiple media types for the same operation and you want a non-default one.
325
+ examples:
326
+ - name: JSON API media type
327
+ files:
328
+ - lang: typescript
329
+ twoslash: false
330
+ code: |
331
+ import { defineConfig } from 'kubb'
332
+ import { pluginTs } from '@kubb/plugin-ts'
333
+
334
+ export default defineConfig({
335
+ input: { path: './petStore.yaml' },
336
+ output: { path: './src/gen' },
337
+ plugins: [
338
+ pluginTs({
339
+ contentType: 'application/vnd.api+json',
340
+ }),
341
+ ],
342
+ })
343
+ - name: group
344
+ type: Group
345
+ required: false
346
+ description: |
347
+ Splits generated files into subfolders based on the operation's tag, so each tag in your OpenAPI spec gets its own directory.
348
+
349
+ Without `group`, every file lands in the plugin's `output.path` folder. With `group`, files are bucketed under `{output.path}/{groupName}/`, where `groupName` is derived from the operation's first tag.
350
+ tip: |
351
+ Use `group` to mirror your API's domain structure (pet, store, user) in the generated code. Combine it with `output.barrel: { type: 'named', nested: true }` to get per-tag barrel files.
352
+ examples:
353
+ - name: kubb.config.ts
354
+ files:
355
+ - lang: typescript
356
+ twoslash: false
357
+ code: |
358
+ import { defineConfig } from 'kubb'
359
+ import { pluginTs } from '@kubb/plugin-ts'
360
+
361
+ export default defineConfig({
362
+ input: { path: './petStore.yaml' },
363
+ output: { path: './src/gen' },
364
+ plugins: [
365
+ pluginTs({
366
+ group: {
367
+ type: 'tag',
368
+ name: ({ group }) => `${group}Controller`,
369
+ },
370
+ }),
371
+ ],
372
+ })
373
+ body: |
374
+ With the configuration above, the generator emits:
375
+
376
+ ```text
377
+ src/gen/
378
+ ├── petController/
379
+ │ ├── AddPet.ts
380
+ │ └── GetPet.ts
381
+ └── storeController/
382
+ ├── CreateStore.ts
383
+ └── GetStoreById.ts
384
+ ```
385
+ properties:
386
+ - name: type
387
+ type: "'tag'"
388
+ required: true
389
+ description: |
390
+ Property used to assign each operation to a group. Required whenever `group` is set.
391
+
392
+ Today only `'tag'` is supported: Kubb reads the first tag on the operation (`operation.getTags().at(0)?.name`) and uses it as the group key. Operations without a tag are placed in a default group.
393
+ note: |
394
+ `Required: true*` is conditional — only required when the parent `group` option is used. `group` itself stays optional.
395
+ - name: name
396
+ type: '(context: GroupContext) => string'
397
+ required: false
398
+ default: (ctx) => `${ctx.group}Controller`
399
+ description: Function that builds the folder/identifier name from a group key (the operation's first tag).
400
+ - name: importPath
401
+ type: string
402
+ required: false
403
+ description: |
404
+ Path or module specifier of a custom client module. Generated code imports its HTTP runtime from here instead of `@kubb/plugin-client/clients/{client}`.
405
+
406
+ Use this when you need to inject auth headers, add interceptors, change the base URL at runtime, or wrap a different HTTP library (ky, ofetch, ...). Both relative paths (`./src/client.ts`) and bare specifiers (`@my-org/api-client`) work.
407
+ details:
408
+ - title: When to use `importPath`
409
+ body: |
410
+ Reach for a custom client when you need to:
411
+
412
+ - Add an auth token to every request.
413
+ - Plug in interceptors, retries, or logging.
414
+ - Configure `baseURL` and headers from environment variables.
415
+ - Wrap a library other than `axios`/`fetch`.
416
+ - title: Default behavior
417
+ body: |
418
+ Without `importPath`:
419
+
420
+ - `bundle: false` (default) — generated code imports from `@kubb/plugin-client/clients/{axios|fetch}`.
421
+ - `bundle: true` — Kubb writes `.kubb/client.ts` and generated code imports from there.
422
+ - title: Required exports
423
+ body: |
424
+ The module pointed to by `importPath` must satisfy the same shape as the built-in client. At minimum:
425
+
426
+ - A default export of the `client` function.
427
+ - A `RequestConfig` type.
428
+ - A `ResponseErrorConfig` type.
429
+
430
+ When used together with a query plugin (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), it must also export a `Client` type alias.
431
+ - title: How generated files import it
432
+ body: |
433
+ Generated code imports the client as a default import (bound to the local name `client`) and the runtime types as named type imports:
434
+ codeBlock:
435
+ lang: typescript
436
+ code: |
437
+ import client from '${client.importPath}'
438
+ import type { RequestConfig, ResponseErrorConfig } from '${client.importPath}'
439
+ // ... rest of the generated file
440
+ important: |
441
+ When used with query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), generated hooks also import a `Client` type alias. Your module **must** export `Client`, `RequestConfig`, and `ResponseErrorConfig` — TypeScript will fail the import otherwise.
442
+ codeBlock:
443
+ lang: typescript
444
+ title: src/client.ts
445
+ code: |
446
+ import axios from 'axios'
447
+
448
+ export type RequestConfig<TData = unknown> = {
449
+ url?: string
450
+ method: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE'
451
+ params?: object
452
+ data?: TData | FormData
453
+ responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
454
+ signal?: AbortSignal
455
+ headers?: HeadersInit
456
+ }
457
+
458
+ export type ResponseConfig<TData = unknown> = {
459
+ data: TData
460
+ status: number
461
+ statusText: string
462
+ }
463
+
464
+ export type ResponseErrorConfig<TError = unknown> = TError
465
+
466
+ // Required when used with @kubb/plugin-react-query or @kubb/plugin-vue-query
467
+ export type Client = <TData, _TError = unknown, TVariables = unknown>(
468
+ config: RequestConfig<TVariables>,
469
+ ) => Promise<ResponseConfig<TData>>
470
+
471
+ const client: Client = async (config) => {
472
+ const response = await axios.request<TData>({
473
+ ...config,
474
+ headers: {
475
+ Authorization: `Bearer ${process.env.API_TOKEN}`,
476
+ ...config.headers,
477
+ },
478
+ })
479
+
480
+ return response
481
+ }
482
+
483
+ export default client
484
+ examples:
485
+ - name: Wire up a custom client
486
+ files:
487
+ - name: kubb.config.ts
488
+ lang: typescript
489
+ twoslash: false
490
+ code: |
491
+ import { defineConfig } from 'kubb'
492
+ import { pluginClient } from '@kubb/plugin-client'
493
+
494
+ export default defineConfig({
495
+ input: { path: './petStore.yaml' },
496
+ output: { path: './src/gen' },
497
+ plugins: [
498
+ pluginClient({
499
+ importPath: './src/client.ts',
500
+ }),
501
+ ],
502
+ })
503
+ tip: |
504
+ See the [custom client guide](https://kubb.dev/plugins/plugin-client#importpath) for a worked example.
505
+ - name: operations
506
+ type: boolean
507
+ required: false
508
+ default: 'false'
509
+ description: |
510
+ Emits an `operations.ts` file that re-exports every generated function grouped by HTTP method. Useful for building meta-tooling (route registries, API explorers) on top of the generated code.
511
+ - name: dataReturnType
512
+ type: "'data' | 'full'"
513
+ required: false
514
+ default: "'data'"
515
+ description: |
516
+ Shape of the value returned from each generated client function.
517
+
518
+ - `'data'` returns only the response body (`response.data`). Concise and matches what most apps need.
519
+ - `'full'` returns the full response config — body, status code, headers, and the original request. Use this when callers need to inspect headers or status.
520
+ examples:
521
+ - name: "'data' (default)"
522
+ files:
523
+ - name: getPetById.ts
524
+ lang: typescript
525
+ twoslash: false
526
+ code: |
527
+ export async function getPetById<TData>(
528
+ petId: GetPetByIdPathParams,
529
+ ): Promise<ResponseConfig<TData>['data']> {
530
+ // ...
531
+ }
532
+ - name: usage.ts
533
+ lang: typescript
534
+ twoslash: false
535
+ code: |
536
+ const pet = await getPetById(1)
537
+ // ^? Pet
538
+ - name: "'full'"
539
+ files:
540
+ - name: getPetById.ts
541
+ lang: typescript
542
+ twoslash: false
543
+ code: |
544
+ export async function getPetById<TData>(
545
+ petId: GetPetByIdPathParams,
546
+ ): Promise<ResponseConfig<TData>> {
547
+ // ...
548
+ }
549
+ - name: usage.ts
550
+ lang: typescript
551
+ twoslash: false
552
+ code: |
553
+ const response = await getPetById(1)
554
+ // ^? ResponseConfig<Pet>
555
+ console.log(response.status, response.headers)
556
+ const pet = response.data
557
+ - name: urlType
558
+ type: "'export' | false"
559
+ required: false
560
+ default: 'false'
561
+ description: |
562
+ Controls whether the URL builder helpers (`get<Operation>Url`) are exported alongside each client function.
563
+
564
+ - `'export'` — expose them via the barrel. Useful when you call the API through a different transport (`navigator.sendBeacon`, server actions, etc.).
565
+ - `false` (default) — keep them private to the generated module.
566
+ codeBlock:
567
+ lang: typescript
568
+ title: Generated URL helper
569
+ code: |
570
+ export function getGetPetByIdUrl(petId: GetPetByIdPathParams['petId']) {
571
+ return `/pet/${petId}` as const
572
+ }
573
+ - name: paramsType
574
+ type: "'object' | 'inline'"
575
+ required: false
576
+ default: "'inline'"
577
+ description: |
578
+ How operation parameters (path, query, headers) are exposed in the generated function signature.
579
+
580
+ - `'inline'` (default) — each parameter is a separate positional argument. Compact for operations with one or two params.
581
+ - `'object'` — every parameter is wrapped in a single object argument. Easier to read for operations with many params and named at the call site.
582
+ tip: |
583
+ Setting `paramsType: 'object'` implicitly sets `pathParamsType: 'object'` as well, so call sites are consistent.
584
+ examples:
585
+ - name: "'inline' (default)"
586
+ files:
587
+ - name: Generated client
588
+ lang: typescript
589
+ twoslash: false
590
+ code: |
591
+ export async function deletePet(
592
+ petId: DeletePetPathParams['petId'],
593
+ headers?: DeletePetHeaderParams,
594
+ config: Partial<RequestConfig> = {},
595
+ ) {
596
+ // ...
597
+ }
598
+ - name: Caller
599
+ lang: typescript
600
+ twoslash: false
601
+ code: |
602
+ await deletePet(42)
603
+ - name: "'object'"
604
+ files:
605
+ - name: Generated client
606
+ lang: typescript
607
+ twoslash: false
608
+ code: |
609
+ export async function deletePet(
610
+ {
611
+ petId,
612
+ headers,
613
+ }: {
614
+ petId: DeletePetPathParams['petId']
615
+ headers?: DeletePetHeaderParams
616
+ },
617
+ config: Partial<RequestConfig> = {},
618
+ ) {
619
+ // ...
620
+ }
621
+ - name: Caller
622
+ lang: typescript
623
+ twoslash: false
624
+ code: |
625
+ await deletePet({ petId: 42, headers: { 'X-Api-Key': 'secret' } })
626
+ - name: paramsCasing
627
+ type: "'camelcase'"
628
+ required: false
629
+ description: |
630
+ Renames path, query, and header parameters in the generated client to the chosen casing. The HTTP request still uses the original names from the OpenAPI spec — Kubb writes the mapping for you.
631
+
632
+ - `'camelcase'` — turn `pet_id` and `X-Api-Key` into `petId` and `xApiKey` in your TypeScript code. The runtime URL still uses `/pet/{pet_id}` and the header is still sent as `X-Api-Key`.
633
+ important: |
634
+ Set the same `paramsCasing` on every plugin that touches operation parameters (`@kubb/plugin-ts`, `@kubb/plugin-client`, `@kubb/plugin-react-query`, `@kubb/plugin-faker`, `@kubb/plugin-mcp`). Mismatched casing causes type errors between generated layers.
635
+ examples:
636
+ - name: "With paramsCasing: 'camelcase'"
637
+ files:
638
+ - name: Generated client
639
+ lang: typescript
640
+ twoslash: false
641
+ code: |
642
+ // Function takes camelCase parameters
643
+ export async function deletePet(
644
+ petId: DeletePetPathParams['petId'],
645
+ headers?: DeletePetHeaderParams,
646
+ config: Partial<RequestConfig> = {},
647
+ ) {
648
+ // ...mapped back to the original API name internally
649
+ const pet_id = petId
650
+
651
+ return client({
652
+ method: 'DELETE',
653
+ url: `/pet/${pet_id}`,
654
+ ...config,
655
+ })
656
+ }
657
+ - name: Caller
658
+ lang: typescript
659
+ twoslash: false
660
+ code: |
661
+ await deletePet(42)
662
+ - name: Without paramsCasing
663
+ files:
664
+ - name: Generated client
665
+ lang: typescript
666
+ twoslash: false
667
+ code: |
668
+ // Function parameters mirror the OpenAPI spec
669
+ export async function deletePet(
670
+ pet_id: DeletePetPathParams['pet_id'],
671
+ headers?: DeletePetHeaderParams,
672
+ config: Partial<RequestConfig> = {},
673
+ ) {
674
+ return client({
675
+ method: 'DELETE',
676
+ url: `/pet/${pet_id}`,
677
+ ...config,
678
+ })
679
+ }
680
+ tip: |
681
+ Callers write friendly camelCase names. The generated client maps them back to whatever the API expects (snake_case path params, kebab-case headers, ...).
682
+ - name: pathParamsType
683
+ type: "'object' | 'inline'"
684
+ required: false
685
+ default: "'inline'"
686
+ description: |
687
+ How URL path parameters appear in the generated function signature. Affects only path params; query/header params follow `paramsType`.
688
+
689
+ - `'inline'` (default) — each path param is a positional argument: `getPetById(petId)`.
690
+ - `'object'` — path params are wrapped in a single object: `getPetById({ petId })`.
691
+ examples:
692
+ - name: "'inline' (default)"
693
+ files:
694
+ - lang: typescript
695
+ twoslash: false
696
+ code: |
697
+ export async function getPetById(
698
+ petId: GetPetByIdPathParams,
699
+ ) {
700
+ // ...
701
+ }
702
+ - name: "'object'"
703
+ files:
704
+ - lang: typescript
705
+ twoslash: false
706
+ code: |
707
+ export async function getPetById(
708
+ { petId }: GetPetByIdPathParams,
709
+ ) {
710
+ // ...
711
+ }
712
+ - name: parser
713
+ type: "'client' | 'zod'"
714
+ required: false
715
+ default: "'client'"
716
+ description: |
717
+ Runtime validator applied to the response body before it is returned to the caller.
718
+
719
+ - `'client'` (default) — no validation. The response is cast to the generated TypeScript type and returned as-is. Fastest path, trusts the API.
720
+ - `'zod'` — pipes the response through the Zod schema produced by `@kubb/plugin-zod`. Catches mismatches between spec and API at runtime, at the cost of a parse on every call.
721
+
722
+ Use `'zod'` when you want a defensive boundary against drift between your OpenAPI spec and the live API. Requires `@kubb/plugin-zod` in the plugins list.
723
+ examples:
724
+ - name: Validate responses with Zod
725
+ files:
726
+ - lang: typescript
727
+ twoslash: false
728
+ code: |
729
+ import { defineConfig } from 'kubb'
730
+ import { pluginClient } from '@kubb/plugin-client'
731
+ import { pluginTs } from '@kubb/plugin-ts'
732
+ import { pluginZod } from '@kubb/plugin-zod'
733
+
734
+ export default defineConfig({
735
+ input: { path: './petStore.yaml' },
736
+ output: { path: './src/gen' },
737
+ plugins: [
738
+ pluginTs(),
739
+ pluginZod(),
740
+ pluginClient({
741
+ parser: 'zod',
742
+ }),
743
+ ],
744
+ })
745
+ - name: client
746
+ type: "'axios' | 'fetch'"
747
+ required: false
748
+ default: "'axios'"
749
+ description: |
750
+ HTTP client used by the generated code.
751
+
752
+ - `'axios'` — generated functions call into `@kubb/plugin-client/clients/axios`. Requires `axios` as a runtime dependency.
753
+ - `'fetch'` — generated functions call into `@kubb/plugin-client/clients/fetch`. Uses the global `fetch`, no extra runtime dependency.
754
+
755
+ To plug in your own client, use [`importPath`](#importpath) instead.
756
+ examples:
757
+ - name: Use fetch
758
+ files:
759
+ - lang: typescript
760
+ twoslash: false
761
+ code: |
762
+ import { defineConfig } from 'kubb'
763
+ import { pluginClient } from '@kubb/plugin-client'
764
+
765
+ export default defineConfig({
766
+ input: { path: './petStore.yaml' },
767
+ output: { path: './src/gen' },
768
+ plugins: [
769
+ pluginClient({
770
+ client: 'fetch',
771
+ }),
772
+ ],
773
+ })
774
+ - name: clientType
775
+ type: "'function' | 'class' | 'staticClass'"
776
+ required: false
777
+ default: "'function'"
778
+ description: |
779
+ Shape of the generated client code.
780
+
781
+ - `'function'` (default) — one standalone async function per operation. Tree-shakes cleanly and works with every query plugin.
782
+ - `'class'` — one class per group/tag with an instance method per operation. Use this to share configuration (auth, headers) through the constructor.
783
+ - `'staticClass'` — one class per group/tag with static methods. Call as `Pet.getPetById(...)` without instantiating. Good for app-wide singleton clients.
784
+ warning: |
785
+ Only `'function'` is compatible with query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`). To use both classes and query hooks, register two `pluginClient` instances — one with `clientType: 'function'` for the query plugins to consume, and a second with `clientType: 'class'` or `'staticClass'` for your direct usage.
786
+ examples:
787
+ - name: "'staticClass'"
788
+ files:
789
+ - name: kubb.config.ts
790
+ lang: typescript
791
+ twoslash: false
792
+ code: |
793
+ import { defineConfig } from 'kubb'
794
+ import { pluginClient } from '@kubb/plugin-client'
795
+ import { pluginTs } from '@kubb/plugin-ts'
796
+
797
+ export default defineConfig({
798
+ input: { path: './petStore.yaml' },
799
+ output: { path: './src/gen' },
800
+ plugins: [
801
+ pluginTs(),
802
+ pluginClient({
803
+ output: { path: './clients' },
804
+ clientType: 'staticClass',
805
+ group: { type: 'tag' },
806
+ }),
807
+ ],
808
+ })
809
+ - name: Generated Pet.ts (excerpt)
810
+ lang: typescript
811
+ twoslash: false
812
+ code: |
813
+ import client from '@kubb/plugin-client/clients/fetch'
814
+ import type { GetPetByIdPathParams, GetPetByIdQueryResponse } from '../../models/ts/petController/GetPetById'
815
+ import type { RequestConfig } from '@kubb/plugin-client/clients/fetch'
816
+
817
+ export class Pet {
818
+ static #client: typeof client = client
819
+
820
+ static async getPetById(
821
+ { petId }: { petId: GetPetByIdPathParams['petId'] },
822
+ config: Partial<RequestConfig> & { client?: typeof client } = {},
823
+ ) {
824
+ const { client: request = this.#client, ...requestConfig } = config
825
+ const res = await request<GetPetByIdQueryResponse>({
826
+ method: 'GET',
827
+ url: `/pet/${petId}`,
828
+ ...requestConfig,
829
+ })
830
+ return res.data
831
+ }
832
+ }
833
+ - name: usage.ts
834
+ lang: typescript
835
+ twoslash: false
836
+ code: |
837
+ import { Pet } from './gen/clients/Pet'
838
+
839
+ const pet = await Pet.getPetById({ petId: 1 })
840
+ - name: "'class'"
841
+ files:
842
+ - name: kubb.config.ts
843
+ lang: typescript
844
+ twoslash: false
845
+ code: |
846
+ import { defineConfig } from 'kubb'
847
+ import { pluginClient } from '@kubb/plugin-client'
848
+ import { pluginTs } from '@kubb/plugin-ts'
849
+
850
+ export default defineConfig({
851
+ input: { path: './petStore.yaml' },
852
+ output: { path: './src/gen' },
853
+ plugins: [
854
+ pluginTs(),
855
+ pluginClient({
856
+ output: { path: './clients' },
857
+ clientType: 'class',
858
+ group: { type: 'tag' },
859
+ }),
860
+ ],
861
+ })
862
+ - name: Generated Pet.ts (excerpt)
863
+ lang: typescript
864
+ twoslash: false
865
+ code: |
866
+ import client from '@kubb/plugin-client/clients/fetch'
867
+ import type { GetPetByIdPathParams, GetPetByIdQueryResponse } from '../../models/ts/petController/GetPetById'
868
+ import type { RequestConfig } from '@kubb/plugin-client/clients/fetch'
869
+
870
+ export class Pet {
871
+ #client: typeof client
872
+
873
+ constructor(config: Partial<RequestConfig> & { client?: typeof client } = {}) {
874
+ this.#client = config.client || client
875
+ }
876
+
877
+ async getPetById(
878
+ { petId }: { petId: GetPetByIdPathParams['petId'] },
879
+ config: Partial<RequestConfig> & { client?: typeof client } = {},
880
+ ) {
881
+ const { client: request = this.#client, ...requestConfig } = config
882
+ const res = await request<GetPetByIdQueryResponse>({
883
+ method: 'GET',
884
+ url: `/pet/${petId}`,
885
+ ...requestConfig,
886
+ })
887
+ return res.data
888
+ }
889
+ }
890
+ - name: usage.ts
891
+ lang: typescript
892
+ twoslash: false
893
+ code: |
894
+ import { Pet } from './gen/clients/Pet'
895
+
896
+ const petClient = new Pet()
897
+ const pet = await petClient.getPetById({ petId: 1 })
898
+ - name: wrapper
899
+ type: '{ className: string }'
900
+ required: false
901
+ description: |
902
+ Generates a single top-level class that composes the per-tag client classes into one entry point. Only meaningful when `clientType: 'class'` (or `'staticClass'`) and `group: { type: 'tag' }` are also set.
903
+
904
+ Use this when you want a single object to hand around your app (`api.pet.findById`, `api.user.login`) instead of importing each tag client separately.
905
+ properties:
906
+ - name: className
907
+ type: string
908
+ required: true
909
+ description: Name of the generated wrapper class — used as the export name and file name.
910
+ examples:
911
+ - name: A composed PetStoreClient
912
+ files:
913
+ - name: kubb.config.ts
914
+ lang: typescript
915
+ twoslash: false
916
+ code: |
917
+ import { defineConfig } from 'kubb'
918
+ import { pluginClient } from '@kubb/plugin-client'
919
+ import { pluginTs } from '@kubb/plugin-ts'
920
+
921
+ export default defineConfig({
922
+ input: { path: './petStore.yaml' },
923
+ output: { path: './src/gen' },
924
+ plugins: [
925
+ pluginTs(),
926
+ pluginClient({
927
+ output: { path: './clients' },
928
+ clientType: 'class',
929
+ group: { type: 'tag' },
930
+ wrapper: { className: 'PetStoreClient' },
931
+ }),
932
+ ],
933
+ })
934
+ - name: Generated PetStoreClient.ts
935
+ lang: typescript
936
+ twoslash: false
937
+ code: |
938
+ import type { Client, RequestConfig } from './.kubb/client'
939
+ import { Pet } from './petController/Pet'
940
+ import { Store } from './storeController/Store'
941
+ import { User } from './userController/User'
942
+
943
+ export class PetStoreClient {
944
+ readonly pet: Pet
945
+ readonly store: Store
946
+ readonly user: User
947
+
948
+ constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
949
+ this.pet = new Pet(config)
950
+ this.store = new Store(config)
951
+ this.user = new User(config)
952
+ }
953
+ }
954
+ - name: usage.ts
955
+ lang: typescript
956
+ twoslash: false
957
+ code: |
958
+ import { PetStoreClient } from './gen/clients/PetStoreClient'
959
+
960
+ const api = new PetStoreClient({ baseURL: 'https://petstore.swagger.io/v2' })
961
+
962
+ const pets = await api.pet.findPetsByTags({ tags: ['available'] })
963
+ const user = await api.user.getUserByName({ username: 'john' })
964
+ - name: bundle
965
+ type: boolean
966
+ required: false
967
+ default: 'false'
968
+ description: |
969
+ Copies the HTTP client runtime into the generated output, so the consuming app does not need `@kubb/plugin-client` installed at runtime.
970
+
971
+ - `false` (default) — generated files import from `@kubb/plugin-client/clients/{client}`. Smaller diff, but the package must be a runtime dependency.
972
+ - `true` — Kubb writes a `.kubb/client.ts` file with the client implementation. Generated code imports from that local file and the project no longer pulls `@kubb/plugin-client` at runtime.
973
+ - Setting `client.importPath` overrides both behaviors and uses your custom client instead.
974
+ examples:
975
+ - name: Bundle the runtime
976
+ files:
977
+ - lang: typescript
978
+ twoslash: false
979
+ code: |
980
+ import { defineConfig } from 'kubb'
981
+ import { pluginClient } from '@kubb/plugin-client'
982
+
983
+ export default defineConfig({
984
+ input: { path: './petStore.yaml' },
985
+ output: { path: './src/gen' },
986
+ plugins: [
987
+ pluginClient({
988
+ client: 'fetch',
989
+ bundle: true,
990
+ }),
991
+ ],
992
+ })
993
+ - name: baseURL
994
+ type: string
995
+ required: false
996
+ description: |
997
+ Base URL prepended to every request URL in the generated client. When omitted, the URL comes from the OpenAPI spec's `servers[0].url` (or whichever index the adapter is configured to read).
998
+
999
+ Set this when the generated client should point at a different environment (staging, production) than the one written in the spec.
1000
+ examples:
1001
+ - name: Override the spec's server URL
1002
+ files:
1003
+ - lang: typescript
1004
+ twoslash: false
1005
+ code: |
1006
+ import { defineConfig } from 'kubb'
1007
+ import { pluginClient } from '@kubb/plugin-client'
1008
+
1009
+ export default defineConfig({
1010
+ input: { path: './petStore.yaml' },
1011
+ output: { path: './src/gen' },
1012
+ plugins: [
1013
+ pluginClient({
1014
+ baseURL: 'https://petstore.swagger.io/v2',
1015
+ }),
1016
+ ],
1017
+ })
1018
+ - name: include
1019
+ type: Array<Include>
1020
+ required: false
1021
+ description: |
1022
+ Restricts generation to operations that match at least one entry in the list. Anything not matched is skipped.
1023
+
1024
+ Each entry filters by one of:
1025
+
1026
+ - `tag` — the operation's first tag in the OpenAPI spec.
1027
+ - `operationId` — the operation's `operationId`.
1028
+ - `path` — the URL pattern (`'/pet/{petId}'`).
1029
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
1030
+ - `contentType` — the media type of the request body.
1031
+
1032
+ `pattern` accepts either a string (exact match) or a `RegExp` for fuzzy matches.
1033
+ codeBlock:
1034
+ lang: typescript
1035
+ title: Type definition
1036
+ code: |
1037
+ export type Include = {
1038
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
1039
+ pattern: string | RegExp
1040
+ }
1041
+ examples:
1042
+ - name: Only the pet tag
1043
+ files:
1044
+ - name: kubb.config.ts
1045
+ lang: typescript
1046
+ twoslash: false
1047
+ code: |
1048
+ import { defineConfig } from 'kubb'
1049
+ import { pluginTs } from '@kubb/plugin-ts'
1050
+
1051
+ export default defineConfig({
1052
+ input: { path: './petStore.yaml' },
1053
+ output: { path: './src/gen' },
1054
+ plugins: [
1055
+ pluginTs({
1056
+ include: [
1057
+ { type: 'tag', pattern: 'pet' },
1058
+ ],
1059
+ }),
1060
+ ],
1061
+ })
1062
+ - name: Only GET operations under /pet
1063
+ files:
1064
+ - name: kubb.config.ts
1065
+ lang: typescript
1066
+ twoslash: false
1067
+ code: |
1068
+ import { defineConfig } from 'kubb'
1069
+ import { pluginTs } from '@kubb/plugin-ts'
1070
+
1071
+ export default defineConfig({
1072
+ input: { path: './petStore.yaml' },
1073
+ output: { path: './src/gen' },
1074
+ plugins: [
1075
+ pluginTs({
1076
+ include: [
1077
+ { type: 'method', pattern: 'get' },
1078
+ { type: 'path', pattern: /^\/pet/ },
1079
+ ],
1080
+ }),
1081
+ ],
1082
+ })
1083
+ - name: exclude
1084
+ type: Array<Exclude>
1085
+ required: false
1086
+ description: |
1087
+ Skips any operation that matches at least one entry in the list. The opposite of `include`.
1088
+
1089
+ Each entry filters by one of:
1090
+
1091
+ - `tag` — the operation's first tag.
1092
+ - `operationId` — the operation's `operationId`.
1093
+ - `path` — the URL pattern (`'/pet/{petId}'`).
1094
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
1095
+ - `contentType` — the media type of the request body.
1096
+
1097
+ `pattern` accepts a plain string or a `RegExp`. When both `include` and `exclude` are set, `exclude` wins.
1098
+ codeBlock:
1099
+ lang: typescript
1100
+ title: Type definition
1101
+ code: |
1102
+ export type Exclude = {
1103
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
1104
+ pattern: string | RegExp
1105
+ }
1106
+ examples:
1107
+ - name: Skip everything under the store tag
1108
+ files:
1109
+ - name: kubb.config.ts
1110
+ lang: typescript
1111
+ twoslash: false
1112
+ code: |
1113
+ import { defineConfig } from 'kubb'
1114
+ import { pluginTs } from '@kubb/plugin-ts'
1115
+
1116
+ export default defineConfig({
1117
+ input: { path: './petStore.yaml' },
1118
+ output: { path: './src/gen' },
1119
+ plugins: [
1120
+ pluginTs({
1121
+ exclude: [
1122
+ { type: 'tag', pattern: 'store' },
1123
+ ],
1124
+ }),
1125
+ ],
1126
+ })
1127
+ - name: Skip a specific operation and all delete methods
1128
+ files:
1129
+ - name: kubb.config.ts
1130
+ lang: typescript
1131
+ twoslash: false
1132
+ code: |
1133
+ import { defineConfig } from 'kubb'
1134
+ import { pluginTs } from '@kubb/plugin-ts'
1135
+
1136
+ export default defineConfig({
1137
+ input: { path: './petStore.yaml' },
1138
+ output: { path: './src/gen' },
1139
+ plugins: [
1140
+ pluginTs({
1141
+ exclude: [
1142
+ { type: 'operationId', pattern: 'deletePet' },
1143
+ { type: 'method', pattern: 'delete' },
1144
+ ],
1145
+ }),
1146
+ ],
1147
+ })
1148
+ - name: override
1149
+ type: Array<Override>
1150
+ required: false
1151
+ description: |
1152
+ Applies a different set of plugin options to operations that match a pattern. Use this when most of your API should follow the global config, but a handful of endpoints need different treatment.
1153
+
1154
+ Each entry has the same `type` and `pattern` shape as `include`/`exclude`, plus an `options` object that overrides the plugin's options for matched operations.
1155
+
1156
+ Entries are evaluated top to bottom. The first matching entry's `options` is merged onto the plugin defaults; later entries do not stack.
1157
+ codeBlock:
1158
+ lang: typescript
1159
+ title: Type definition
1160
+ code: |
1161
+ export type Override = {
1162
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
1163
+ pattern: string | RegExp
1164
+ options: PluginOptions
1165
+ }
1166
+ examples:
1167
+ - name: Use a different enum style for the user tag
1168
+ files:
1169
+ - name: kubb.config.ts
1170
+ lang: typescript
1171
+ twoslash: false
1172
+ code: |
1173
+ import { defineConfig } from 'kubb'
1174
+ import { pluginTs } from '@kubb/plugin-ts'
1175
+
1176
+ export default defineConfig({
1177
+ input: { path: './petStore.yaml' },
1178
+ output: { path: './src/gen' },
1179
+ plugins: [
1180
+ pluginTs({
1181
+ enumType: 'asConst',
1182
+ override: [
1183
+ {
1184
+ type: 'tag',
1185
+ pattern: 'user',
1186
+ options: { enumType: 'literal' },
1187
+ },
1188
+ ],
1189
+ }),
1190
+ ],
1191
+ })
1192
+ - name: generators
1193
+ type: Array<Generator<PluginClient>>
1194
+ required: false
1195
+ experimental: true
1196
+ description: |
1197
+ Adds custom generators that run alongside the plugin's built-in generators. Each generator can emit additional files or post-process existing ones using the plugin's AST and options.
1198
+
1199
+ Use this when you need output the plugin does not produce out of the box (a custom client wrapper, an extra index, a metadata file). For end-to-end guidance, see [Creating plugins](https://kubb.dev/docs/5.x/guides/creating-plugins).
1200
+ warning: |
1201
+ Generators are an experimental, low-level API. The signature may change between minor releases.
1202
+ - name: resolver
1203
+ type: Partial<ResolverClient> & ThisType<ResolverClient>
1204
+ required: false
1205
+ description: |
1206
+ Overrides naming and path resolution for the generated client. Only the methods you supply replace the defaults; everything else falls back to the built-in resolver.
1207
+
1208
+ Inside each method, `this` is bound to the full resolver, so you can call `this.default(name)` to delegate to the original implementation.
1209
+ codeBlock:
1210
+ lang: typescript
1211
+ title: Append "Client" to every name
1212
+ code: |
1213
+ import { defineConfig } from 'kubb'
1214
+ import { pluginClient } from '@kubb/plugin-client'
1215
+
1216
+ export default defineConfig({
1217
+ input: { path: './petStore.yaml' },
1218
+ output: { path: './src/gen' },
1219
+ plugins: [
1220
+ pluginClient({
1221
+ resolver: {
1222
+ resolveName(name) {
1223
+ return `${this.default(name)}Client`
1224
+ },
1225
+ },
1226
+ }),
1227
+ ],
1228
+ })
1229
+ - name: transformer
1230
+ type: Visitor
1231
+ required: false
1232
+ experimental: true
1233
+ description: |
1234
+ AST visitor applied to operation nodes before code is printed. Use this to rewrite operation IDs, tags, or descriptions across the entire client.
1235
+ codeBlock:
1236
+ lang: typescript
1237
+ title: Prefix every operationId with "api_"
1238
+ code: |
1239
+ import { defineConfig } from 'kubb'
1240
+ import { pluginClient } from '@kubb/plugin-client'
1241
+
1242
+ export default defineConfig({
1243
+ input: { path: './petStore.yaml' },
1244
+ output: { path: './src/gen' },
1245
+ plugins: [
1246
+ pluginClient({
1247
+ transformer: {
1248
+ operation(node) {
1249
+ return { ...node, operationId: `api_${node.operationId}` }
1250
+ },
1251
+ },
1252
+ }),
1253
+ ],
1254
+ })
1255
+ examples:
1256
+ - name: kubb.config.ts
1257
+ files:
1258
+ - lang: typescript
1259
+ twoslash: false
1260
+ code: |
1261
+ import { defineConfig } from 'kubb'
1262
+ import { pluginTs } from '@kubb/plugin-ts'
1263
+ import { pluginClient } from '@kubb/plugin-client'
1264
+
1265
+ export default defineConfig({
1266
+ input: { path: './petStore.yaml' },
1267
+ output: { path: './src/gen' },
1268
+ plugins: [
1269
+ pluginTs(),
1270
+ pluginClient({
1271
+ output: {
1272
+ path: './clients/axios',
1273
+ barrel: { type: 'named' },
1274
+ banner: '/* eslint-disable */',
1275
+ },
1276
+ group: {
1277
+ type: 'tag',
1278
+ name: ({ group }) => `${group}Service`,
1279
+ },
1280
+ resolver: {
1281
+ resolveName(name) {
1282
+ return `${this.default(name)}Client`
1283
+ },
1284
+ },
1285
+ operations: true,
1286
+ parser: 'client',
1287
+ exclude: [{ type: 'tag', pattern: 'store' }],
1288
+ pathParamsType: 'object',
1289
+ dataReturnType: 'full',
1290
+ client: 'axios',
1291
+ }),
1292
+ ],
1293
+ })