hey-api / openapi-ts

✨ Turn your OpenAPI specification into a beautiful TypeScript client
https://heyapi.vercel.app
Other
1.1k stars 90 forks source link

How to `queryClient.invalidateQueries` in `hey-api/openapi-ts` #980

Closed sagardwivedi closed 1 month ago

sagardwivedi commented 1 month ago

Description

I have implemented the following code:

const profileMutation = useMutation({
    ...updateUserMutation(),
    onSuccess: () => {
        toast({
            title: "Success",
            description: "Profile Updated"
        });
    },
    onError: (error) => {
        const errorMessage = getErrorMessage(error);

        toast({
            title: "Something went wrong",
            description: errorMessage,
            variant: "destructive",
        });
    },
    onSettled: () => {
        queryClient.invalidateQueries({ queryKey: ["readUser"] });
    }
});

I am encountering an issue determining the queryKey for readUser. The readUserOptions function is defined as follows:

export const readUserOptions = (options?: Options) => {
    return queryOptions({
        queryFn: async ({ queryKey }) => {
            const { data } = await readUser({
                ...options,
                ...queryKey[0],
                throwOnError: true,
            });
            return data;
        },
        queryKey: [createQueryKey("readUser", options)],
    });
};

The queryKey is generated by a function and it seems cumbersome to manually specify it for invalidateQueries. Could you advise on the best approach to handle this scenario?


Let me know if there's anything else you need!

Reproducible example or configuration

https://stackblitz.com/edit/hey-api-client-fetch-tanstackreact-query

OpenAPI specification (optional)

No response

System information (optional)

No response

stackblitz[bot] commented 1 month ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

mrlubos commented 1 month ago

@sagardwivedi Maybe to begin with, we could export query keys separately in addition to the functions

sagardwivedi commented 1 month ago

What's the use of

export const loginAccessTokenOptions = (
  options: Options<LoginAccessTokenData>,
) => {
  return queryOptions({
    queryFn: async ({ queryKey }) => {
      const { data } = await loginAccessToken({
        ...options,
        ...queryKey[0],
        throwOnError: true,
      });
      return data;
    },
    queryKey: [createQueryKey("loginAccessToken", options)],
  });
};

Because loginAccessTokenMutation is be use based on the openapi.json

export const loginAccessTokenMutation = () => {
  const mutationOptions: UseMutationOptions<
    LoginAccessTokenResponse,
    LoginAccessTokenError,
    Options<LoginAccessTokenData>
  > = {
    mutationFn: async (options) => {
      const { data } = await loginAccessToken({
        ...options,
        throwOnError: true,
      });
      return data;
    },
  };
  return mutationOptions;
};

So why it is creating a loginAccessTokenOptions also because I unable to see the usage of it.

mrlubos commented 1 month ago

For now, it's a safe default. We'd probably want to be smarter around which functions we generate, but there's no harm in giving you more, you simply won't use them. The idea is that sometimes people use POST requests instead of GET to fetch data, for example if they have a lot of query parameters and prefer to move them inside request body. You could ask the same question around queries/infinite queries, that also creates duplicates.

mrlubos commented 1 month ago

@sagardwivedi In the next release, your readUser query could be invalidated like this:

queryClient.invalidateQueries({
  queryKey: readUserQueryKey(options),
});

It's likely that you will want to invalidate all queries of the same type

queryClient.invalidateQueries({
  queryKey: [{
    id: readUserQueryKey(options)[0].id,
  }],
});

The query key function is strict for now, we could make it partial if needed. Perhaps a byId() function could be added to help with the second scenario in a type-safe way, let me know your thoughts when you try it!