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

Refactor WordPressComRestApiError #696

Merged
merged 13 commits into from
Jan 19, 2024

Conversation

crazytonyli
Copy link
Contributor

Description

In upcoming PRs, I'll add functions to WordPressComRestApi which use URLSession to make API calls. The newly added URLSession returns enum WordPressAPIError type. That means, NSError instances that are returned by WordPressComRestApi will change internally: In cases where returns a WordPressComRestApiError, they will return WordPressAPIError after the refactor(*). That means the domain and code value in those NSError instances will be changed too. This change of course impacts the error handling code on the app side.

Note

There are some info in WordPressKit/WordPressAPIError+NSErrorBrdige.swift that I don't repeat here. Please have a read there too.

There are mainly two kinds of code that handles NSError returned by WordPressComRestApi:

  1. Checking its domain and code: domain == "WordPressComRestApiError" && code == WordPressComRestApiError...
  2. Casting into WordPressComRestApiError: error as? WordPressComRestApiError.

Once the aforementioned refactor is implemented, it's pretty easy to migrate the second error handling code: by simply resolving Swift compiler errors.

However, the first error handling code is more tricky to resolve. Because it's largely used in Objective-C code which can't access enum WordPressAPIError<EndpointError> Swift type.

One way to solve the issue is making sure returned NSError instances (their domain, code, user info) do not change, even though the type of errors from where they are casted has been changed: the three NSError instances below are equal.

  1. WordPressComRestApiError.<code> as NSError (old code)
  2. WordPressComRestApiEndpointError(code: <code>) as NSError (new code).
  3. WordPressComRestApiEndpointError(code: <code>) as NSError (new code).

(*): Since we haven't implemented the new API call functions, this PR changes the existing functions to return WordPressComRestApiEndpointError instead of WordPressAPIError for now. But eventually, the errors will be WordPressAPIError<WordPressComRestApiEndpointError>

Note

It might be easier to review this PR commit by commit.

Testing Details

See the updated unit tests.


  • Please check here if your pull request includes additional test coverage.
  • I have considered if this change warrants release notes and have added them to the appropriate section in the CHANGELOG.md if necessary.

…iError

This is an unfortunate comprosie we need to make during a refactor(*).
After the refactor is done, the `error` variable here should be of type
`WordPressAPIError<WordPressComRestApiEndpointError>`. That means,
at the end, we can access the 'error code' in a more strongly-typed way.

(*): A WordPressComRestApi refactor to make it return
`WordPressAPIError` in its Swift API, instead of `NSError`.
@crazytonyli crazytonyli requested a review from mokagio January 18, 2024 01:57
@crazytonyli crazytonyli mentioned this pull request Jan 18, 2024
2 tasks
mokagio
mokagio previously approved these changes Jan 19, 2024
switch self {
case let .endpointError(endpointError):
return (endpointError as NSError).code
// Use negative values for other cases to reduce chances of collision with `EndpointError`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Smart

/// In theory, we should not need to implement this bridging, because we should never cast errors to `NSError`
/// instances in any error handling code. But since there are still Objective-C callers, providing this custom bridging
/// implementation comes in handy for those cases. See the `WordPressComRestApiEndpointError` extension below.
extension WordPressAPIError: CustomNSError {
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL about CustomNSError

@mokagio mokagio dismissed their stale review January 19, 2024 00:27

I approved out of habit, when what I wanted to do was "this commit looks good, let's move to the next"

Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

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

Left a couple of code suggestions, nothing blocking.

let errorWithLocalizedMessage = NSError(domain: nsError.domain, code: nsError.code, userInfo: userInfo)
return errorWithLocalizedMessage

let message = NSLocalizedString("Limit reached. You can try again in 1 minute. Trying again before that will only increase the time you have to wait before the ban is lifted. If you think this is in error, contact support.", comment: "Message to show when a request for a WP.com API endpoint is throttled")
Copy link
Contributor

Choose a reason for hiding this comment

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

Good occasion to add key as well? I mean, I understand this is a refactor so behavior should not change, but I think we can squeeze this in:

Suggested change
let message = NSLocalizedString("Limit reached. You can try again in 1 minute. Trying again before that will only increase the time you have to wait before the ban is lifted. If you think this is in error, contact support.", comment: "Message to show when a request for a WP.com API endpoint is throttled")
let message = NSLocalizedString(
"wordpresskit.api.message.endpoint_throttled",
value: "Limit reached. You can try again in 1 minute. Trying again before that will only increase the time you have to wait before the ban is lifted. If you think this is in error, contact support.",
comment: "Message to show when a request for a WP.com API endpoint is throttled"
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Code squeezed. 3cc7a80

Comment on lines 360 to 361
let nserror = self.processError(response: response, originalError: error).flatMap { $0 as NSError }
failure(nserror ?? (error as NSError), response.response)
Copy link
Contributor

Choose a reason for hiding this comment

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

The original naming of the value made me feel confused when reading (error as NSError).

What do you think of processedError

Suggested change
let nserror = self.processError(response: response, originalError: error).flatMap { $0 as NSError }
failure(nserror ?? (error as NSError), response.response)
let processedError = self.processError(response: response, originalError: error).flatMap { $0 as NSError }
failure(processedError ?? (error as NSError), response.response)

@crazytonyli crazytonyli merged commit e9afb31 into trunk Jan 19, 2024
6 checks passed
@crazytonyli crazytonyli deleted the wordpress-com-rest-api-error-type-change branch January 19, 2024 02:04
@kean
Copy link
Contributor

kean commented Jan 24, 2024

It's a breaking change for WordPressAuthenticator. I suggest adding a deprecation for backward compatibility:

@available(*, deprecated, renamed: "WordPressComRestApiErrorCode", message: "`WordPressComRestApiError` is renamed to `WordPressRestApiErrorCode`, and no longer conforms to `Swift.Error`")
public typealias WordPressComRestApiError = WordPressComRestApiErrorCode

I can do that in the scope of #704

@crazytonyli
Copy link
Contributor Author

It's a breaking change for WordPressAuthenticator.

Yes indeed. As noted in the changelog file, this PR introduces a breaking change.

I suggest adding a deprecation for backward compatibility:

The new typealias still introduces a breaking change, because WordPressComRestApiErrorCode no longer conforms to Swift.Error.

BTW, I have made some changes (wordpress-mobile/WordPress-iOS#22434, woocommerce/woocommerce-ios#11755, and wordpress-mobile/WordPressAuthenticator-iOS#829) to adopt these breaking changes. They are still in draft, because we haven't released a new WordPressKit version yet. But, if these breaking changes are blocking you, I can look into releasing new versions of the libraries?

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.

3 participants