kubb-labs / kubb

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

Generate `mutationKeys` for `useMutation` hooks #1102

Open wuyuanyi135 opened 1 month ago

wuyuanyi135 commented 1 month ago

What is the problem this feature would solve?

I want to have mutationKeys to arrange invalidations of queries after mutation occurs. But right now no mutationKey was generated for mutation hooks. Can this feature be implemented/?

External documents/projects?

No response

What is the feature you are proposing to solve the problem?

No response

What alternatives have you considered?

No response

helt commented 3 weeks ago

@wuyuanyi135 Can you provide details about the relevant kubb plugins this change would involve? You mean swr? Or react-query? Or whatever?

wuyuanyi135 commented 3 weeks ago

@helt Hi, I meant the react-query plugin, I wrote a template as workaround. However, since I am not familiar with this project this template may look awkward :P. The goal is to put mutationKey onto each mutation requests

import transformers, {camelCase} from '@kubb/core/transformers'
import {Function,} from '@kubb/react'
import {Mutation} from '@kubb/swagger-tanstack-query/components'
import {} from '@kubb/plugin-oas'
import {ReactNode} from "react";

export const templates = {
    ...Mutation.templates,
    react: function Template(
        {
            name,
            params,
            mutateParams,
            JSDoc,
            client,
            hook,
            dataReturnType,
        }: React.ComponentProps<typeof Mutation.templates.react>): ReactNode {

        const isFormData = client.contentType === 'multipart/form-data'
        const headers = [
            client.contentType !== 'application/json' ? `'Content-Type': '${client.contentType}'` : undefined,
            client.withHeaders ? '...headers' : undefined,
        ]
            .filter(Boolean)
            .join(', ')

        const clientOptions = [
            `method: "${client.method}"`,
            `url: ${client.path.template}`,
            client.withQueryParams ? 'params' : undefined,
            client.withData && !isFormData ? 'data' : undefined,
            client.withData && isFormData ? 'data: formData' : undefined,
            headers.length ? `headers: { ${headers}, ...clientOptions.headers }` : undefined,
            '...clientOptions',
        ].filter(Boolean)

        const resolvedClientOptions = `${transformers.createIndent(4)}${clientOptions.join(`,\n${transformers.createIndent(4)}`)}`

        const formData = isFormData
            ? `
   const formData = new FormData()
   if(data) {
    Object.keys(data).forEach((key) => {
      const value = data[key];
      if (typeof key === "string" && (typeof value === "string" || value instanceof Blob)) {
        formData.append(key, value);
      }
    })
   }
  `
            : undefined

        const keyFunctionName = `${camelCase(name, {prefix: 'get', suffix: 'MutationKey'})}`

        return (
            <>
                <Function export name={keyFunctionName}>
                    {`
         return ['${client.path.path}'];
                    `}
                </Function>

                <Function export name={name} params={params} JSDoc={JSDoc}>
                    {`
         const { mutation: mutationOptions, client: clientOptions = {} } = options ?? {}

         return ${hook.name}({
           mutationFn: async(${mutateParams}) => {
             ${hook.children || ''}
             ${formData || ''}
             const res = await client<${client.generics}>({
              ${resolvedClientOptions}
             })

             return ${dataReturnType === 'data' ? 'res.data' : 'res'}
           },
           mutationKey: ['${client.path.path}'],
           ...mutationOptions
         })`}
                </Function>
            </>
        )

    }
} as const
helt commented 2 weeks ago

Actually, exposing mutation keys is also interesting for swr.