Firebase DataSnapshot to Swift struct
The requirement was simple — an app to track attendance. It needed to pull down names, display them, and send the selected list to an e-mail address. A straightforward project, one that I could try out some new stuff on.
I had Firebase spitting out data in a couple of hours; clear and easy. I distinctly remember thinking, at this rate, I’d have time to put fancy finishing flourishes into the design.
Inevitably, pride comes before a fall.
Despite uploading data as
JSON to Firebase, it is returned as a
DataSnapshot, an immutable dump of data wrapped in a custom type.
This is useless for direct conversion to an object using the new Swift 4
Codable interface, with its intrinsic type safety. Also, littering the codebase with references to this object couples everything to the framework.
Nasty business. There had to be a solution.
Of course, the result is always simple, and the time taken to reach it worries you, that it somehow reflects badly on you as a programmer ¹.
snapshot.value provides the data as a native type, in this case,
[[String: String]]. And, when this is combined with the custom types adhering to
We are left with
Level — lovely, usable
Codable adherents the whole way down.
All that’s left is to take the
snapshot.value, cast to its native type, encode to
JSON, and decode the
JSON to the
[User] — Success ²! 🎉 🎊 🍾
But it nags, it niggles, it irritates; is this the best it can be?
🤔 🕐 ☕️ 🕑 ☕️ 🕒 ☕️ 💡
Of course not!
By the power of generics, and extensions, this code can be reused across the app.
Behold, the freshly baked
fetch function of DatabaseReference.
Pass this the expected result type, a simple struct that holds the Firebase child path with the
snapshot.value type, and 💥 ! Clean, reusable, and helping keep the Firebase references to a minimum ³.
- It doesn’t — this stuff is hard to do properly. Anyone who says it isn’t is lying to you.
- Another resolution is to iterate over the
[[String: String]]returned from
snapshot.value, and instantiate each
Userdirectly. However, this is more code, is minimally more performant, doesn’t take advantage of the type safety of
Codableand, if needed, the
JSONDecoder()is descriptive, allowing for better debugging, and clearer error handling.
- This very simple app pulls down the whole list of users. In the interests of YAGNI, the extension does not handle more complex use cases. But it could!