Skip to content

Is this package also useful for one vs many queries? #39

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

Open
EllaBudy opened this issue Feb 9, 2025 · 8 comments
Open

Is this package also useful for one vs many queries? #39

EllaBudy opened this issue Feb 9, 2025 · 8 comments
Labels
question Further information is requested

Comments

@EllaBudy
Copy link

EllaBudy commented Feb 9, 2025

Let's say I have a query getPosts() and a query getPost(id). My goal is, if I already have all posts, why would I need to get that single post from the server again? So I want getPost(id) to just return my post without querying the server. Will the package achieve this goal?

Thank you!

@klis87
Copy link
Owner

klis87 commented Feb 9, 2025

You could use https://github.com/klis87/normy/tree/master/packages/normy-react-query#getObjectById-and-getQueryFragment-arrow_up

I am not sure if it is possible to use it like described with newest react-query - I mean it is for sure to populate data before request is fired, but I am not sure it is actually possible to prevent that request this way.

But you could always pass data from getObjectById to your query function, and it could just return this data instead of doing actual request, so this should be definitely possible.

@klis87 klis87 added the question Further information is requested label Feb 9, 2025
@EllaBudy
Copy link
Author

Thank you so much for the quick response!

I'm just coming from an Apollo GraphQL background where you get this feature for free due to the cache normalization. I'm referring to a situation where the getPost(id) query would not fire before I have all the posts. Imagine an Amazon page where you have all the products, and then you go into a specific product view. So you already have the data at that point, no need to bring it from the server again. Unless, the user opens up a specific product view directly because they have a link to that product - in which case I would like to query the server.

So basically, if I'm using rtk query, I wouldn't be able to use their built-in queries, I would have to add the getObjectById part. Thank you!

@EllaBudy
Copy link
Author

This is what I was referring to:

By default, the useQuery hook checks the Apollo Client cache to see if all the data you requested is already available locally. If all data is available locally, useQuery returns that data and doesn't query your GraphQL server. This cache-first policy is Apollo Client's default fetch policy.

There is also the cache-and-network policy:

cache-and-network: Apollo Client executes the full query against both the cache and your GraphQL server. The query automatically updates if the result of the server-side query modifies cached fields.Provides a fast response while also helping to keep cached data consistent with server data.

https://www.apollographql.com/docs/react/data/queries#setting-a-fetch-policy

@klis87
Copy link
Owner

klis87 commented Feb 10, 2025

I completely understand your use case, not sure though how to ideally implement it with rtk-query. I suspect though, that you could do this trick I mentioned for react-query, having a query function like:

const getPost(id: number, postFromList?: Post) => postFromList ?? axios.get(`/posts/${id}`)

Unfortunately this cannot be done automatically like in graphql world, because Normy calculates normalization base on responses, and it does not know anything about a response until it arrives. If you have any problems with this, we will try to find another solution :)

@EllaBudy
Copy link
Author

Thanks! Is it not possible to do the same with rtk-query? My project uses rtk-query and not react-query.

Also, can't normy know the response type based on the type definition of the query?

@klis87
Copy link
Owner

klis87 commented Feb 11, 2025

Also, can't normy know the response type based on the type definition of the query?

You would need to give me example. But if you mean if Normy can work like graphql, to inspect objects at build time, not in runtime, then at the moment not. Because types are typically not analyzed in runtime. This would be an interesting feature though, albeit complex one, to optionally add a build parser, so you could define response types ahead, so object structures of queries would not need to be constructed in runtime

Thanks! Is it not possible to do the same with rtk-query? My project uses rtk-query and not react-query.

I think it is possible, you still have getObjectById from normy, and you still fire requests, be it with fetch api or axios or similar. Before I gave you some idea how to update/wrap a request function, so that it would return passed object postFromList instead of firing request. If I remember correctly, rtk-query is also promise based, so you could do whatever you wanted I hope

@EllaBudy
Copy link
Author

EllaBudy commented Feb 13, 2025

Here's an example from my code:

apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    getAllOpenPayments: builder.query<Payment[], void>({
      query: () => `${paymentsPrefix}/`,
      providesTags: (result) => {
        if (result) {
          return [
            { type: "Payment", id: "List" },
            ...result.map((payment) => ({
              type: "Payment" as const,
              id: payment.external_id,
            })),
          ];
        }
        return [{ type: "Payment", id: "List" }];
      },
    }),
    getPayment: builder.query<Payment, string>({
      query: (externalId) => ({
        url: `${paymentsPrefix}/${externalId}`,
      }),
      providesTags: (payment) => [
        { type: "Payment", id: payment.external_id },
      ],
    }),

So in this case you could tell that the getPayment query returns a single Payment just like getAllOpenPayments. So if I'm asking to getPayment("ABCD"), you could just check the cache (at runtime) and see that there's already such payment with all the relevant fields and return it. Yes it would require relying on the type definition so maybe the only solution would involve a build parser as you suggested.

Does that make sense?

I'm just wondering how people are doing it today, since this is my first non-GraphQL project where I'm doing the frontend, are people just issuing multiple queries even though they already have the objects? And showing a loader in the frontend for a while? This is unnecessary waiting for end-users. I thought of passing the payment as an argument to the component but then if the user goes directly to the single-object page it would fail.

I guess your solution of manually getting the object by ID from the cache would solve all the issues, it's just very manual and repetitive compared to the GraphQL approach.

@klis87
Copy link
Owner

klis87 commented Feb 17, 2025

Thanks for example.

I'm just wondering how people are doing it today, since this is my first non-GraphQL project where I'm doing the frontend, are people just issuing multiple queries even though they already have the objects?

Usually it is even worse in not graphql world, many people do query refetches after every mutation. This is why I created normy, so most updates can be done automatically, without manual query data updates or refetches.

But the use case from this issue cannot be solved automatically, as we would need to know dependencies between queries on build time. Also, imagine that detail endpoint would hold a field which is not present in the list, you would need to make request to detail endpoint anyway to get those missing fields. This is actually a typical case in REST, as list endpoints are optimized, as you do not pick fields which you need but you get them all.

So for now this has to be done manually, probably with helpers I pasted you before.

For the future, we could think about some build time algorythm, but it will not be trivial and fast to do, we would need to design it first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants