"Clean" way to centralize API calls in RQ while still keeping some typesafety?
Currently I have something like this (using
ky which is kinda like axios)
And usage would be:
But this looks kind of ugly to me, though I have no idea how it's usually implemented. This is basically just writing 1 custom hook for every single kind of API call I would have, which doesn't seem right.
I tried one other version with a single custom hook called useApi() which accepted all kinds of props, and returns a specific useQuery() call for that query only (though this looks like it violates the rules of hooks), however the problem with this is that const { data } = useApi() would type data as a union of all possible return types instead, ruining any typesafety I'd have.5 Replies
quickest-silver•3y ago
Not entirely sure what the question is. The first implementation looks good to me, although I would personally not wrap it in the
api abstraction but rather call useGetPlaylists directly. For your question about data being a union, you might find a solution in using discriminated unions as return type, like https://twitter.com/mattpocockuk/status/1679433277730353152Matt Pocock (@mattpocockuk)
A lot of people talk about generic React components.
But I think the MUCH more useful tip (and often easier to grok) is using discriminated unions in React props.
Here, we make a version of the 'as' prop to choose between the 'button' and 'a' tags, with different props on both.
Likes
1210
Retweets
106

Twitter
eastern-cyanOP•3y ago
Thanks for replying!
First implementation I forgot to mention that I would wrap them in separate
[something]Api like playlistApi or videoApi and put each of them in the feature's folder (vertical slice ish) rather than a single src/api/api.ts file.
What I was thinking about is that it looks like I'd have a separate custom hook for every single endpoint in my API and I didn't think that's very realistic in real systems with hundreds of endpoints.
Which leads me to the 2nd question I had, where I did try implementing a single useApi() hook with specific props returning a specific useQuery() and its related query keys, data fetching callback and other settings. But I couldn't get it to type the return value properly.
What I want is the hook to be able to infer what the return type is, depending on its props (in this example, calling useGetPlaylistApi() should infer that res.data is Response_Query_GetPlaylists | undefined, while useGetPlaylistApi(3) should infer that res.data is Response_Query_GetPlaylist | undefined.inland-turquoise•3y ago
That'll require some generics and you'll probably lose type inference from react query. Having one hook per API is way simpler to me, or you can also go with the query key factory pattern:
https://tanstack.com/query/v4/docs/react/community/lukemorales-query-key-factory
Query Key Factory | TanStack Query Docs
Typesafe query key management with auto-completion features. Focus on writing and invalidating queries without the hassle of remembering how you've set up a key for a specific query!
quickest-silver•3y ago
Agree with @julien . Like he said, you should overwrite inference and use your own generics if you want to achieve something similar. Wouldn't recommend personally
eastern-cyanOP•3y ago
Oh wow, that looks way more complicated than I expected, and I don't even have a justifiable reason to do that ("what I currently do doesn't look pretty when there's lots of endpoints" isn't really valid)
Thanks everyone, guess I'll just stick to simple, separate hooks for now