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

Build a better way for users to derive a cache key in a type safe way #3478

Closed
PSinha1202 opened this issue Nov 22, 2024 · 7 comments
Closed
Labels
feature New addition or enhancement to existing solutions

Comments

@PSinha1202
Copy link

Use case

More details here:
https://community.apollographql.com/t/how-can-we-avoid-sending-hardcoded-format-while-reading-fragment/7951/3

Can we have a better way to send the non-hardcode key as defined below

ref: Direct cache access - Apollo GraphQL Docs - Apollo Doc

let data = try transaction.readObject(
ofType: HeroDetails.self,
withKey: "Hero:123"
)

The reason is when we updated the SDK, we missed changing the cacheKey format, and we hit an issue since theing that key format. Trying to avoid such things in the cacheKey format had changed and we missed updat future.

We set the format of cacheKeyInfo as below, as defined in doc.

cacheKeyInfo(for type: ApolloAPI.Object, object: ApolloAPI.ObjectData) -> CacheKeyInfo? {
guard let id = object["id"] as? String else {
return nil
}
return CacheKeyInfo(id: id)
}

Describe the solution you'd like

Build a better way for users to derive a cache key in a type-safe way. Giving caller more custom formatting of CacheKey, so we can avoid the above issues in future.

@PSinha1202 PSinha1202 added the feature New addition or enhancement to existing solutions label Nov 22, 2024
@calvincestari
Copy link
Member

Thanks for creating the issue @PSinha1202.

Build a better way for users to derive a cache key in a type-safe way. Giving caller more custom formatting of CacheKey, so we can avoid the above issues in future.

I don't think we'd allow full customization of the cache key but being able to derive the same cache key for manual read/write transactions as is used for response-based cache persistence is likely where we'll end up.

@AnthonyMDev
Copy link
Contributor

I do agree that right now this isn't great. The user needs to input a stringly-typed value that is derived from implicit knowledge the developer needs to have about the way we construct cache keys. This is very far from ideal.

I'm not sure what the solution looks like though. At the time of calling readObject(ofType:withKey:) the user doesn't have the object that they are trying to get the cache key for (that's why they are calling readObject). So even if there was a function for deriving a cache key, they wouldn't have the object to pass into that call. What type of mechanism could we even provide that would make this easier?

@PSinha1202
Copy link
Author

PSinha1202 commented Nov 22, 2024

Thanks for the information and please correct me if i am wrong.

We have this func

public static func cacheKeyInfo(for type: ApolloAPI.Object, object: ApolloAPI.ObjectData) -> CacheKeyInfo? {
    guard let id = object["id"] as? String else {
      return nil
    }
    return CacheKeyInfo(id: id, uniqueKeyGroup: "xyz\(type.typename)") --> if no uniqueKeyGroup sent, it defaults to type.typename i believe.
  }

which defines the CacheKeyInfo and is being sent to transaction metadata. But it keep the format always as
return "\(info.uniqueKeyGroup ?? type.typename):\(info.id)"
but lets say we provide an optional param to this customizedUniqeKey (it can be better name)

func CacheKeyInfo(id: id, uniqueKeyGroup: "xyz\(type.typename)", customizedUniqeKey: String)
and then we can have this func

@inlinable public static func cacheKey(for object: ObjectData) -> String? {
    guard let type = graphQLType(for: object),
          let info = configuration.cacheKeyInfo(for: type, object: object) else {
      return nil
    }
    return info.customizedUniqeKey ?? "\(info.uniqueKeyGroup ?? type.typename):\(info.id)"
  }

Will it solve the entire problem? Possibly No. But since customizedUniqeKey is defined by the caller, we can safely use that for readObject by passing the key, without worrying if the sdk update.

@AnthonyMDev
Copy link
Contributor

Ah, I see. It sounds like you are asking for a way to bypass the prepending of the typename/uniqueKeyGroup. I don't think that is something we want to do. The normalization mechanisms of the cache really depend on objects being grouped by typename or some other grouping. Otherwise, it would be too easy to have cache key collisions between objects of different types.

I think a better addition would be to add a new method: readObject(ofType: SelectionSet.Type, withCacheKey: CacheKeyInfo). That way you could provide a CacheKeyInfo with both the key and the optional uniqueGroupID and we would do the concatenation of the two internally. This would also add consistency, as it's clear that you are expected to input a CacheKeyInfo that is equal to the one output from your cacheKey(for object:) method.

Would that resolve this for you?

@PSinha1202
Copy link
Author

ohh yeah, i din't thought about it. yes adding a new method to send CacheKeyInfo will surely make it future proof.

@AnthonyMDev AnthonyMDev changed the title Build a better way for users to derive a cache key in a type safe way Provide cache transaction methods that use CacheKeyInfo Nov 25, 2024
@AnthonyMDev AnthonyMDev changed the title Provide cache transaction methods that use CacheKeyInfo Build a better way for users to derive a cache key in a type safe way Nov 25, 2024
@AnthonyMDev
Copy link
Contributor

Okay great! I'll create a new issue to track that and close this one out. Not sure exactly when we'll get to this work, but if you'd like to take a crack at writing a PR for it yourself, we're always happy to have contributions!

Copy link
Contributor

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo iOS usage and allow us to serve you better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New addition or enhancement to existing solutions
Projects
None yet
Development

No branches or pull requests

3 participants