@kubb/plugin-react-query 5.3.0 → 5.3.2

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.
@@ -0,0 +1,167 @@
1
+ # Call operations
2
+
3
+ `@kubb/plugin-react-query` can generate a typed TanStack Query hook for each operation. `GET` operations get query hooks such as `useGetPetById`, and `POST`, `PUT`, `PATCH`, and `DELETE` operations get mutation hooks such as `useDeletePet`. Each hook calls the client function from `@kubb/plugin-fetch` or `@kubb/plugin-axios`.
4
+
5
+ > [!IMPORTANT]
6
+ > By default the plugin emits only the factory helpers (`queryOptions`, `mutationOptions`, `queryKey`, `mutationKey`). Set [`hooks: true`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#hooks) in the plugin options to also generate the `use*` hooks shown below.
7
+
8
+ ## Queries
9
+
10
+ A query hook takes the operation's grouped request config (`path`, `query`, `headers`, whichever the operation declares) as its first argument and returns a TanStack `UseQueryResult`:
11
+
12
+ ```typescript
13
+ import { useGetPetById } from './gen/hooks/useGetPetById'
14
+
15
+ const { data, error, isLoading } = useGetPetById({ path: { petId: 1n } })
16
+ ```
17
+
18
+ The second argument has two optional groups. `query` takes any TanStack Query option, and `query.client` sets the `QueryClient` to use. The top-level `client` takes request config for this call, such as `baseURL` or `signal`:
19
+
20
+ ```typescript
21
+ import { useGetPetById } from './gen/hooks/useGetPetById'
22
+
23
+ useGetPetById(
24
+ { path: { petId: 1n } },
25
+ {
26
+ query: { staleTime: 60_000 },
27
+ client: { baseURL: 'https://api.example.com/v1' },
28
+ },
29
+ )
30
+ ```
31
+
32
+ ## Factories
33
+
34
+ Each query operation also exports a `queryOptions` factory and a `queryKey` helper. Use them to prefetch or invalidate a query outside a hook. The key includes the operation URL and path parameters, followed by query or body values when present:
35
+
36
+ ```typescript
37
+ import { useQueryClient } from '@tanstack/react-query'
38
+ import { getPetByIdQueryKey, getPetByIdQueryOptions } from './gen/hooks/useGetPetById'
39
+
40
+ const queryClient = useQueryClient()
41
+
42
+ await queryClient.prefetchQuery(getPetByIdQueryOptions({ path: { petId: 1n } }))
43
+ queryClient.invalidateQueries({ queryKey: getPetByIdQueryKey({ path: { petId: 1n } }) })
44
+ ```
45
+
46
+ ## Mutations
47
+
48
+ A mutation hook takes only an options object. The grouped request config is the mutation variable, so you pass it to `mutate` or `mutateAsync`:
49
+
50
+ ```typescript
51
+ import { useQueryClient } from '@tanstack/react-query'
52
+ import { useDeletePet } from './gen/hooks/useDeletePet'
53
+
54
+ const queryClient = useQueryClient()
55
+
56
+ const { mutate } = useDeletePet({
57
+ mutation: { onSuccess: () => queryClient.invalidateQueries() },
58
+ })
59
+
60
+ mutate({ path: { petId: 1n } })
61
+ ```
62
+
63
+ Each mutation also exports a `mutationOptions` factory and a `mutationKey` helper.
64
+
65
+ ## Errors and transport
66
+
67
+ Each generated hook calls the client function with `throwOnError: true`. A failed request sets TanStack Query's `error`, typed from the error responses in the spec. Set the base URL, authentication, interceptors, serialization, and validation on the client plugin. See the [plugin-fetch](https://kubb.dev/extensions/kubb-labs/plugin-fetch) or [plugin-axios](https://kubb.dev/extensions/kubb-labs/plugin-axios) guide.
68
+
69
+ ## Customize cache keys
70
+
71
+ Set `queryKey` on the plugin to change generated keys. String entries are emitted as source code, so use `JSON.stringify` for a string literal.
72
+
73
+ ```typescript [kubb.config.ts]
74
+ import { pluginReactQuery } from '@kubb/plugin-react-query'
75
+
76
+ pluginReactQuery({
77
+ queryKey: ({ node }) => [JSON.stringify(node.operationId)],
78
+ })
79
+ ```
80
+
81
+ > [!WARNING]
82
+ > This `queryKey` gives every call the same key, such as `['getUserByName']`. If path or query values select different data, add them to the key.
83
+
84
+ ## Load more pages
85
+
86
+ Configure `infinite` with a query parameter declared by the operation, its initial value, and the response path for the next cursor. Infinite output needs `hooks: true`, and only operations that declare the `queryParam` receive it.
87
+
88
+ ::code-group
89
+
90
+ ```typescript [kubb.config.ts]
91
+ import { pluginReactQuery } from '@kubb/plugin-react-query'
92
+
93
+ pluginReactQuery({
94
+ hooks: true,
95
+ infinite: {
96
+ queryParam: 'page',
97
+ initialPageParam: 0,
98
+ nextParam: 'pagination.next.cursor',
99
+ },
100
+ })
101
+ ```
102
+
103
+ ```typescript [usage.ts]
104
+ import { useInfiniteQuery } from '@tanstack/react-query'
105
+ import { findPetsByTagsInfiniteQueryOptions } from './gen/hooks/useFindPetsByTagsInfinite'
106
+
107
+ const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
108
+ findPetsByTagsInfiniteQueryOptions({ query: { tags: ['dog'] } }),
109
+ )
110
+ ```
111
+
112
+ ::
113
+
114
+ `nextParam` takes dot notation or an array of keys. Change it to match your API's response. Without `getNextPageParam`, `nextParam` or `cursorParam`, the generated options increment the page number until a page returns an empty array.
115
+
116
+ ## Use suspense
117
+
118
+ Set `suspense: {}` and `hooks: true` to generate suspense hooks alongside regular hooks. Suspense requires TanStack Query v5 or higher.
119
+
120
+ ::code-group
121
+
122
+ ```typescript [kubb.config.ts]
123
+ import { pluginReactQuery } from '@kubb/plugin-react-query'
124
+
125
+ pluginReactQuery({ hooks: true, suspense: {} })
126
+ ```
127
+
128
+ ```typescript [usage.ts]
129
+ import { useGetPetByIdSuspense } from './gen/hooks/useGetPetByIdSuspense'
130
+
131
+ const { data } = useGetPetByIdSuspense({ path: { petId: 1n } })
132
+ ```
133
+
134
+ ::
135
+
136
+ ## Share hook options
137
+
138
+ Set [`customOptions`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#customoptions) to call one options function from every generated hook.
139
+
140
+ ```typescript [kubb.config.ts]
141
+ import { pluginReactQuery } from '@kubb/plugin-react-query'
142
+
143
+ pluginReactQuery({
144
+ hooks: true,
145
+ customOptions: {
146
+ importPath: './useCustomHookOptions',
147
+ name: 'useCustomHookOptions',
148
+ },
149
+ })
150
+ ```
151
+
152
+ Create the function at `importPath`, resolved from the generated hooks folder (here `src/gen/hooks/useCustomHookOptions.ts`). Each hook passes `{ hookName, operationId }`. The generated barrel re-exports `HookOptions`.
153
+
154
+ ```typescript [src/gen/hooks/useCustomHookOptions.ts]
155
+ import type { HookOptions } from './HookOptions'
156
+
157
+ export function useCustomHookOptions(
158
+ { hookName }: { hookName: keyof HookOptions; operationId: string },
159
+ ) {
160
+ if (hookName === 'useGetPetById') {
161
+ return { staleTime: 60_000 } satisfies HookOptions['useGetPetById']
162
+ }
163
+ return {}
164
+ }
165
+ ```
166
+
167
+ Per-call query options override shared options.
@@ -0,0 +1,308 @@
1
+ # Options
2
+
3
+ Pass these options to `pluginReactQuery()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options) for details.
4
+
5
+ ## Options overview
6
+
7
+ | Option | Purpose | Default |
8
+ | ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
9
+ | [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'hooks', barrel: { type: 'named' } }` |
10
+ | [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
11
+ | [`client`](#client) | Which registered client plugin the hooks call. | Auto-detected |
12
+ | [`infinite`](#infinite) | Generate `useInfiniteQuery` hooks for pagination. | `false` |
13
+ | [`suspense`](#suspense) | Generate `useSuspenseQuery` hooks. | `false` |
14
+ | [`query`](#query) | Configure the query hooks. | `{ methods: ['GET'], importPath: '@tanstack/react-query' }` |
15
+ | [`queryKey`](#querykey) | Build the `queryKey` for each query hook. | Built-in `queryKeyTransformer` |
16
+ | [`mutation`](#mutation) | Configure the mutation hooks. | `{ methods: ['POST', 'PUT', 'PATCH', 'DELETE'], importPath: '@tanstack/react-query' }` |
17
+ | [`mutationKey`](#mutationkey) | Build the `mutationKey` for each mutation hook. | Built-in `mutationKeyTransformer` |
18
+ | [`customOptions`](#customoptions) | Route every hook through your own options function. | None |
19
+ | [`hooks`](#hooks) | Emit `use*` hook functions on top of the factories. | `false` |
20
+ | [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
21
+ | [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
22
+ | [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
23
+ | [`resolver`](#resolver) | Customize generated names and file paths. | `resolverReactQuery` |
24
+ | [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
25
+
26
+ ## Option details
27
+
28
+ ### client
29
+
30
+ Selects which registered client plugin the hooks call. A single registered client is auto-detected. Set `client` when several are registered.
31
+
32
+ | | |
33
+ | -------- | -------------------- |
34
+ | Type | `'axios' \| 'fetch'` |
35
+ | Required | `false` |
36
+
37
+ ::field-group
38
+
39
+ :::field{name="'fetch'"}
40
+ Calls the operations generated by [`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch).
41
+ :::
42
+
43
+ :::field{name="'axios'"}
44
+ Calls the operations generated by [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios).
45
+ :::
46
+
47
+ ::
48
+
49
+ ### infinite
50
+
51
+ Adds `infiniteQueryOptions` and `useInfiniteQuery` for operations that declare the query parameter named in `infinite.queryParam`. Needs [`hooks: true`](#hooks).
52
+
53
+ | | |
54
+ | -------- | ---------------------------- |
55
+ | Type | `Partial<Infinite> \| false` |
56
+ | Required | `false` |
57
+ | Default | `false` |
58
+
59
+ #### infinite.queryParam
60
+
61
+ Query parameter that carries the page cursor.
62
+
63
+ | | |
64
+ | -------- | -------- |
65
+ | Type | `string` |
66
+ | Required | `false` |
67
+ | Default | `'id'` |
68
+
69
+ #### infinite.initialPageParam
70
+
71
+ Initial value for `pageParam` on the first fetch.
72
+
73
+ | | |
74
+ | -------- | --------- |
75
+ | Type | `unknown` |
76
+ | Required | `false` |
77
+ | Default | `0` |
78
+
79
+ #### infinite.nextParam
80
+
81
+ Path to the next-page cursor on the response, as dot notation (`'pagination.next.id'`) or array form (`['pagination', 'next', 'id']`).
82
+
83
+ | | |
84
+ | -------- | --------------------------------- |
85
+ | Type | `string \| Array<string> \| null` |
86
+ | Required | `false` |
87
+ | Default | `null` |
88
+
89
+ #### infinite.previousParam
90
+
91
+ Path to the previous-page cursor on the response, in the same dot or array form.
92
+
93
+ | | |
94
+ | -------- | --------------------------------- |
95
+ | Type | `string \| Array<string> \| null` |
96
+ | Required | `false` |
97
+ | Default | `null` |
98
+
99
+ #### infinite.cursorParam
100
+
101
+ Deprecated path to the cursor field, read for both `getNextPageParam` and `getPreviousPageParam` when set. Use `nextParam` and `previousParam` instead.
102
+
103
+ | | |
104
+ | -------- | ---------------- |
105
+ | Type | `string \| null` |
106
+ | Required | `false` |
107
+ | Default | `null` |
108
+
109
+ #### infinite.getNextPageParam
110
+
111
+ Source code for TanStack Query's `getNextPageParam`, copied into the generated code as written. Use it when the next page must be computed instead of read from a field. Takes precedence over `nextParam` and `cursorParam`.
112
+
113
+ | | |
114
+ | -------- | ---------------- |
115
+ | Type | `string \| null` |
116
+ | Required | `false` |
117
+ | Default | `null` |
118
+
119
+ ```typescript
120
+ infinite: {
121
+ queryParam: 'page',
122
+ getNextPageParam: '(lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)',
123
+ getPreviousPageParam: '(firstPage) => (firstPage.number > 0 ? firstPage.number - 1 : undefined)',
124
+ }
125
+ ```
126
+
127
+ Without `getNextPageParam`, `nextParam` or `cursorParam`, the hook counts pages up from `initialPageParam` until a page is an empty array. This works only for array responses, so generation warns when the response is an object.
128
+
129
+ #### infinite.getPreviousPageParam
130
+
131
+ Source code for TanStack Query's `getPreviousPageParam`, copied into the generated code as written. Takes precedence over `previousParam` and `cursorParam`.
132
+
133
+ | | |
134
+ | -------- | ---------------- |
135
+ | Type | `string \| null` |
136
+ | Required | `false` |
137
+ | Default | `null` |
138
+
139
+ ### suspense
140
+
141
+ Adds `useSuspenseQuery` hooks next to the regular query hooks. Pass `{}` to turn it on. Needs TanStack Query v5 or higher and [`hooks: true`](#hooks).
142
+
143
+ | | |
144
+ | -------- | -------------------------- |
145
+ | Type | `Partial<object> \| false` |
146
+ | Required | `false` |
147
+ | Default | `false` |
148
+
149
+ ### query
150
+
151
+ Which operations become queries, emitting a `queryOptions` factory by default. Pass `false` to skip, or set [`hooks`](#hooks) to also emit `useQuery`.
152
+
153
+ | | |
154
+ | -------- | ----------------------------------------------------------- |
155
+ | Type | `Partial<Query> \| false` |
156
+ | Required | `false` |
157
+ | Default | `{ methods: ['GET'], importPath: '@tanstack/react-query' }` |
158
+
159
+ #### query.methods
160
+
161
+ HTTP methods treated as queries.
162
+
163
+ | | |
164
+ | -------- | --------------- |
165
+ | Type | `Array<string>` |
166
+ | Required | `false` |
167
+ | Default | `['GET']` |
168
+
169
+ #### query.importPath
170
+
171
+ Module for the `queryOptions` and `useQuery` imports.
172
+
173
+ | | |
174
+ | -------- | ------------------------- |
175
+ | Type | `string` |
176
+ | Required | `false` |
177
+ | Default | `'@tanstack/react-query'` |
178
+
179
+ ### queryKey
180
+
181
+ Builds the `queryKey` for each hook from the operation `node`, `casing` and `variant`. Strings are copied into the generated code as written, so wrap a string literal in `JSON.stringify(...)`.
182
+
183
+ | | |
184
+ | -------- | ------------------------------------------------------ |
185
+ | Type | `(props: { node, casing, variant }) => Array<unknown>` |
186
+ | Required | `false` |
187
+ | Default | Built-in `queryKeyTransformer` |
188
+
189
+ `variant` is `'query'`, `'suspenseQuery'`, `'infiniteQuery'` or `'suspenseInfiniteQuery'`. The default key adds `infinite: true` to infinite variants so they never share a cache entry with the plain query.
190
+
191
+ ```typescript
192
+ queryKey: ({ node, variant }) => [JSON.stringify({ variant, operationId: node.operationId })]
193
+ ```
194
+
195
+ ### mutation
196
+
197
+ Which operations become mutations, emitting a `mutationOptions` factory by default. Set `false` to skip, or set [`hooks`](#hooks) to also emit `useMutation`.
198
+
199
+ | | |
200
+ | -------- | -------------------------------------------------------------------------------------- |
201
+ | Type | `Partial<Mutation> \| false` |
202
+ | Required | `false` |
203
+ | Default | `{ methods: ['POST', 'PUT', 'PATCH', 'DELETE'], importPath: '@tanstack/react-query' }` |
204
+
205
+ #### mutation.methods
206
+
207
+ HTTP methods treated as mutations.
208
+
209
+ | | |
210
+ | -------- | ------------------------------------ |
211
+ | Type | `Array<string>` |
212
+ | Required | `false` |
213
+ | Default | `['POST', 'PUT', 'PATCH', 'DELETE']` |
214
+
215
+ #### mutation.importPath
216
+
217
+ Module for the `mutationOptions` and `useMutation` imports.
218
+
219
+ | | |
220
+ | -------- | ------------------------- |
221
+ | Type | `string` |
222
+ | Required | `false` |
223
+ | Default | `'@tanstack/react-query'` |
224
+
225
+ ### mutationKey
226
+
227
+ Builds the `mutationKey` for each mutation hook, for batched invalidations or `useMutationState`. Same props and string-inlining caveat as `queryKey`, with `variant` set to `'mutation'`.
228
+
229
+ | | |
230
+ | -------- | ------------------------------------------------------ |
231
+ | Type | `(props: { node, casing, variant }) => Array<unknown>` |
232
+ | Required | `false` |
233
+ | Default | Built-in `mutationKeyTransformer` |
234
+
235
+ ### customOptions
236
+
237
+ Routes every hook through your own function that returns extra options such as `onSuccess` or `select`. Also emits a `HookOptions` type that maps each hook name to its options type. Needs [`hooks: true`](#hooks).
238
+
239
+ | | |
240
+ | -------- | --------------------------------------- |
241
+ | Type | `{ importPath: string, name?: string }` |
242
+ | Required | `false` |
243
+
244
+ #### customOptions.importPath
245
+
246
+ Module of your custom-options hook, imported as a named import.
247
+
248
+ | | |
249
+ | -------- | ---------------------------------- |
250
+ | Type | `string` |
251
+ | Required | `true` when `customOptions` is set |
252
+
253
+ #### customOptions.name
254
+
255
+ Exported name of your custom-options hook.
256
+
257
+ | | |
258
+ | -------- | ------------------------ |
259
+ | Type | `string` |
260
+ | Required | `false` |
261
+ | Default | `'useCustomHookOptions'` |
262
+
263
+ ### hooks
264
+
265
+ When `false` (the default), only the `queryOptions`, `mutationOptions`, `queryKey` and `mutationKey` helpers are written, using factory imports that work across TanStack Query adapters. Set `true` to also generate `useQuery`, `useSuspenseQuery`, `useInfiniteQuery`, `useSuspenseInfiniteQuery`, and `useMutation`.
266
+
267
+ | | |
268
+ | -------- | --------- |
269
+ | Type | `boolean` |
270
+ | Required | `false` |
271
+ | Default | `false` |
272
+
273
+ ### resolver
274
+
275
+ Overrides generated file and symbol names. Omitted members keep `resolverReactQuery`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).
276
+
277
+ | | |
278
+ | -------- | ----------------------------------- |
279
+ | Type | `ResolverPatch<ResolverReactQuery>` |
280
+ | Required | `false` |
281
+
282
+ ::code-collapse{name="ResolverReactQuery patch members"}
283
+
284
+ ```typescript [Partial override]
285
+ type ResolverReactQueryPatch = {
286
+ // plus the shared name, file, and imports members
287
+ query?: {
288
+ name?(node: OperationNode): string // → 'useGetPetById'
289
+ optionsName?(node: OperationNode): string // → 'getPetByIdQueryOptions'
290
+ keyName?(node: OperationNode): string // → 'getPetByIdQueryKey'
291
+ keyTypeName?(node: OperationNode): string // → 'GetPetByIdQueryKey'
292
+ clientName?(node: OperationNode): string // → 'getPetById'
293
+ }
294
+ // suspenseQuery, infiniteQuery, suspenseInfiniteQuery: same members as query
295
+ mutation?: {
296
+ name?(node: OperationNode): string // → 'useUpdatePet'
297
+ optionsName?(node: OperationNode): string
298
+ keyName?(node: OperationNode): string
299
+ typeName?(node: OperationNode): string // → 'UpdatePet'
300
+ }
301
+ hook?: {
302
+ optionsName?(): string
303
+ customOptionsName?(): string
304
+ }
305
+ }
306
+ ```
307
+
308
+ ::
@@ -0,0 +1,43 @@
1
+ # React Query
2
+
3
+ Generates TanStack Query helpers for React from your OpenAPI spec. By default you get `queryOptions` and `mutationOptions` factories with their cache keys. Set `hooks: true` to also get `useQuery`, `useSuspenseQuery`, `useInfiniteQuery`, and `useMutation` hooks.
4
+
5
+ The plugin ships no HTTP client. Each helper calls a function generated by a client plugin.
6
+
7
+ ## Setup
8
+
9
+ - Add `@kubb/plugin-ts` and a client plugin: `@kubb/plugin-fetch` or `@kubb/plugin-axios`.
10
+ - Install `@tanstack/react-query` v5 or higher in the app that uses the generated code.
11
+ - Configure validation on the client plugin, not here.
12
+
13
+ ## Options worth knowing
14
+
15
+ - `client` picks `fetch` or `axios` when both client plugins are registered. A single client is detected automatically.
16
+ - `hooks` adds the `use*` hooks on top of the option factories.
17
+ - `suspense` adds `useSuspenseQuery` hooks.
18
+ - `infinite` adds infinite queries for pagination. Set `infinite.queryParam` to the query parameter that holds the page cursor.
19
+ - `query` and `mutation` set which HTTP methods become queries (`GET`) and mutations (`POST`, `PUT`, `PATCH`, `DELETE`), and where the TanStack Query runtime is imported from. Set either to `false` to skip it.
20
+ - `customOptions` routes every hook through your own function that returns extra options.
21
+
22
+ ## Example
23
+
24
+ ```typescript [kubb.config.ts]
25
+ import { defineConfig } from 'kubb/config'
26
+ import { pluginTs } from '@kubb/plugin-ts'
27
+ import { pluginFetch } from '@kubb/plugin-fetch'
28
+ import { pluginReactQuery } from '@kubb/plugin-react-query'
29
+
30
+ export default defineConfig({
31
+ input: './petStore.yaml',
32
+ output: { path: './src/gen' },
33
+ plugins: [
34
+ pluginTs(),
35
+ pluginFetch(),
36
+ pluginReactQuery({ hooks: true }),
37
+ ],
38
+ })
39
+ ```
40
+
41
+ ## See also
42
+
43
+ - [TanStack Query](https://tanstack.com/query)