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

Add root error info to public error #4680

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

tonidero
Copy link
Contributor

@tonidero tonidero commented Jan 17, 2025

Description

This is a possible approach to add root error info to public errors exposed by the SDK. Many times, we have nested errors, which makes discoverability of the root error difficult. This also hides actual StoreKit errors from being easily accessible, which some devs have asked about.

This PR adds a new property to the userInfo of the public error exposed by the SDK including relevant information about the root error. If the root error is a type of StoreKitError, we add some additional information related to that.

For example, when simulating an error getting products during the getOfferings call using StoreKit, a new property in userInfo rc_root_error will be added with the following structure:

{
    code = 4;
    domain = "StoreKit.StoreKitError";
    localizedDescription = "Item Unavailable";
    storeKitError =     {
        description = "not_available_in_storefront";
    };
}

or

{
    code = 2;
    domain = "StoreKit.Product.PurchaseError";
    localizedDescription = "Unable to Complete Purchase";
    storeKitError =     {
        description = "purchase_not_allowed";
    };
}

@tonidero tonidero requested a review from a team January 17, 2025 16:31
@tonidero
Copy link
Contributor Author

I want to test this more and add some tests next week, but I wanted to get some feedback, specially from iOS folks, to make sure this makes sense and if there are other ideas to expose the root StoreKit error if any to developers 🙏

@@ -39,7 +40,29 @@ extension PurchasesError {
/// let errorCode = error as? ErrorCode
/// ```
var asPublicError: PublicError {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

My main concern with this approach is whether we only expose PublicError everywhere and/or if we use this method somewhere else... Need to research it a bit more.

Comment on lines 45 to 56
var rootErrorInfo = [
"code": rootNSError.code,
"domain": rootNSError.domain,
"localizedDescription": rootNSError.localizedDescription,
] as [String : Any]
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, visionOS 1.0, *) {
if let storeKitErrorInfo = self.getStoreKitErrorInfoIfAny(error: rootError) {
rootErrorInfo = rootErrorInfo.merging(["storeKitError": storeKitErrorInfo])
}
}
let userInfoToUse = self.userInfo.merging([ErrorDetails.rootErrorKey: rootErrorInfo])
return NSError(domain: Self.errorDomain, code: self.errorCode, userInfo: userInfoToUse)
Copy link
Contributor

Choose a reason for hiding this comment

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

I am afraid we might lose some keys because of an unwanted overlap. I would just add a prefix like rc_ to any new key we add to:

  • be explicit on what we're adding
  • avoid dropping useful data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I added everything within a rc_root_error which I felt was enough as a namespace... I don't think it's worth adding to all nested properties then? Lmk if you think otherwise though!

case let .networkError(urlError):
return resultMap.merging([
"urlErrorCode": urlError.errorCode,
"urlErrorFailingUrl": urlError.failureURLString ?? ""
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe we can add an explicit missing_value, otherwise people will think we missed it

} else if let storeKitError = error as? StoreKit.Product.PurchaseError {
return ["description": storeKitError.trackingDescription]
} else {
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it would be useful to log what other error type we might be missing? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, in this case I'm assuming it's because the root error is not a store kit error (which may happen in several situations). I could add a log here, but I think the situation may happen relatively often... Note that this method is only to add extra data to the userInfo map in case it's actually a StoreKit error.

@@ -39,7 +40,29 @@ extension PurchasesError {
/// let errorCode = error as? ErrorCode
/// ```
var asPublicError: PublicError {
Copy link
Contributor

Choose a reason for hiding this comment

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

I know it's a draft, but it would be great to list the keys we'll include in userInfo so people can just read it from here without going through the code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm so I included it in the docs for the asPublicError, but that's actually internal... I'm trying to figure out a better way to explain this, but maybe this is something we should add to the docs, for people that care to get the root error.

@tonidero tonidero marked this pull request as ready for review January 21, 2025 13:27
@tonidero tonidero requested review from a team, facumenzella and aboedo January 21, 2025 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants