-
-
Notifications
You must be signed in to change notification settings - Fork 493
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
(Auto) Abortable API #1126
Comments
I would like to weigh in on this as a regular library consumer - I think it's best to leave such functionality to libraries like tanstack-query. They already support query auto-cancellation with signals and deduplication. If you provide that functionality - people will still reach out to solutions like tanstack because it provides a lot of other useful functionality on top: caching, cache invalidation, pre-fetching, refetch on mount, focus etc, retries and many more. So either openapi-fetch would have to provide those too(and framework specific solutions as well) or people will use both libraries in tandem but now a lot of double work is being done. Tanstack uses first request as a base for deduplication - your solution seems to suggest you will use the last one as a base. Now there could be hard to debug problems due to this because it's hard to understand what even cancelled the request. But once again that's just my pov of what I expect a library to do. Perhaps another route is to go tRPC way and to publish some compatibility layer which will make it easier to use openapi-fetch and tanstack-query together. This also might be much easier to implement since a lot of functionality is already done for you and all you need to do is just implement a way for your two libraries to communicate. |
That’s a great point. And I have been using React Query (Tanstack) in a production app and I agree—it provides caching, stale request refetching, and other utilities that are separate concerns from this library. I’ve been using openapi-fetch with it pretty successfully. I think that’s a good enough reason to keep this library minimal and not concern itself with higher-order things like this (there are some minor API QoL improvements over the raw Open to revisiting this in the future, but I think it’s not a priority for now. |
@drwpow I think making a small compat layer would be nice - I don't think it would need to provide any functionality beyond generating a key automatically with an api call based on verb, path, params & body. And also being able to get a key by providing a verb, path, input your self or something like that - for query invalidations and such. Everything else can be solved in user-land and so you don't even need framework-specific adapters. We just provide a user with a queryFn and a queryKey and they plug those in themselves. I did that already for our project but it was a bit hacky due to how TS doesn't handle generics within generics well and I didn't wanna patch the library - but it works more or less but it could be more stable if it were done on a library level. |
I think for now, I’d be interested in maybe expanding the React Query example before trying to turn it into an actual maintained library. For us, we started off with a lot of duplicated code that seemed like it could be deduped. But very quickly, each query/mutation evolved to handle unique concerns based on the endpoint (for example, some queries would invalidate others’ keys for refetching; other mutations would fire background API calls that partially updated data caches, etc.). And there’s no clear/sane way we could automate those unique concerns. So in at least one real-world example, there’s not a compat layer we could write that wouldn’t be overridden in about every case with only a couple weeks of usage. With all the flexibility React Query provides I’m not confident a compat layer could exist that would help most people (at least not until I could see it for myself and kick the tires). But again, showing an example of a good pattern is always helpful! And could possibly yield ideas to turn it into a library one day. |
My idea of a compat layer(and what I did in our project) was basically this declare function createQueryData(verb, path, input): QueryData;
type QueryData = {
// this input is merged with the one from createQueryData
runQuery: (input) => void,
queryKey: [[path, verb?], input?]
};
declare function getQueryKey(queryData: QueryData, type: "precise" | "route & verb" | "route & all verbs"): QueryData.queryKey And then you just create your queryData objects and plug them into tanstack query functions however you like - you have a Here's a gist with a more concrete example of my implementation - it's quite hacky but I believe a more "pretty" solution could be achieved if this was done more on a library level. So it's the responsibility of a user to pass in generated key explicitly and to use these functions at all, it's not done implicitly like in trpc-query, but on the other hand it's a flexible solution which doesn't require to create a framework specific solution each time, you can use it with any framework. |
Personally I would like to see abort and other features somehow integrated with this library. Maybe not in the core but as am official plugin. Plenty of apps not using React Query or even React. |
Another idea I’ve been thinking about is either making requests auto-abortable, or providing an easier API than the standard AbortController API when it comes to resubmitting requests. Some ideas:
Option A: implicit params match
Requests that hit the same endpoint with the same options will be automatically aborted. This is “magic” and also will increase the project weight by a significant amount by adding in the equality evaluation (which may also be buggy).
Option B: explicit ID
This is less magic, will have almost no impact on library weight, and won’t be buggy.
Note that in both instances, I think it’s only correct that the silently aborted call be replaced with the call that overrode it. Because if it simply erred, then it would cause the implementor to have to deal with an entirely new layer of typechecking (i.e. rather than simply handling
data
orerror
, they’d now have to always handledata
,error
, oraborted
). There’d be no easy way for this library to match the abort error shape to the API shape, since the API shapes happen statically whereas the abort error happens at runtime (which has no knowledge of any types).The “don’t add another typechecking layer” restriction is one I feel strongly about, since this library is meant to reduce complexity and boilerplate and not add to it.
The text was updated successfully, but these errors were encountered: