Skip to content

Integration with tanstack-query #1502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task
adiletto64 opened this issue Jan 14, 2024 · 3 comments
Closed
1 task

Integration with tanstack-query #1502

adiletto64 opened this issue Jan 14, 2024 · 3 comments
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library PRs welcome PRs are welcome to solve this issue!

Comments

@adiletto64
Copy link

Description
Using with react-query or vue-query (this library) you need manually return data or raise error:

import createClient from "openapi-fetch";
import type { paths } from "./v1";

const client = createClient<paths>({ baseUrl: "https//localhost:8000" });

const {data, isLoading, isError} = useQuery({
    queryFn: async () => {
        const { data, error } = await client.GET("/articles/", { params });
        if (data) return data; // here
        throw new Error(error); // and here
    }
})

Proposal
Make wrapper or another createClient, so it elegantly works with tanstack-query

const client = createQueryClient<paths>({ baseUrl: "https//localhost:8000" });

const {data, isLoading, isError} = useQuery({
    queryFn: client.GET("/articles/", { params }) // returns data or throws an error
})

Checklist

@adiletto64 adiletto64 added enhancement New feature or request PRs welcome PRs are welcome to solve this issue! openapi-fetch Relevant to the openapi-fetch library labels Jan 14, 2024
@drwpow
Copy link
Contributor

drwpow commented Jan 16, 2024

I’m against the core library throwing an error by default, because it’s this library’s design to match the fetch API. Most applications should gracefully handle error codes without a try/catch that introduces unnecessary boilerplate.

Requiring an error is a design decision of Tanstack Query that goes against the design of the fetch API. That said, I’m not opposed to a wrapper designed for Tanstack, but maybe there would be other functionality in addition to just simply throwing?

@drwpow drwpow mentioned this issue Jan 28, 2024
3 tasks
@drwpow
Copy link
Contributor

drwpow commented Jan 28, 2024

Update: with openapi-fetch adding middleware, there may be a more automatic way to achieve this: https://github.com/drwpow/openapi-typescript/pull/1521/files#diff-decdbf43769e15babbf0e979dcea2acadd305ca28f41e453db3329ad1f317b80R4

@eddie-atkinson
Copy link

Hi @drwpow,

I have a question about how this middleware works with type narrowing. I have added the middleware to my codebase like so:

import createClient, { Middleware } from 'openapi-fetch';
import { paths } from '~src/service';

const throwOnError: Middleware = {
  async onResponse(res) {
    if (res.status >= 400) {
      const body = res.headers.get('content-type')?.includes('json')
        ? await res.clone().json()
        : await res.clone().text();
      throw new Error(body, res.status);
    }
    return res;
  },
};

const client = createClient<paths>({
  baseUrl: process.env.API_URL,
});

client.use(throwOnError);

export const { GET, POST } = client;

and then used it like so:

  const { mutate } = useMutation({
    mutationFn: async (body: StatusChangeRequest) => {
      return POST('/status', {
        body,
      });
    },
    mutationKey: ['change-resource-status'],

    onSuccess({ data}) {
    // do things with the returned data

    },
    onError(err) {
     // do error things
    },
  });

The problem is the type the destructured data key is that it is <my type> | undefined. I gather from this issue that that is because the type narrows when I check for the error key and indeed doing something like:

    onSuccess({ data, error}) {
        if(!error) {
   // do things with the returned data in a typesafe way
          }

    }

I get type safety on the data key.

However, I'd ideally like to not do this, React Query allows me to separate my concerns using the onSuccess and onError callbacks in quite a nice way.

The only way I can think of solving this is wrapping GET and POST in my own helper function, something like:


type Post = (
  ...args: Parameters<typeof _POST>
) => Omit<ReturnType<typeof _POST>, 'error'>;

export const post: Post = async (url, ...rest) => {
  const { data, error, response } = await _POST(url, ...rest);
  if (error) {
    const body = response.headers.get('content-type')?.includes('json')
      ? await response.clone().json()
      : await response.clone().text();
    throw new APIError(body, response.status);
  }
  return { data, response };
};

Note this doesn't work from a TS perspective. I appreciate I'm really trying to have my cake and eat it here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library PRs welcome PRs are welcome to solve this issue!
Projects
None yet
Development

No branches or pull requests

3 participants