-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add 'errorPolicy' to FetchMoreQueryOptions interface #12298
base: main
Are you sure you want to change the base?
Add 'errorPolicy' to FetchMoreQueryOptions interface #12298
Conversation
@dlin303: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/ |
👷 Deploy request for apollo-client-docs pending review.Visit the deploys page to approve it
|
❌ Docs preview failedThe preview failed to build. Build ID: f5c7dd9f3e5e19fd23dea4af Errorsreact/data/queries
|
🦋 Changeset detectedLatest commit: 3f61712 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
d88db9d
to
0b540ea
Compare
Not sure why security-scans workflow is failing. It looks like I don't have access in CircleCI to see the actual job or failure. |
@dlin303 don't worry about that one. For some reason that security scan fails on all forked PRs. Thanks for opening the PR! We'll try and get to it soon! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is generally really great! The only change I'm requesting here is to check the rest of the renders after the error returns to ensure we understand the behavior of the hook and how it affects the component. Really appreciate you adding those additional tests to make sure this behavior is documented!
}); | ||
}); | ||
|
||
it("fetchMore does not inherits errorPolicy 'all' from original query if 'query' is defined as a parameter in fetchMore", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do find this exhisting behavior a bit odd and not entirely sure why this was written that way (oversight perhaps?). Really appreciate you adding this test as it documents the current behavior.
That said, would you mind adding a TODO
comment above this test that mentions we should come back to re-evaluate whether this is the correct long-term behavior? I see no reason why adding a query
option should behave much different than not adding one. The TODO comment will at least help remind us that this may not be optimal for long-term (definitely not something we have to fix/implement right now).
In the mean time, I'll ask around and see if I can figure out at all why this might behave this way.
loading: false, | ||
errors: [new GraphQLError("Partial pagination error")], | ||
networkStatus: NetworkStatus.error, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should probably also check what the next rendered value is after this error (i.e. you should have another await takeSnapshot()
block. Can you update this test to include that? If the hook doesn't actually rerender, add an await expect(takeSnapshot).not.toRerender()
call at the end (I think we should do this regardless after we've checked all the renders)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing. Updated.
letters: prev.letters.concat(fetchMoreResult.letters), | ||
}), | ||
}) | ||
).rejects.toThrow("Partial pagination error"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other comment, can we check the rest of the renders to see how the error affects the hook in the component itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
errors: [new GraphQLError("Partial pagination error")], | ||
networkStatus: NetworkStatus.error, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, let's check the rest of the renders here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. Turns out this test was actually missing the query
parameter on line 6205 despite the description, so added that as well.
7ae729f
to
3f61712
Compare
Not quite sure why that particular test for CircleCI UI seems to suggest that it's a flaky test, but I don't appear to have the ability to rerun it in CircleCI from the console without force-pushing my change over and over. Anyone have any insight whether or not this is an expected flaky test when running in a CI environment? |
@dlin303 we have a few flaky tests and this happens to be one of them. I've restarted that test suite to see if it passes this time. Unfortunately the frequency of these flakes seems to be increasing lately 🤦♂️ |
Hey @dlin303 👋 The more we've talked about this throughout the week, the more @phryneas and I agree that an As such, we think the correct approach would be to leave the TypeScript types as-is and instead fix the issue by always overriding I'm very sorry for the back and forth on the solution here. For your specific situation where you're ok with partial results, what I'd recommend is a custom link that would remove const ignoreErrorsLink = new ApolloLink((operation, forward) => {
return forward(operation).map((result) => {
if (operation.getContext().ignoreErrors && result.errors) {
return { ...result, errors: undefined };
}
return result;
});
}) Then in your fetchMore({ context: { ignoreErrors: true } }); Hopefully something like this will work for your use case. |
Hey @jerelmiller, thanks for the response and the thought you and @phryneas have put into the issue! Totally understand the concern about building footguns and why that might be a problem. I'd like to consider a few things however. It seems that the concern with merging partial data would apply regardless, as there is nothing preventing the main query, or any other query touching that node, from writing partial data to the cache even if Overriding errorPolicy to To address the original footgun, would it be unreasonable to default to always overriding |
This is true, but I think of it more on the mechanics of how
apollo-client/src/core/ObservableQuery.ts Lines 552 to 556 in eeba2ef
If you do provide an apollo-client/src/core/ObservableQuery.ts Lines 533 to 544 in eeba2ef
If you perform explicit cache writes in your own code with partial data, at least the write operation itself is signal enough that you intend to write that data as-is. Again, the goal isn't to eliminate the cache write entirely, its just to ensure the default behavior doesn't get you in a state that you don't expect. Since That said, perhaps you can give me a more detailed view at your use case. I'd like to better understand more in-depth how you've designed your API to work with pagination so that errors with partial data can be handled correctly. If we support this in the client, we need to be able to explain cases where its ok to use this to other users who ask these questions. The best I can promise is that I'll noodle on this some more over the weekend. Better understanding your use case will help me understand the best course of action. Appreciate the conversation! |
Thanks for the in-depth explanation! I'll double check with my teammates on exactly how we're handling things on the service to make sure I'm not missing any gaps. It could absolutely be the case that we are inadvertently blowing our toes off without knowing 💥 Will let you know! I appreciate the time and hope ya'll have a great weekend! |
Hey @jerelmiller, got a chance to chat with my teammates on the service side. Here's a rough summary of our usecase: We are paginating through dynamic content - i.e. recommendations often change for the user, and the user is not aware of any enforced order. In the event of a partial error in this scenario, we would like to make a best effort rendering of what we are able to receive, rather than error out completely and not show the user anything at all. In most cases of partial error, our service ends up returning the correct # of items, as the errors usually pertain to pieces of missing metadata within the item, which generally do not affect rendering or cache in a significant way. In the event that pagination itself is affected, our service returns a full error, rather than erroneous or incomplete The general takeaway though, are that strong defaults with the option to override seems like it would provide the most intuitive developer ergonomics to handle a variety of different pagination behaviors. Perhaps naming the param something like |
I obviously can't speak for every organization out there, we're far from exports but I think we've learned to carefully monitor cache state and the effects our various queries have on it for troubleshooting 😆 |
Adds
errorPolicy
option toFetchMoreQueryOptions
interface to expose errorPolicy functionality onfetchMore
to TypeScript.Fixes: #12297