Kitura and the BFF Pattern

In this article, learn what high-level issues Kitura solves with server-side Swift, and what the BFF pattern is all about! By David Okun.

Leave a rating/review
Save for later
Share

Did you know: Etymologically, the word Kitura loosely stems from the Hebrew word Keturah, which literally translates into “incense”?

What does that have to do with Kitura? Absolutely nothing! Why is Kitura’s logo a bird, and does it have anything to do with Swift’s iconic imagery? Maybe! How do you pronounce Kitura — is the “i” long or short? No one knows the empirical answer to this. The members of the Kitura team have been known to pronounce the word Kitura differently at different times of the day on the same day. I’ve personally repeatedly asked them why they do this, and typically, they just shrug, chuckle and walk away.

Joking aside, when Apple announced availability for the Linux build of Swift, IBM immediately pounced. Out of the box, there were major hurdles to overcome: The team worked to port most of Swift’s core APIs, like Dispatch, to compile and pass tests on Linux. In addition to this, the team visualized a module for running a RESTful server using Swift. That module is now known as Kitura.

This article aims to give you a quick overview of server-side Swift using Kitura, how the Backend-for-Frontend (BFF) pattern works, and some of the high-level problems that Kitura solves.

Why Swift on the Server?

The core argument in favor of writing Swift for your server is to share code and knowledge between the front-end and the back-end of your app. And if you’re a team of one, this streamlining is arguably even more crucial and empowering. This includes, but is not limited to, your model object code.

Given that the team who wrote Kitura came from the Node.js ecosystem, there was a conscious desire to model Kitura after Express.js, which is arguably the most popular Node.js framework for running a RESTful server. There are many facets of Express to discuss, but the router is one of the most important ones.

Think of a router as a module that routes requests to the appropriate place. Here is an example of a route in Express.js:

app.get("/testing", (req, res) => {
    res.send("Hello world!")
})

In English, this means that, whenever someone accesses /testing on your server, you send a plain-text response that says “Hello world!” Notice that you have two parameters called req and res passed into your closure for handling the response. Compare this to how a similar route would look in Kitura 1.x:

router.get("/testing") { request, response, next in
    response.send("Hello world")
    next()
}

The two code snippets are nearly identical, except for closure syntax in Javascript versus Swift, and the need to call next() (something they managed to eliminate in Kitura 2.x). Not only does this provide a comfortable landing for Node.js developers interested in trying Swift, but this also means Kitura has been architected with a consistent, tried-and-true methodology that caters to performance, ease of use and code longevity.

The BFF Pattern and Why it Matters

The BFF (Backend for Frontend) is a design pattern that will quickly become your best friend (forever?) :]

It’s a common task for a mobile developer to interface an app with a REST API. It’s also somewhat common to run into issues during this integration. This could be for any number of reasons:

  • Verbose responses
  • Inconsistent error states
  • Versioning issues
  • Poor documentation

If you’re nodding your head, you might also remember saying something along the lines of, “I wish I could have just written the server myself!”

What if there was a way to handle these issues in the same programming language you write your iOS apps in, and you could deploy this solution to the cloud separately from your mobile app? Well, that’s precisely what you will do with Kitura. The BFF pattern enables you to deploy a server written in Swift that integrates with the existing server API.

The Swift server acts as an intermediary between your mobile app and that existing server API, and it allows the mobile developer to spend much less time integrating the app with the API. This also means that the only code your mobile app written in Swift will ever have to integrate with is also written in Swift, which insulates your mobile developers from having to work with something that may have a steep learning curve.

Picture a common scenario amongst developer teams for modern-day apps. With all due respect to DevOps and Data Science engineers, this scenario only involves two types of developers: the front-end developer and the back-end developer. For the sake of explanation, assume the front-end has two media: an iOS app and a website. You are the iOS developer. Assume you also do not know how to set up a back-end in any language.

Your app must show a series of restaurants with the following properties:

  • Name
  • Latitude and longitude
  • Address
  • Rating

The back-end developer has already made this method on the server, and you can access it RESTfully with a GET method. You would need to query the server based on providing a longitude and latitude. However, the current response is a little bit verbose, and looks like this:

{   
    "reasons": {
        "count": 0,
        "items": [
            {
                "summary": "This spot is popular",
                "type": "general",
                "reasonName": "globalInteractionReason"
            }
        ]
    },
    "venue": {
        "id": "40b13b00f964a520cff31ee3",
        "name": "North By Northwest (NXNW)",
        "location": {
            "address": "10010 N Capital of Texas Hwy",
            "crossStreet": "Stonelake",
            "lat": 30.391062198099544,
            "lng": -97.73859813809395,
            "labeledLatLngs": [
                {
                    "label": "display",
                    "lat": 30.391062198099544,
                    "lng": -97.73859813809395
                }
            ],
            "distance": 144,
            "postalCode": "78759",
            "cc": "US",
            "city": "Austin",
            "state": "TX",
            "country": "United States",
            "formattedAddress": [
                "10010 N Capital of Texas Hwy (Stonelake)",
                "Austin, TX 78759",
                "United States"
            ]
        }
    }
}

You have parsed JSON before, so the task might not be too terribly difficult to complete, but you are not the only iOS developer who will ever work on this. You might be a pro, but it would be nice to make the job easier for everyone, right? And what if this API goes down all of a sudden? You could cache data on the device if you wanted, but your users might notice a different user experience if the app is just loading data from the disk, and not able to pull data from a brand new query.

Monolith

This is where the Backend for Frontend design pattern comes in. To this point, I have described a Monolith pattern, where one API is responsible for handling requests from every single possible client that may consume it. Aside from these issues, how can you be sure that the API is up to the task of fielding requests from X number of devices concurrently? We want to make their job easier too, right?

The BFF pattern inserts an iOS API between the mobile iOS app and the main server API:

The BFF pattern

A few reasons why this pattern works in this particular use case:

  1. You can be sure that the only devices that make requests from this API will be iOS devices. This means you can be less worried about balancing request load.
  2. You have more control over what data goes in a response to an iOS device. Before this, you may have waited for the back-end developer to eventually get around to helping you, and conditionally trimmed response data based on a User-Agent header. Now, you can let the back-end developer work uninterrupted, and solve your problem by parsing response data down to only what your BFF device needs.
  3. In our specific use case, you can save responses for queries one user might make into a database before sending a response. This means that, if someone else requests restaurants in the same exact location, and the stored data is new enough to satisfy your refresh policy, you do not even have to send a query to the master server! You can just send the cached data and trust that it is fresh enough for your users.
  4. You can accomplish 1–3 in the language you already know how to write code in — Swift!

This is a microservice friendly approach that SoundCloud and ThoughtWorks pioneered in 2015. Imagine a workplace where you are free to “make your app work” without having to depend on another developer potentially blocking you. Thanks to the BFF design pattern, you do not have to imagine it anymore.