Reputation: 77596
I have a firebase function that returns an object including a timestamp
[{
startTime: firestore.Timestamp.fromDate(randomDate),
duration: 45
}]
In swift I have a model representing this data
struct AvailabilityTimeSlot: Codable {
let startTime: Date
let int: Duration
}
Followed by the code calling the function and decoding it
func fetchTimeSlotAvailability(date: Date, groomerId: String, requestedServices: [Pet: [PetServiceAndPricing]]) async throws -> [AvailabilityTimeSlot] {
let result = try await Functions.functions().httpsCallable("availableBookingTimeSlots")
.call([
"date": date.timeIntervalSince1970,
"groomerId": groomerId,
"requestedServices": requestedServices
])
return try Firestore.Decoder().decode([AvailabilityTimeSlot].self, from: result.data)
}
The returning data looks like
[{
duration = 45;
startTime = {
"_nanoseconds" = 341000000;
"_seconds" = 1673116451;
};]
But I'm getting decoding error
keyNotFound(TimestampKeys(stringValue: "seconds", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "startTime", intValue: nil)], debugDescription: "No value associated with key TimestampKeys(stringValue: \"seconds\", intValue: nil) (\"seconds\").", underlyingError: nil))
What's the recommended way of receiving dates from firebase functions? Timestamps have been working as expected when using FireStore for reading data, but not for functions
Upvotes: 0
Views: 331
Reputation: 1
That works for me in Swift
struct YourName: Codable {
var date: Timestamp?
... anotherValues
enum CodingKeys: String, CodingKey {
case date
... anotherValues
}
enum TimestampKeys: String, CodingKey {
case seconds
case nanoseconds
case _seconds
case _nanoseconds
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let timestampContainer = try? container.nestedContainer(keyedBy: TimestampKeys.self, forKey: .date),
let seconds = (try? timestampContainer.decodeIfPresent(Int.self, forKey: .seconds)) ?? (try? timestampContainer.decodeIfPresent(Int.self, forKey: ._seconds)),
let nanoseconds = (try? timestampContainer.decodeIfPresent(Int.self, forKey: .nanoseconds)) ?? (try? timestampContainer.decodeIfPresent(Int.self, forKey: ._nanoseconds)) {
date = Timestamp(seconds: Int64(seconds), nanoseconds: Int32(nanoseconds))
} else {
date = try container.decodeIfPresent(Timestamp.self, forKey: .date)
}
device = try container.decodeIfPresent(String.self, forKey: .device)
}
}
Upvotes: 0
Reputation: 317427
Since callable type functions always return JSON that's serialized automatically from the data you provide, you might want to make a decision about how you want to serialize the timestamp's data in a way that's compatible with JSON. By default, the function is just going to dump the internal representation of any found object to the client, as you can see:
{
"_nanoseconds" = 341000000;
"_seconds" = 1673116451;
}
Those are the internal fields of the Timestamp object. Note that the keys are prefixed with an underscore - this is part of the timestamp's implementation details that you are getting by default.
If you want your frontend code to reach into those dumped timestamp implementation details, that's up to you to decide. You could even reconstitute a new Timestamp in your app using those values. Or you can be intentional about writing code to send exactly the values you want (which will be converted to JSON) from the timestamp you have in the function, and make sure your app code is prepared to receive that data and convert it to whatever you need.
See also:
Upvotes: 1