-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[WIP] FirebaseFunctionsSwift #8854
[WIP] FirebaseFunctionsSwift #8854
Conversation
…s I can't find Xcodes location for my shared scheme when using a custom workspace with the firebase-ios-sdk added as a local package.
Now rebased on codable-refactor branch which includes the merged #8853 |
We could also go for something a little more opinionated.
The use would be:
This means that the If this is a style you like, then that could either be added to the current PR - or the other Let me know what you think. And also about the naming ( |
c90e26a
to
b900e9c
Compare
|
||
public func call<T: Encodable, U: Decodable>(_ data: T, | ||
resultAs: U.Type, | ||
encoder: StructureEncoder = StructureEncoder(), |
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 am new to the party here and just started looking at this.
I wonder if you have considered adding this API to Functions
instead? This would then look as such:
let callable = functions.httpsCallable("HelloWorld", encoder: Foo, decoder: Bar);
callable.call(data);
This follows the pattern that Firestore uses on the Web and prescribes the schema for all functions call. You can see how we specify a schema for a Firestore collection here: https://firebase.google.com/docs/reference/js/firestore_.collectionreference.md#collectionreferencewithconverter
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.
Hi @schmidt-sebastian ,
Thank you for the suggestion - I think that API strikes a really nice balance between ease of use preventing unintended types at the call site.
I'll go ahead and update the PR and close the related discussion thread.
Thanks again, Sebastian!
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 am not sure I fully understand the last update. I was hoping we could get rid of the "encoder" and "decoder" from cal()
and just pass it to HTTPSCallable
, which would then use the same encoder/decoder for every function call. Let me know if I am missing something 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.
Sorry, I misunderstood your suggestion then. The reference to the Firestore js api where you send a transform along made me think that you meant the encodable and decodable types (since they basically correspond to transforms between a serialized representation and an entity).
I can of course bring in the encoder and decoder at this point in the api too.
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.
The main idea behind this is that I think the encoder
and decoder
are more tied to the Function rather than the Function invocation - and they should be the same for all invocations.
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 am in favour of configuring the encoder / decoder on httpsCallable.
Morten - you mentioned "modifying the state of the encoder/decoder" - when would a user do this?
Also, I guess thread-safety is a concern for any code that uses an encoder/decoder, so telling the users that if they plan to re-configure the encoder/decoder instance, they need to do so in a thread-safe way. As Sebastian mentioned, most users should be fine with the defaults (at least we should try to make sure they can), so anyone using a custom encoder/decoder should hopefully know what they're getting themselves into :-)
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.
Hi @peterfriese ,
Likely they would never do that - although userInfo
could be used together with an encodable or decodable entity for some custom purpose.
And you're right that this basically the same as other usages of encoders and decoders - but there is one difference:
The httpCallable
is specifically intended for longer durations where you create you callable and invoke it many times, where with all other usages I have seen myself, it is customary to create and configure the encoder or decoder for a single use - as in the Codable overlay for Firestore.
It's likely not an issue, but as I mentioned somewhere else in this thread it represents a pattern of usage of the encoder and decoder that I haven't met before.
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.
But using something besides the defaults may not be very uncommon. For instance through a preference for snake cased keys in JS, but not in Swift...
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.
And apologies for using 'you' to refer to you all working on the Firebase Apple sdk collectively. I know that you may of course have different opinions. 😊
I you wish to try out the two flavors of generics discussed above, toggle between head and head minus two commits. 😊
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.
Also note that I am in the process of adding tests so you can see the call site after @paulb777 made it possible to use the required 'fakes' from Swift. I think I'll have the tests ready tomorrow.
Let me know if you like the |
…tureEncoder/Decoder
…s I can't find Xcodes location for my shared scheme when using a custom workspace with the firebase-ios-sdk added as a local package.
Now that we have Swift test infrastructure for FirebaseFunctions after #8957, #8959 and #8960, we should be able to add integration tests. The integration tests could also potentially be used to demonstrate the Functions Codable API for the API proposal. I rebased the codable-refactor branch with #8853 on the latest master and pushed it in codable-refactor2. This PR could rebase to codable-refactor2 and change its merge target to that branch and then add the tests to https://github.com/firebase/firebase-ios-sdk/tree/master/FirebaseFunctions/Tests/SwiftIntegration |
I am trying to understand why we need those arguments. Are they provided to let the compiler infer the types correctly? |
Exactly - so that's the way to say: this callable always takes |
It looks like the
or:
|
The encoder and decoder are indeed decoupled from the Encodable and Decodable types. That's a big part of the design of the Codable system. |
Excellent, let me know if you need me to do something in relation to this PRs. |
No immediate need. I can manage them after the PR merges. However, if you do additional changes in this branch, it would be good to pull in #8983 for CI. |
#8981 is now merged and this PR should be similarly updated. |
I have a question regarding the following API:
The |
We generally try to throw for API input validations and raise error callbacks for network errors. In this case, though, I think we should remove the |
I just requested an approval for this API change. Currently, this is scheduled for Dec 6 (sorry for the long waiting time). The API in the approval is as follows:
We can update the proposal until the 6th. |
Hi @schmidt-sebastian , I agree with your suggestion to bake in both the So the usage point for defining the callable using the above API would be require the type of the
Do you like that better than:
I guess there are pros and cons, but I would love to hear your reasoning about them. For myself, I can think of the following pros and cons:
Cons:
I think the discoverability of the new API is better when the types are given explicitly as arguments. With those things said, good documentation and examples can get you a long way. :-) Looking forward to hearing the conclusions of the review. |
I talked to @peterfriese about this in the API proposal and we both prefer the shorter version, but I agree that it comes at the cost of discoverability. Let me explicitly highlight this as we go through the approval process. |
I can recommend just trying out both versions in Xcode. |
Thanks @mortenbekditlevsen for the PR! Catching up on this thread now, but wanted to check in on one thing related to the custom encoder/decoder. I can't remember the reason for needing a custom encoder/decoder vs using the built in |
Sure, the Note that I think that Paul and I discussed an attempt many years back to make the official In the Firestore pr (#8858) there are a few extra features added to the Optimally the very limited set of changes from the |
@mortenbekditlevsen thanks for the details, that's super helpful! I see the small changes now and understand the issue (and saw your posts on the Swift forums). It would be nice to just use the JSONEncoder/Decoder but I think since we aren't making massive changes to it, the fork makes sense to avoid the extra CPU cycles wasted (and potential data loss for Firestore). Sorry again for the long delay in things but I'm still catching up on it and hope to be able to give it a full review within the next week! |
Hey @mortenbekditlevsen - wanted to give you an idea as to what I am looking into and maybe you have some thoughts here. Thinking of the higher level API and the decoder for RTDB and Functions (haven't re-evaluated Firestore yet so these comments don't apply):
a) If they are necessary, should we have the b) If they're not necessary, we could remove the parameter and just leave it as an implementation detail. My hunch: we may want some sort of customization, but it could be for specialized use cases. If that's the case, maybe we could remove the parameter and evaluate re-introducing it once we hear some reasonable and valid use cases. |
Hi @ryanwilson , Which encoding is better for the other two services? And do you even really want to enforce dates to always be encoded as the timestamp type in Firestore? Are The use case is that these encodings are (at least in my eyes) purely a matter of preference, style and taste. If your functions are written in typescript you may like milliseconds since epoch. If your functions are written in rust and you use 'serde' for serialization it appears that iso8601 strings are the default. Similarly your preferences may differ for RTDB and Firestore based on commonality between client languages or frameworks or may be dictated by a dominating language or by precedence or by the whims of a platforms architect. The I think that my best argument for keeping the strategies that are already proposed by That said, I like the hiding away of That's a big part of my motivation for suggesting the use of the same encoder across the services: I am lacking flexibility with the current FirestoreEncoder. 😊 |
Rebased to codable-refactor3(which is the shared Codable from #8853 rebased on current master) |
I'm going to merge to enable setting up a full review on the codable-refactor3 branch |
A possible implementation of #8528
Builds on top of a previous PR #8853 , so that should be merged before this one.
Still needs testing and verification that it actually works.