Skip to content
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

[ApolloPagination] Update PaginationOutput to operate over GraphQLResults #428

Merged
merged 32 commits into from
Aug 14, 2024

Conversation

Iron-Ham
Copy link
Contributor

@Iron-Ham Iron-Ham commented Jul 15, 2024

Closes: apollographql/apollo-ios#3413

Caution

This is a breaking change.

The goal of this PR is two-fold:

  1. We want to expose errors per-response when fetching data, and handle those errors gracefully where we can. While we do currently expose networking failures to consumers, we are not correctly parsing GraphQL error responses. Additionally, since we were not considering errors within the responses previously, we weren't handling them correctly. This was especially noticeable in loadAll, where some cases may lead to continued retries of fetching data.
  2. We want to simplify usage.

Changes

Broken down into:

  • Exposing Errors
  • Simplifying Usage
  • Other Changes

Exposing Errors

Changing the stored values of PaginationOutput

We started by changing the stored values of PaginationOutput to be GraphQLResult<GraphQLQuery.Data, instead of the GraphQLQuery.Data: See this diff for detail.

Changing the Output types of GraphQLQueryPager

With the changes to PaginationOutput in place, with each page containing a Source (i.e., cache or server) via its GraphQLResult, we made the choice to modify the Output values of both GraphQLQueryPager and AsyncGraphQLQueryPager such that those values are no longer tuples of (Model, UpdateSource) and are instead just Model: 1 2.

Improving loadAll

To correctly handle errors within loadAll, we first detect whether an error occurred and use that error to set isLoadingAll to false (1), which forces an exit of loadAll.

Storing the most recent result

This is important in order to know the most recent Source of an update, as well as the errors key of the most recent update. 1

Simplifying Usage

Changes to subscribe

We marked the subscribe methods of both GraphQLQueryPager and AsyncGraphQLQueryPager as deprecated: 1 2. This is because the subscribe method was already redundant: The GraphQLQueryPager and AsyncGraphQLQueryPager are Combine Publishers, and a consumer of the API can subscribe to them by calling sink.

Removal of Initializers

In conjunction with the changes related to errors, we've removed various initializers that were no longer valid given the change in return types. We considered removal of all convenience initializers and initializers that contain a transform function, but found them useful in specific applications. For example, some consumers of the library must have an output type that is not constrained to any underlying Query, as the underlying Query may be different. For those consumers, the transform: initializers remain. For all others, however, it's highly recommended that the standard transform-less initializer is used, as it retains information about the most recent value, errors within, and so on.

New computed properties

Some users have made note that they commonly employ a bit of code like this one:

let allPages = previousPages + [initialPage] + nextPages

We've added a computed property that should automatically do that for you if the pages are of the same type, as well as a computed property that surfaces all data.

Similarly, we've added a computed property that surfaces all errors from all pages.

Other Changes

We've removed conformance to Equatable on GraphQLQueryPager, as it doesn't make much sense – we were previously comparing the equatability of the current values – but not of the underlying data or state of the pager. 1 2

We've renamed the fetch case of UpdateSource to server, to be more in line with GraphQLResult.Source. 1.

Impact

The impact of this PR is:

  • Users are now aware of request-level errors when using GraphQLQueryPager
  • loadAll can no longer short-circuit.
  • The caller API is simplifying and maturing, with fewer ways to achieve the same results. This also means a net deletion of code within the library, and less surface area to support.

Copy link

netlify bot commented Jul 15, 2024

👷 Deploy request for apollo-ios-docc pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 66a0ece

Copy link

netlify bot commented Jul 15, 2024

👷 Deploy request for eclectic-pie-88a2ba pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 66a0ece

@Iron-Ham Iron-Ham changed the title Expose errors via PaginationOutput ApolloPagination: Allow for partial success and expose errors via the errors response key Jul 15, 2024
@Iron-Ham Iron-Ham marked this pull request as ready for review July 15, 2024 21:44
@Iron-Ham Iron-Ham marked this pull request as draft July 23, 2024 14:38
Copy link
Contributor

@AnthonyMDev AnthonyMDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you’re still working on getting this PR passing CI. But I’m doing some code review now and I’m having a hard time understanding some of the changes made here. Adding this PaginationResult feels like it adds a lot of complexity, both internally and in the consumption of the API in calling code.


This also seems to be concatenating all errors from individual pages into one [errors] array on the PaginationResult. That is not ideal, as it will be difficult to understand which errors came from which requests and trace them back using the error path and location.


As is often the case, this is becoming a lot more involved than was originally anticipated to solve the issues in apollographql/apollo-ios#3413. I'm wondering if there is a different approach to addressing that without making such sweeping changes.

I'm not sure if this is the right approach either, but would it be possible to keep the transform APIs, but change them to expose the errors for each query? That could allow users to determine if they want to ignore and suppress those errors or expose them however they see fit. This could mean we are just pushing off the difficulty of dealing with per-page errors to the users, rather than handling them ourselves though...

@Iron-Ham
Copy link
Contributor Author

Iron-Ham commented Jul 24, 2024

cc: @AnthonyMDev I'll push changes with the swap to using GraphQLResult within PaginationOutput following this PR Did it here

@Iron-Ham Iron-Ham marked this pull request as ready for review July 24, 2024 20:32
@Iron-Ham Iron-Ham changed the title ApolloPagination: Allow for partial success and expose errors via the errors response key [ApolloPagination] Update PaginationOutput to operate over GraphQLResults Jul 29, 2024
@Iron-Ham
Copy link
Contributor Author

Iron-Ham commented Aug 7, 2024

cc: @AnthonyMDev would it be helpful to split this into a few smaller PRs?

@AnthonyMDev AnthonyMDev merged commit 07e12aa into apollographql:main Aug 14, 2024
27 checks passed
BobaFetters pushed a commit to apollographql/apollo-ios-pagination that referenced this pull request Aug 14, 2024
BobaFetters pushed a commit that referenced this pull request Aug 14, 2024
b591b09c [ApolloPagination] Update `PaginationOutput` to operate over `GraphQLResult`s (#428)

git-subtree-dir: apollo-ios-pagination
git-subtree-split: b591b09cc9891e16d699925be4fb706b37ff2714
BobaFetters pushed a commit that referenced this pull request Aug 14, 2024
…aginationOutput` to operate over `GraphQLResult`s

git-subtree-dir: apollo-ios-pagination
git-subtree-mainline: a17a165
git-subtree-split: b591b09cc9891e16d699925be4fb706b37ff2714

extension PaginationOutput where InitialQuery == PaginatedQuery {
public var allData: [InitialQuery.Data] {
previousPages.compactMap(\.data) + [initialPage?.data].compactMap { $0 } + nextPages.compactMap(\.data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super

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

Successfully merging this pull request may close these issues.

Pagination: Errors on initial page not reported
3 participants