Blog

Swift Tip: Sharing Code between Backend and Frontend

Over at Swift Talk, we’ve been busy building a new Swift Talk client app in SwiftUI. Because our backend is already written in Swift, we can now share a bunch of code between the client and server.

As a first step, we extracted our Tiny Networking library into its own Github project. It’s a Swift package, and with Xcode 11, it’s now even easier to use across projects.

Then, we went for the low hanging fruit: sharing view helper functions. This gives us a consistent output between our backend and client apps. For example, we share custom formatters to display an episode’s duration, and custom date formatters.

Finally, one of the most interesting cases is sharing the JSON models we use for the API. The backend provides a JSON list of episodes and collections, and we generate that using the Codable infrastructure. To keep things flexible, we have the following setup:

In our backend, our model struct for an episode is called Episode. Rather than directly rendering this to JSON, we created a struct EpisodeView. An EpisodeView is so called because we use it as a (JSON) view on the original data. In our backend, we can then populate it from an episode:

extension EpisodeView {
    init(_ e: Episode) {
        self = EpisodeView(
            id: e.id.rawValue,
            number: e.number,
            title: e.title,
            synopsis: e.synopsis,
            url: Route.episode(e.id, .view(playPosition: nil)).url,
            small_poster_url: e.posterURL(width: 590, height: 270),
            // ...
        )
    }
}

Separating the two types allows us to change the original Episode struct, while maintaining the same API. Likewise, our Episode struct shouldn’t know about URLs for the episode itself, those are added when we create the view.

In our shared code, we also expose a JSON encoder and decoder. By putting those into the shared library, it’s much easier to keep them in sync. For example, we need to ensure that we encode and decode our dates using the same strategy. In our server, we use the shared encoder, and in our client, we use the shared decoder.

In the future, it would be nice to also share a typed specification of routes between the server and the client, in a manner similar to Haskell’s servant library.

To follow our experiments with SwiftUI, subscribe to Swift Talk.


  • See the Swift Talk Collection

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts