<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Morten Bek Ditlevsen on Medium]]></title>
        <description><![CDATA[Stories by Morten Bek Ditlevsen on Medium]]></description>
        <link>https://medium.com/@bek_29339?source=rss-8598b8818305------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*sdjDH2cbnD-B4JHRqN_1_g.jpeg</url>
            <title>Stories by Morten Bek Ditlevsen on Medium</title>
            <link>https://medium.com/@bek_29339?source=rss-8598b8818305------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 24 Apr 2026 05:22:52 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bek_29339/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Swifty Firebase APIs @ Ka-ching — part 4]]></title>
            <link>https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-4-1ec12f2be4dc?source=rss-8598b8818305------2</link>
            <guid isPermaLink="false">https://medium.com/p/1ec12f2be4dc</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[firebaserealtimedatabase]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Morten Bek Ditlevsen]]></dc:creator>
            <pubDate>Sun, 14 Oct 2018 08:05:30 GMT</pubDate>
            <atom:updated>2018-10-15T07:08:41.630Z</atom:updated>
            <content:encoded><![CDATA[<h3>Swifty Firebase APIs @ Ka-ching — part 4</h3><h3>Automatic Code Generation and Open Sourcing</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/832/1*5KjF5KRSxsTDXZZXWSmqsQ.png" /></figure><p>This post is part 4 of a series where we explore building Swift extensions to the Firebase API.</p><p>So far we have talked about <a href="https://medium.com/@bek_29339/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459">adding </a><a href="https://medium.com/@bek_29339/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459">Codable support</a> for the Firebase Realtime Database APIs, <a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-2-f337b579d86a">adding type-safe paths </a>that define a schema of your database structure and <a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-3-e91e865bb4be">adding RxSwift extensions</a> to the API.</p><p>In this post we have tried wrapping up all of the currently discussed topics into two very light weight frameworks, that can easily be included into your own project. This provides hazzle-free Codable support, type safe paths and RxSwift extensions — and you can pick and choose the features you wish to use.</p><p>But before we start talking about the open sourced frameworks, let’s look at a topic that can make our lives a bit easier:</p><h4>Automatic Code Generation</h4><p>In the article about type-safe paths, we described a strategy for modelling a hierarchy using constrained extensions of the Path type. These extensions require typing quite a bit of boilerplate.</p><p>Tools like <a href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a> and <a href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> have become popular for a some very good reasons:</p><ul><li>Boilerplate is boring and error prone to maintain.</li><li>Code that is automatically generated from some form of assets will stay up-to-date, so if you remove or rename an asset, you will immediately get a compile error if your code still refers to these assets.</li></ul><p>So instead of having to type and maintain a huge list of phantom types and constrained Path extensions, why not just define your schema and let the code be auto-generated?</p><p>Consider the following example schema:</p><pre>{<br>  &quot;configuration&quot;: &quot;Configuration&quot;,<br>  &quot;chatrooms&quot; : {<br>    &quot;&lt;chatroomId&gt;&quot;: {<br>      &quot;messages&quot;: {<br>        &quot;&lt;messageId&gt;&quot;: &quot;Message&quot;<br>      },<br>      &quot;name&quot;: &quot;String&quot;<br>    }<br>  }<br>}</pre><p>This will define Paths from the root of the structure and down to the leaf nodes which must correspond to names of model types in your code.</p><p>A json key that is wrapped in angle brackets means that the data at this point in the tree is part of a collection.</p><p>As you will notice, there is no entity defining a chatroom. For the sake of the above schema there is no model type corresponding to a chatroom, but rather you need to create a path to a chatroom in order to get to the messages of the chatroom.</p><p>This concept is modelled using phantom types. The code generator will generate an enum named Chatroom with no values. This means that the Chatroom can never be instantiated, but it can still be used as a generic restriction in our code.</p><p>With the code generated from the schema above, you can generate paths like:</p><pre>let messagesPath = Path().chatrooms.child(&quot;firechat&quot;).messages</pre><p>Or you can use the auto generated convenience method that wraps the .child(_ key: String) method as follows:</p><pre>let messagesPath = Path().chatroom(&quot;firechat&quot;).messages</pre><p>The type of the messagesPath variable is Path&lt;Message&gt;.Collection. In other words, a path to a collection of messages.</p><p>The full code generated from the above json is provided here as an example:</p><pre>import FireSwift_Database<br><br>enum Chatroom {}<br><br>extension Path where Element == Root {<br>    var configuration: Path&lt;Configuration&gt; {<br>        return Path.append(self, &quot;configuration&quot;)<br>    }<br><br>    var chatrooms: Path&lt;Chatroom&gt;.Collection {<br>        return Path.append(self, &quot;chatrooms&quot;)<br>    }<br><br>    // Convenience<br>    func chatroom(_ key: String) -&gt; Path&lt;Chatroom&gt; {<br>        return chatrooms.child(key)<br>    }<br>}<br><br>extension Path where Element == Chatroom {<br>    var messages: Path&lt;Message&gt;.Collection {<br>        return Path.append(self, &quot;messages&quot;)<br>    }<br><br>    // Convenience<br>    func message(_ key: String) -&gt; Path&lt;Message&gt; {<br>        return messages.child(key)<br>    }<br><br>    var name: Path&lt;String&gt; {<br>        return Path.append(self, &quot;name&quot;)<br>    }<br>}</pre><p>The Swift script that generates the Path extensions is called GeneratePaths.swift . I don’t think that it is very interesting to explore exactly what it does — but overall the strategy is:</p><ul><li>The JSON structure is modelled using a single recursive type: Tree that can either represent a ‘leaf’ node (the concrete model types like Configuration, Message and String in the example) or ‘branch’ node (represented by the generated phantom types in the output — like Chatroom in the example).</li><li>In the decoding, some restructuring occurs after child nodes have been processed, since only after parsing the parent nodes can we tell whether or not the child nodes are part of a collection or not.</li><li>After parsing, an enum is output for every phantom type — and an extension of Path is output for every phantom type. Each extension contains members to access child nodes of the generated tree.</li></ul><h4>Future directions for automatic code generation</h4><p>The current strategy is very basic and you could quickly run into issues that the current version of the script cannot account for:</p><ul><li>Names of generated phantom types could clash with existing type names in your code. This could potentially be resolved by supplying a prefix or a postfix for the generated phantom types when you call the script.</li><li>Names of generated phantom types could clash with each other — if you use the same names for separate path elements in your structure. This could potentially be solved in the future by allowing you to describe desired generated type names along with the tree structure in the JSON file. We just need to think of a good way to describe this. (Suggestions are very welcome).</li><li>Currently you cannot model collections of collections (ie. two nested &lt;id&gt; elements). The only current workaround is to model any such parts of the database hierarchy by hand.</li></ul><p>Suggestions for improvements — and suggestions for how to solve the annotation issues in the JSON format are very welcome.</p><h4>The open sourced frameworks</h4><p>The concepts discussed in the previous blog posts have been split into two frameworks:</p><ul><li>One that only depends on Firebase (<a href="https://github.com/ka-ching-as/FireSwift-Database">FireSwift-Database</a>)</li><li>Another that adds the RxSwift extensions (<a href="https://github.com/ka-ching-as/RxFireSwift-Database">RxFireSwift-Database</a>)</li></ul><p>This means that non-Rx users can still benefit from Codable support and also take advantage og the Path concepts.</p><p>RxSwift users on the other hand can just grab the other framework to get the full range of expressivity.</p><p>Both of the frameworks are built as statically linked frameworks. This is due to the fact that the Firebase framework suite is already distributed as statically linked frameworks.</p><p>One benefit from distributing the frameworks this way is that at runtime, you will not have to pay the extra cost of loading the libraries dynamically.</p><h4>Usage</h4><p>Please refer to the README.md of each framework for usage examples.</p><h4>Installation</h4><p>Currently the only installation method is through Carthage — please reach out if you are interested in CocoaPods support as well, or perhaps even support the project by creating a pull-request adding CocoaPods support! :-)</p><h4>Github</h4><p><a href="https://github.com/ka-ching-as/FireSwift-Database">ka-ching-as/FireSwift-Database</a></p><p>and</p><p><a href="https://github.com/ka-ching-as/RxFireSwift-Database">ka-ching-as/RxFireSwift-Database</a></p><h4>About the author</h4><p>My name is Morten Bek Ditlevsen, and I work for the Danish company <a href="https://ka-ching.dk">Ka-ching (website in Danish)</a>.</p><p>At Ka-ching we are building a world class Point-of-Sales system for iOS. Currently we are B2B only, but we will keep you posted once we enter the App Store. :-)</p><h4>Feedback</h4><p>If you have any questions, comments or need clarification for some of the examples, please don’t hesitate to ask!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1ec12f2be4dc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-4-1ec12f2be4dc">Swifty Firebase APIs @ Ka-ching — part 4</a> was originally published in <a href="https://medium.com/swift2go">Swift2Go</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swifty Firebase APIs @ Ka-ching - part 3]]></title>
            <link>https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-3-e91e865bb4be?source=rss-8598b8818305------2</link>
            <guid isPermaLink="false">https://medium.com/p/e91e865bb4be</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[firebaserealtimedatabase]]></category>
            <dc:creator><![CDATA[Morten Bek Ditlevsen]]></dc:creator>
            <pubDate>Wed, 22 Aug 2018 09:01:49 GMT</pubDate>
            <atom:updated>2018-10-14T05:07:46.857Z</atom:updated>
            <content:encoded><![CDATA[<h3>Swifty Firebase APIs @ Ka-ching — part 3</h3><h3>Firebase and RxSwift — a marriage made in heaven</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZfXL6r7ed-EuEZvIQxg9Zw.png" /></figure><h4>UPDATE, OCTOBER 14th, 2018:</h4><p>Since writing this article, the concepts described in these blog posts have been made into two Open Source frameworks, which can be found here:</p><ul><li><a href="https://github.com/ka-ching-as/FireSwift-Database">ka-ching-as/FireSwift-Database</a></li><li><a href="https://github.com/ka-ching-as/RxFireSwift-Database">ka-ching-as/RxFireSwift-Database</a></li></ul><p>This post is a continuation of the 3 (or 4 or 5?) part series.</p><p>In the first post, we <a href="https://medium.com/@bek_29339/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459">added Codable support</a> to the Firebase APIs:</p><p>In the second post, we added <a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-2-f337b579d86a">Type Safe paths using Phantom Types </a>which gave us strongly typed paths and excellent API ergonomics:</p><p>In this post, we are going to add support for RxSwift. If you want to learn more about RxSwift, please refer to the official <a href="https://github.com/ReactiveX/RxSwift">github repo</a>, which has excellent examples of use cases.</p><p>The only further motivation I will present here is that there is an huge overlap in the mindset of the Firebase Real-Time Database and Rx: the RTDB allows the user to <em>subscribe</em> to data as it changes over time. One of the main purposes of Rx is exactly to provide primitives to model data as it changes over time.</p><p>As I see it, Rx is the perfect way to consume the Firebase RTDB APIs. For instance, observing changes for a location in Firebase using the native APIs require the user to keep track of a subscription token that is returned when subscribing. In Rx we can wrap this token in the subscription so that the Firebase observer is removed when the subscription is disposed.</p><p>But all this is probably easier to grasp when we start coding!</p><h4>Adding an Rx extension</h4><p>Let us start by adding an Rx extension to a DatabaseQuery (which is a super type of DatabaseReference) for convenience. The pattern for adding Rx extensions can be found in the RxSwift repo — for instance in the RxCocoa extensions. It looks as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/04ec683b6e273a8e76658806e9333cb6/href">https://medium.com/media/04ec683b6e273a8e76658806e9333cb6/href</a></iframe><p>Extending Reactive with the constraint on Base means that the type DatabaseQuery gets a .rx property that can be used to call the extension functions:</p><pre>let obs: Observable&lt;DecodeResult&lt;Configuration&gt;&gt;<br>         = ref.rx.observe(eventType: .value)</pre><p>For the wrapping of a single observation we return a Single&lt;T&gt; type from RxSwift. Single represents an observable that can have at most one element. This means that it either always completes (returning that single element) or fails with an error. In that respect, a Single can be compared to a Future or a Promise¹.</p><p>For the wrapping of continuous observations we return an Observable&lt;DecodeResult&lt;T&gt;&gt; . When creating an Observable you need to return a Disposable that will be used to keep track of the life time of a subscription to an Observable. The closure passed to Disposable.create will be called when a subscription is disposed, and this provides a convenient way to remove the actual Firebase observer.</p><p>You may wonder why we use different generic types T and DecodeResult&lt;T&gt; for the Single and the Observable respectively. The reason for this has to do with the way that Observables work. For the Observable case: as soon as an observable has an error, the signal ends. This means, that if we treated errors (like network errors, missing data errors) like Observable errors, then the signal would fail upon missing network. We might not be interested in such a behavior, so instead we let our signal contain a sequence of DecodeResult&lt;T&gt; — then the user has more freedom to interpret the errors as they see fit. We will add convenience functions to ‘unwrap’ the result type below. For the case of the Single we do not have the issue of the signal terminating after the first error, because the Single always terminates after the first value. So in this case there is no reason to keep the DecodeResult wrapper.</p><h4>Extending the FirebaseService</h4><p>Let us extend our FirebaseService from the last post to add support for type safe paths:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e083eef8ad064803ebb86196e0899e4d/href">https://medium.com/media/e083eef8ad064803ebb86196e0899e4d/href</a></iframe><p>So here we replace all the observe functions to return an Observable (or a Single) instead of taking callback closures as we did in the previous post.</p><h4>Filtering DecodeResults</h4><p>If you like to live your life dangerously, or have no sound way to handle errors, you may wish to filter away the errors, or have them logged, while only actually handling the success cases where model entities are received and parsed successfully. For this purpose we could create overloads of the observe functions. But as the amount of wrapper functions could grow in the future, we could instead add a generic way of filtering Observable&lt;DecodeResult&lt;T&gt;&gt; signals.</p><p>This can be done by a constrained extension on Observable, but we cannot constrain on DecodeResult since this is itself a generic type. What we can do is create a protocol and use this to create our constrained extension:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac6d22f154175a277efca1a72d06be24/href">https://medium.com/media/ac6d22f154175a277efca1a72d06be24/href</a></iframe><p>To explain the code above: We add a protocol ResultProtocol to use for our constrained extension. Then we conform Result to this protocol. Now we can create the extension constrained to Observable types containing ResultProtocol-conforming elements.</p><p>One function, filtered(), simply throws away all error values in the Observable stream while filtered(handler:) gives you an opportunity to intercept error values — for instance for logging. If you have a Singleton’ish logging concept, you could use this to create your own small extension that filters success values and logs errors.</p><h4>Consuming the Rx’ified API</h4><p>As an example of consuming the updated API, I have created a small ViewModel — in a style inspired by <a href="https://github.com/kickstarter/ios-oss">Kickstarter´s open sourced iOS code</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a675c1b81b8addfb0fa069b9c0206f4/href">https://medium.com/media/3a675c1b81b8addfb0fa069b9c0206f4/href</a></iframe><p>Pass an instance of the ViewModel (as an anonymous ViewModelType) to your ViewController, create a few bindings, and you’re done!</p><h4>Future work</h4><p>There are more areas to explore here, so I think that I will have to write a few more posts. Ideas for future directions are:</p><ul><li>Adding higher level abstractions to our API (improved observation of collections of objects)</li><li>Auto-generating boilerplate for our Path modelling of the firebase database hierarchy.</li><li>Creating similar wrappers for Firestore, so that migration in the client will be as easy as swapping out the concrete implementation.</li><li>Caveats when using Firebase Real-time database. There are quite a few. Caveats using RxSwift — and caveats using Codable (especially using key coding and decoding)</li><li>Applying <a href="https://www.pointfree.co/episodes/ep12-tagged">Tagged Pointers</a> instead of the current String based keys in the API.</li></ul><p>Let me know what you would like to hear!</p><h4>Github</h4><p>As always, the sample code can be found on <a href="https://github.com/ka-ching-as/SwiftyFirebase/tree/rxswift">github — on a branch named </a><a href="https://github.com/ka-ching-as/SwiftyFirebase/tree/rxswift">rxswift</a>.</p><h4>About the author</h4><p>My name is Morten Bek Ditlevsen, and I work for the Danish company <a href="https://ka-ching.dk">Ka-ching (website in Danish)</a>.</p><p>At Ka-ching we are building a world class Point-of-Sales system for iOS. Currently we are B2B only, but we will keep you posted once we enter the App Store. :-)</p><h4>Feedback</h4><p>If you have any questions, comments or need clarification for some of the examples, please don’t hesitate to ask!</p><h4>Foot notes</h4><ol><li>with the noticable exception that Singles do NOT cache their result, and thus may be triggered multiple times if multiple places in the code subscribe to the result.</li></ol><figure><a href="http://bit.ly/2KkkwGL"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5-oC2BqqizoRxIls08WMmA.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e91e865bb4be" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-3-e91e865bb4be">Swifty Firebase APIs @ Ka-ching - part 3</a> was originally published in <a href="https://medium.com/swift2go">Swift2Go</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swifty Firebase APIs @ Ka-ching - part 2]]></title>
            <link>https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-2-f337b579d86a?source=rss-8598b8818305------2</link>
            <guid isPermaLink="false">https://medium.com/p/f337b579d86a</guid>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[firebaserealtimedatabase]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Morten Bek Ditlevsen]]></dc:creator>
            <pubDate>Thu, 09 Aug 2018 08:50:36 GMT</pubDate>
            <atom:updated>2018-10-14T05:07:30.353Z</atom:updated>
            <content:encoded><![CDATA[<h3>Swifty Firebase APIs @ Ka-ching — part 2</h3><h3>Type-safe paths using Phantom Types</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eRNTvkVtGIG2B1L62WQXNA.png" /></figure><h4>UPDATE, OCTOBER 14th, 2018:</h4><p>Since writing this article, the concepts described in these blog posts have been made into two Open Source frameworks, which can be found here:</p><ul><li><a href="https://github.com/ka-ching-as/FireSwift-Database">ka-ching-as/FireSwift-Database</a></li><li><a href="https://github.com/ka-ching-as/RxFireSwift-Database">ka-ching-as/RxFireSwift-Database</a></li></ul><p>This post is a continuation of the 3 part series, that started with <a href="https://medium.com/@bek_29339/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459">adding Codable support</a> to the Firebase APIs:</p><p>In this post we will cover a very interesting and powerful subject which is hugely inspired by the objc.io <a href="https://talk.objc.io/episodes/S01E71-type-safe-file-paths-with-phantom-types">Swift Talk #71: Type-Safe File Paths with Phantom Types</a>.</p><p>In the Swift Talk, Brandon Kase and Florian Kugler discuss `Phantom Types` which in short are types that are never instantiated, but only ever used as generic constraints. These can be a really powerful tool for adding strong typing to APIs that are usually not strongly typed — just like the paths used in Firebase RTDB References.</p><p>Please, please go and watch the awesome talk on objc.io!</p><p>In this post we are going to mix Phantom Types with actual Codable model types to create a really powerful API.</p><p>Sample code for this post can be found on the typesafe_paths branch of the github repo introduced in the first blog post:</p><p><a href="https://github.com/ka-ching-as/SwiftyFirebase/tree/typesafe_paths">ka-ching-as/SwiftyFirebase</a></p><p>Note that this post deals with Firebase, but the techniques described can be used for any kind of API where you have a ‘stringly’ defined hierarchy of data.</p><h3>A simple Path type</h3><p>We are going to introduce a Path type that basically wraps an Array of path components, but adds type safety in the process.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f14bcca353c282bb387c41560363db1/href">https://medium.com/media/8f14bcca353c282bb387c41560363db1/href</a></iframe><p>As you can see, the Path is generic over some Element.</p><p>It carries an array of Strings representing the path components.</p><p>It has an append function that takes a variable number of strings (just for convenience, so that it can be called with one or multiple path components).</p><p>append is made fileprivate so only code in this file can append path components. Similarly, the init is fileprivate too, so by default it cannot be instantiated from the outside.</p><p>The only public member is rendered which returns the joined path components.</p><p>The fun part begins when we start adding constrained extensions to Path.</p><h3>Constrained extensions</h3><p>First of all we need to provide a way to initialize a Path to the outside world — since the only current init is fileprivate.</p><p>This will be the first example of a Phantom Type.</p><p>We simply create an empty enum called Root. Now we can extend the Path type constrained to the Root type as follows:</p><pre>enum Root {}</pre><pre>extension Path where Element == Root {<br>  init() {<br>    self.init([])<br>  }<br>}</pre><p>This means that we can only ever create fresh instances of the Path type if they are paths of type Root. Swift&#39;s type inference even helps us, so if we type:</p><pre>let root = Path()</pre><p>The type of root is now Path&lt;Root&gt;.</p><p>But this alone does not do us a whole lot of good, so let’s expand our example a bit:</p><p>Imagine a Firebase Real-time Database with a tree structure like this:</p><pre>/<br>  chatrooms<br>    &lt;chatroom key&gt;<br>      name<br>        &lt;chatroom name&gt;<br>      messages<br>        &lt;message key&gt;<br>          &lt;message&gt;<br>  configuration<br>    &lt;some configuration entity&gt;</pre><p>Hopefully you can follow my arbitrary structure annotation:</p><p>At the root level we have a chatrooms path and a configuration path. Under chatrooms we have a number of keys of individual chat rooms. For each individual chat room we have a name and a messages path. Name could just be a String and under messages we have a number of keys — and for each of these keys we have some Message entity. The configuration path at the root contains some Configuration entity.</p><p>With the above structure in mind, now we can create yet another constrained extension on Root paths that lets us access all the children in the root of our tree:</p><pre>enum Root {}<br>enum ChatRooms {}</pre><pre>struct Configuration: Codable { <br>  // Our actual Configuration entity<br>  var welcomeMessage: String<br>}</pre><pre>extension Path where Element == Root {<br>  init() {<br>    self.init([])<br>  }<br>}</pre><pre>extension Path where Element == Root {<br>  var chatrooms: Path&lt;ChatRooms&gt; {<br>    return append(&quot;chatrooms&quot;)<br>  }</pre><pre>  var configuration: Path&lt;Configuration&gt; {<br>    return append(&quot;configuration&quot;)<br>  }<br>}</pre><p>Now it’s starting to look like something! So we added another Phantom Type (the ChatRooms enum) — and a Configuration entity — just added here as an example.</p><p>The new constrained extension provides us with two sub-paths. One ‘pointing’ to our accounts and another to the configuration. On the call site these can be used like:</p><pre>let chatRoomsPath = Path().chatRooms<br>let configurationPath = Path().configuration</pre><p>The type of chatRoomsPath is now Path&lt;ChatRooms&gt; and configurationPath is Path&lt;Configuration&gt;.</p><p>You can imagine building an entire tree of paths like this, but we are <em>still</em> only getting started! :-)</p><h3>Using the Path type</h3><p>For now, the only thing we can do is create paths and render them.</p><p>This can of course be used in conjunction with a Reference in order to provide a String path. But we can do better.</p><p>At this point I would like to introduce an alterior motive with the wrapping of the Firebase RTDB APIs:</p><p>As we are building up more and more general concepts, we are also abstracting away from the actual Firebase APIs. This means that we are basically able to hide away the Firebase APIs and only use our own wrapper. This is extremely handy when it comes to testing: The tests do not need to know anything about Firebase — only our wrapped APIs. You can also imagine replacing the Firebase RTDB with something else entirely. For instance you could possibly transition to FireStore using the exact same wrapped API.</p><p>Let’s define a type to handle all Firebase RTDB observations — later on we can add a protocol defining the API for this for easy test mocking.</p><pre>class FirebaseService {<br>  private let rootRef: DatabaseReference</pre><pre>  init(ref: DatabaseReference) {<br>    // Ensure that rootRef is always pointing to the root      <br>    rootRef = ref.root<br>  }<br>}</pre><p>Now we can begin to take advantage of our Path type. Let us wrap the extensions to DatabaseReference and DatabaseQuery that we defined in the previous post — and spice it up using our Path type:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f9da6ee42aedf644b1fd39c741a0281c/href">https://medium.com/media/f9da6ee42aedf644b1fd39c741a0281c/href</a></iframe><p>In the three functions we just call the extensions that we already provided in the previous post.</p><p>But more importantly we call them on a rendered Path and we <em>connect</em> the generic types from the Path to the generic parameter of the extension functions.</p><p>This is very powerful, because now we can only call setValue with Encodable types for paths that actually point to such a type.</p><p>This is probably easier to illustrate with an example:</p><pre>let s = FirebaseService(...)<br>let config = Configuration(welcomeMessage: &quot;Hello, World!&quot;)</pre><pre>try s.setValue(at: Path().chatRooms, value: config) // Fails<br>try s.setValue(at: Path().configuration, value: config) // Succeeds</pre><p>In the first example, the compiler will let us know that ChatRooms is not Encodable, so it can’t be used. And the second example works as intended. Perfect!</p><p>Let us write out the full ‘chat rooms’ hierarchy as constrained extensions on Path to see more examples:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ab44041f611e8967db616dc36e8f5fa7/href">https://medium.com/media/ab44041f611e8967db616dc36e8f5fa7/href</a></iframe><p>Now we can get a path to a Message:</p><pre>let messagePath = Path().chatRooms.chatRoom(&quot;firechat&quot;).messages.message(&quot;first_post&quot;)</pre><p>This is still a bit verbose, but we will enhance the ergonomics later on in this post.</p><p>Now that we have a path to another Encodable type let us try setting the Configuration entity on this path:</p><pre>try s.setValue(at: messagePath, value: config) // Fails</pre><p>This correctly fails — and the error message even gives a hint at what is wrong:</p><blockquote>Cannot invoke ‘setValue’ with an argument list of type ‘(at: Path&lt;Message&gt;, value: Configuration)’</blockquote><p>So the compiler directly tells you that you are providing a path to a Message but a value of type Configuration. This makes it easy to spot the error in the code.</p><p>As you may begin to see, this is indeed very powerful. The hierachy of Path types now defines a type safe ‘schema’ the tells the compiler where you may write different kinds of model objects in the database!</p><p>The observe function also improves greatly from being bound to the types of a path:</p><pre>let path = Path().configuration<br>s.observeSingleEvent(of: .value, at: path) { result in<br>  // result is now inferred to be of type:<br>  // Result&lt;Configuration, DecodeError&gt;</pre><pre>}</pre><p>This is another huge improvement to the API.</p><p>Again the Path hierarchy tells us what kind of data can reside at a specific path, so the compiler will try to decode that specific type — like the Configuration type above.</p><p>Again we will get an error if we try to call the function with a path to a type that is not Decodable.</p><h3>Paths to collections of model entities</h3><p>The example above highlights an issue with our API:</p><p>We still have to send the DataEventType to our API — and actually the specified event type contains some semantics about the use.</p><p>For instance the .value type returns data at a specific path while .childAdded returns data from child nodes of the path. This means that if we use a .childAdded type on a path to a Message, then we will not get called with actual message data, but rather when data below a message is added.</p><p>Wouldn’t it be awesome if we could model that some paths referred to collections of entities and others to the specific entity itself?</p><p>At Ka-ching we have tried a few ways of modelling this, but far the easiest way is to basically duplicate our Path type. We will name the copy Collection and nest it inside the Path type in order to avoid clashing with the standard library Collection type.</p><p>This means that a path to a collection of messages will be typed: Path&lt;Message&gt;.Collection.</p><p>That is quite a nice representation, don’t you think?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/98cc4c37fbb7c48d23bfd1fd04fa709d/href">https://medium.com/media/98cc4c37fbb7c48d23bfd1fd04fa709d/href</a></iframe><p>So the Path.Collection type differs from Path in that it has a child() function that given a String key always returns a Path to a specific instance of it’s own generic type.</p><p>The Path type is extended with a fileprivate version of append that can return paths to collections.</p><p>With this addition we can do a lot of new things. First of all our Path hierarchy becomes a lot smaller since we do not have to explicitly model the ChatRooms and Messages collections — they are now available ‘for free’:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ff57908600dc0bdc45b7e4440dff4373/href">https://medium.com/media/ff57908600dc0bdc45b7e4440dff4373/href</a></iframe><p>Instead we have just specified that var chatrooms is a Path&lt;ChatRoom&gt;.Collection.</p><p>A path to a Message can now be expressed as:</p><pre>let path = Path().chatrooms.child(&quot;firechat&quot;).messages.child(&quot;first_post&quot;)</pre><p>You could even add helper extensions that lets you ‘jump’ directly into an entity in a collection and skip the .child() step:</p><pre>extension Path where Element == ChatRoom {<br>  var messages: Path&lt;Message&gt;.Collection {<br>    return append(&quot;messages&quot;)<br>  }</pre><pre>  // Convenience function:<br>  func message(_ key: String): Path&lt;Message&gt; {<br>    return messages.child(key)<br>  }<br>}</pre><p>In this way the path can be built like this:</p><pre>let path = Path().chatroom(&quot;firechat&quot;).message(&quot;first_post&quot;)</pre><p>Simple and to the point!</p><h3>Taking advantage of our collection paths</h3><p>Now we can extend our FirebaseService in a number of ways. First let us get rid of the DataEventType parameter in our existing observer functions. It doesn’t make sense to call them with child added/changed/removed.</p><p>Instead we will also create new overloads for observing on collection paths where these event types still make sense.</p><p>Finally we will also add an addValue that may only be used on collections.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e851562543be95b99e8c8aa9aa354b5c/href">https://medium.com/media/e851562543be95b99e8c8aa9aa354b5c/href</a></iframe><p>The changes are quite few:</p><p>We removed the DataEventTypefrom the Path observations and created new Path.Collection observations for use with only the .childAdded/.childChanged/.childRemovedevent types.</p><p>The addValue allows the adding entities to collections as follows:</p><pre>let message = Message(...)<br>let path = Path().chatroom(&quot;firechat&quot;).messages<br>try s.addValue(at: path, value: message)</pre><h3>Conclusion</h3><p>Adding the quite simple Path type and a small service class allows you to build a hierarchy which becomes a type safe definition of the structure of your database.</p><p>With this hierachy in place you make the compiler ensure that you can’t accidentally place data in locations that are not intended. And when observing, the type of data that is being parsed is inferred by the compiler. This reduces boilerplate and is yet another safe-guard with respect to parsing the data from the database into the correct type.</p><p>We are so thrilled to get rid of any stringly typed data in our code base, so thank you very much objc.io for the great inspiration for using Phantom Types! :-)</p><h3>Future enhancements</h3><p>It would be nice to have a function that could observe an entire collection of entities.</p><p>This can be done in a few different ways: We could just add another observe overload that returned [String: T] results using the .value event type. This will, however cause the entire collection to be re-downloaded and parsed every time a single entity changes in the database. Still, it could be useful when you know that you have small collections. The dangers of using this should be communicated in the API name.</p><p>Another way would be for the observe function to keep track of a [String: T] dictionary, observing both .childAdded, .childChanged and .childRemoved and then calling the handler with the new Dictionary each time a child is manipulated. This is a bit better than the above, but we are also moving towards some higher level logic that is further away from the existing Firebase APIs. We will have a look at this in the next blog post about wrapping all this up using RxSwift!</p><p>Another thing that becomes apparent when you are modelling your Path hierachy is how much this looks like an actual schema defined by some piece of data. Wouldn’t it be awesome if we could generate this boilerplate code based on a JSON representation of the Firebase RTDB hierarchy? I think we need to explore this in a fourth post in this three-part series. :-)</p><h3>Who are we</h3><p>My name is Morten Bek Ditlevsen, and I work for the Danish company <a href="https://ka-ching.dk">Ka-ching (website in Danish)</a>.</p><p>At Ka-ching we are building a world class Point-of-Sales system for iOS. Currently we are B2B only, but we will keep you posted once we enter the App Store. :-)</p><figure><a href="http://bit.ly/2KkkwGL"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5-oC2BqqizoRxIls08WMmA.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f337b579d86a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-2-f337b579d86a">Swifty Firebase APIs @ Ka-ching - part 2</a> was originally published in <a href="https://medium.com/swift2go">Swift2Go</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swifty Firebase APIs @ Ka-ching - part 1]]></title>
            <link>https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459?source=rss-8598b8818305------2</link>
            <guid isPermaLink="false">https://medium.com/p/c7f2e6fb9459</guid>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[firebaserealtimedatabase]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Morten Bek Ditlevsen]]></dc:creator>
            <pubDate>Thu, 26 Jul 2018 13:07:55 GMT</pubDate>
            <atom:updated>2018-10-14T05:07:17.407Z</atom:updated>
            <content:encoded><![CDATA[<h3>Swifty Firebase APIs @ Ka-ching — part 1</h3><h3>Adding support for Codable types</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eRNTvkVtGIG2B1L62WQXNA.png" /></figure><h4>UPDATE, OCTOBER 14th, 2018:</h4><p>Since writing this article, the concepts described in these blog posts have been made into two Open Source frameworks, which can be found here:</p><ul><li><a href="https://github.com/ka-ching-as/FireSwift-Database">ka-ching-as/FireSwift-Database</a></li><li><a href="https://github.com/ka-ching-as/RxFireSwift-Database">ka-ching-as/RxFireSwift-Database</a></li></ul><h3>Background</h3><p>The <a href="https://firebase.google.com/products/realtime-database/">Firebase Realtime Database</a> is an excellent tool for building apps. There are plenty of articles covering some of the advantages of using Firebase, so this post will not go into details about that, but instead assume that you have some prior knowledge of the technology.</p><p>The iOS APIs for Firebase are currently written in Objective-C, and although the APIs present themselves nicely in Swift, this does mean that we cannot take advantage of Swift-only features like Codable support out-of-the-box.</p><p>This post (and the following few) will explore the possibility of adding nice and ‘Swifty’ extensions to the Realtime Database API.</p><h3>Overview</h3><p>Here is an overview of what the posts will cover:</p><ol><li>(This post) Adding support for Codable types.</li><li><a href="https://medium.com/@bek_29339/swifty-firebase-apis-ka-ching-part-2-f337b579d86a">Adding type-safe paths to data in your database</a></li><li>(Yet to come) Adding RxSwift extensions to provide data as Observables</li></ol><h3>Motivation</h3><p>The motivation for this first post is to allow you to consider the data stored in the Realtime Database as model objects instead of as pure data.</p><p>For the second post we will get rid of the error prone use of String paths to data.</p><p>The third post is motivated by the fact that there is a pretty big overlap in how the world is perceived through Rx glasses and how the Realtime Database APIs work. Namely the fact that data is in both concepts percieved as values that change over time. Let us take advantage of this by combining the concepts.</p><h3>TL;DR</h3><p>The goal of this post is to be able to use Codable model types with the Firebase Realtime Database APIs like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a14448df76b4c9e3cb58945a22c678b4/href">https://medium.com/media/a14448df76b4c9e3cb58945a22c678b4/href</a></iframe><h3>Codable</h3><p>Many other articles explain Swift’s Codable in greater detail. Suffice it to say here, that annotating your model types with Codable conformance provides an elegant and convenient way of allowing your types to be serialized into various formats.</p><p>One of these very common formats is naturally JSON. Support for decoding from and encoding to JSON is provided through the types JSONDecoder and JSONEncoder respectively.</p><p>Unfortunately, these two types consume and create JSON in the format of Data instances containing the String representations of the JSON — while the Firebase RTDB APIs create and consume JSON ‘structures’. Basically this means nested values of type Dictionary, Array and ‘primitive’ types like strings, numbers and booleans.</p><p>This means that there is a gap between the two APIs. One way of bridging this gap would be to take the Data output from JSONEncoder and deserializing it into a structure using the JSONSerialization API. But this doesn’t feel quite right since it basically needs you to do extra work.</p><p>Fortunately, Swift is Open Source, and the current implementation of JSONEncoder and JSONDecoder almost already does what we want.</p><p>So here is a small recipe for making your own Firebase RTDB-compatible Encoder and Decoder pair.</p><h3>Cloning JSONEncoder.swift</h3><p>Create a new project in Xcode. Let it be a Cocoa Touch Framework.</p><p>Find the JSONEncoder.swift file in the github repo for your version of Swift. In this example we’ll go with Swift 4.1</p><ol><li>Go to the apple/swift repo and navigate to <a href="https://github.com/apple/swift/tree/swift-4.1-branch/stdlib/public/SDK/Foundation">stdlib/public/SDK/Foundation</a></li><li>Copy JSONEncoder.swift as well as Codable.swift (which contains a helper function for creating error values needed by JSONEncoder)</li><li>Rename JSONEncoder to StructureEncoder (the name is borrowed from Itai Ferber in a <a href="https://forums.swift.org/t/idea-exposing-jsonencoder-and-jsondecoder-functionality/6379">Swift forums discussion</a>)</li><li>For the encode function, replace the return type Data with Any, remove the JSONSerialization step and return topLevel directly.</li><li>Similarly, rename JSONDecoder to StructureDecoder</li><li>In the decode function, replace the input from json: Data with from structure: Any and call _decode directly on the structure instead of deserializing the json data first.</li><li>Be sure to import Foundation in both the renamed StructureEncoder.swift and Codable.swift</li><li>Remember to add attribution to the apple/swift project in your library or app.</li></ol><p>Now you have a functioning encoder / decoder pair that can be used together with the RTDB APIs!</p><h3>Add the Result type to your project</h3><p>This is of course based on your own preference, but there are good reasons for modelling the input to an asynchronous callback using a type like the popular <a href="https://github.com/antitypical/Result">Result-type implemented by antitypical</a> — instead of as a pair of optional version of your model type, and an optional Error .</p><p>This concept is explored in depth by the excellent Stephen Cellis and Brandon Williams on their <a href="https://www.pointfree.co">point free</a> episode about <a href="https://www.pointfree.co/episodes/ep4-algebraic-data-types">Algebraic Datatypes</a>.</p><h3>Improving the Realtime Database APIs</h3><p>Ok, after quite a bit of setup, we are finally ready to start extending the APIs.</p><p>Let’s start by adding a convenience to DataSnapshot to allow decoding the data into a generic type that conforms to Decodable:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/64bb3abdab22d9086902c7d0d581750b/href">https://medium.com/media/64bb3abdab22d9086902c7d0d581750b/href</a></iframe><p>We have created an error type, DecodingError to hold the exact errors that can occur while using the API.</p><p>When decoding, we create an instance of our StructureDecoder. Later we can add a way of configuring the decoder with a set of global options, but for now we are just using the defaults.</p><p>With decoded in place, we can now start overloading functions on the DatabaseReference type. But since these functions actually live on the super class DatabaseQuery, let us extend that instead:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f427849d6138e86a3cdc12b84bd0b599/href">https://medium.com/media/f427849d6138e86a3cdc12b84bd0b599/href</a></iframe><p>Encoding can be implemented as simple as:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e4166d7b90ea32a2a2532248245ea220/href">https://medium.com/media/e4166d7b90ea32a2a2532248245ea220/href</a></iframe><p>For encoding we can easily see the benefits of the typed API:</p><p><a href="https://gist.github.com/mortenbekditlevsen/cd351f36e61cd04eab3c7eaa53b0bf25">https://gist.github.com/mortenbekditlevsen/cd351f36e61cd04eab3c7eaa53b0bf25</a></p><h3>Conclusion</h3><p>With just a little groundwork, we can now use the Firebase Realtime Database APIs together with Codable types. The APIs are still a bit clunky to use since you need to supply the generic type argument inside of the callback function signature.</p><p>We will deal with this bit of clunkyness later. Until then you can imagine the observeSingleEvent returning some kind of Future type, so that the type can be inferred by the assignment — or when Swift support for async / await lands (in Swift 6, perhaps?), observeSingleEvent could be an async function used like this (assuming that async functions are also throwing):</p><pre>do {<br>  let product: Product = await ref.observeSingleEvent(of: .value)<br>} catch {<br>  // Handle error<br>}</pre><h3>Considerations</h3><p>The downside of using JSONEncoder.swift from the swift repo is that it needs to be maintained as swift evolves. There has <a href="https://forums.swift.org/t/revisiting-structureencoder-and-structuredecoder/12634">been talks</a> in the Swift forums about adding a StructureEncoder and StructureDecoder pair to Swift, but from the discussions it appears that they would not get JSON ‘semantics’, so likely no support for automatic encoding and decoding of keys to snake case and the like.</p><p>At our company we have maintained a version of the StructureEncoder.swift through 3 swift releases, and it has not been a very big deal to maintain it so far.</p><h3>Github</h3><p>We created a <a href="https://github.com/ka-ching-as/SwiftyFirebase">small repo</a> to demonstrate the changes to JSONEncoder.swift and the extensions to the Firebase API.</p><h3>Who are we</h3><p>My name is Morten Bek Ditlevsen, and I work for the Danish company <a href="https://ka-ching.dk">Ka-ching (website in Danish)</a>.</p><p>At Ka-ching we are building a world class Point-of-Sales system for iOS. Currently we are B2B only, but we will keep you posted once we enter the App Store. :-)</p><figure><a href="http://bit.ly/2KkkwGL"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5-oC2BqqizoRxIls08WMmA.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c7f2e6fb9459" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swift2go/swifty-firebase-apis-ka-ching-part-1-c7f2e6fb9459">Swifty Firebase APIs @ Ka-ching - part 1</a> was originally published in <a href="https://medium.com/swift2go">Swift2Go</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>