Setting Swift Free on the Web

Using server-side to let anyone enjoy Swift from their browser

Danny Bolella
Oct 14, 2019 · 6 min read
Image for post
Image for post
Image supplied by author

When I attended WWDC 2016, I remember sitting in the session called “Going Server-side With Swift Open Source.” After initially being taken aback by Apple’s new partnership with IBM, I then was amazed by the concept of server-side Swift. When I did some research back home, I found that a great number of devs were craving it, even to the point of begging Apple to pick up proposals that would help budding open source server frameworks.

The server-side Swift community is still quite passionate, today. There are multiple frameworks out there in the wild, the most popular among them being Perfect, Kitura, and Vapor. Probably the most obvious purpose is for writing a Swifty back end for an app written in Swift, specifically with shared code to save time, eliminate rewrite error, and reduce extraneous data massaging. However, there are devs out there who are just passionate about Swift and have set up entire websites and APIs in Swift without any Swifty clients that consume them.

Sharing Is Caring

Recently, I was working on a mobile project for both iOS (Swift) and Android (Kotlin). Because of how similar Swift and Kotlin actually are, they allow for the architecture and design to be extremely similar between the two versions. Since the Swift version was always slightly ahead, I found an open-sourced Mac app called SwiftKotlin that turned out to be an incredibly useful conversion tool.

While I was enjoying myself, some of my colleagues were a bit envious — primarily because I happened to have a Mac that could run the tool, which they could not in their Windows environments. I began to offer to pick up more of the translation work, but this was becoming a bottleneck. If only there was a way for Swift to run cross-platform without my colleagues needing to download and install any toolsets, languages, or dependencies.

And that’s how I came up with my use case for a server-side Swift project. Because SwiftKotlin was open source, the conversion framework was readily available. My plan, then, was to write a basic website where anyone could drop off Swift code, have it run through the SwiftKotlin Framework, and get the converted Kotlin code.

Note: While this is a specific use case, the concept would work with most frameworks/packages/pods. If you have one in mind, you can still follow these instructions, swapping out my example for your use case instead.

Building My Steam (Vapor) Engine

You will need Xcode, Terminal, and Vapor. That’s it! You can pull my code to follow along with from this repo.

For this project, I decided to use Vapor only because it was the only one of the three mentioned earlier that I hadn’t tried yet. In the end, it turned out to be pretty simple, and I was very satisfied with the results. To get it set up, just follow the installation guide.

From the terminal, we’ll want to start a new Vapor project using the web template. This way our Windows colleagues can simply convert from their browser of choice. To do so, run:

vapor new SwiftKotlinOnline — template=web

This sets up a project with the Leaf framework already set up. Leaf is a way of writing templated web pages that can also be linked to Swift functionality. We’ll get into that more later.

Next, we want to pull in SwiftKotlin as a Swift Package and Transform (a helper package). Open up the Package.swift file in our new project’s directory and add these dependencies:

.package(url: “https://github.com/yanagiba/swift-transform", .exact(“0.18.10”)),
.package(url:”https://github.com/angelolloqui/SwiftKotlin.git", .revision(“e993ad55276531e5f723b0ede47d0619ea734dcf”))

And then add them to our App target:

.target(name: “App”, dependencies: [“Vapor”, “Leaf”, “SwiftKotlinFramework”, “swift-transform”]),

To pull these dependencies in and also create our Xcode project, we now can run vapor xcode. When finished, you’ll be prompted to open Xcode automatically by entering y. After Xcode launches and our project is up, hit Run to make sure everything is working so far. In the console, you’ll eventually see that the app is running at localhost:8080. Copy and paste that link into the browser and make sure you see that it works. If so, we’re golden so far!

Routes

Having got this far, we can quickly check out a few things. First, look at routes.swift. This is how our server determines how to handle requests from the web and make any connections we decide to build. You’ll see where “welcome” is set up to be called as the default get route. We’ll come back here when we’re ready to make our routes. For now, let’s jump to welcome.leaf to see what Leaves are and what we’re asking to render.

Leaves

You’ll see some # marks as well as some familiar <div> and <img> tags. In Lead, #set tells Leaf that for some variable (e.g., title), the following is to be inserted where they’re referenced. On the bottom, we see #embed, which tells Leaf that these values are to be inserted into the named template (e.g., base). If we jump over to base.leaf, we see where a more complete HTML body, but with #get inserted where we want those values to be inserted by other Leafs that embed it. This is a high overview of how Leaf works, though I recommend checking out the docs.

Since this is how we’ll make our UI, we’ll start building our site here. Now, I’m not a proficient web UI developer, so we’ll just be making two simple leaves here. One will have a text field to drop Swift code into, use Javascript to place it into a form for processing purposes, and then POST to our server. The other Leaf will take the translation results and simply display them using <pre> and <code> tags. Both simply embed base.leaf to build the rest of the HTML around them.

Here are the gists:

Controllers

The last area of Vapor to cover is Vapor Controllers. Simply put, they allow us to group our custom Swift functionality as well as to write methods to handle requests and responses alongside that code.

For us, this will also be where we start coding by implementing the SwiftKotlin Framework in a controller. Referencing how it’s used in the author’s App implementation, we will extract the basics from there to set up translation. We will then write a method that takes a Vapor Request parameter and returns a Future<View>.

To move along, I’ve posted a gist of my code below so I can walk us through it. You’ll see that store takes the request, extracts the Swift code from it, and massages some of the string junk put in during the request. We then make sure we even have code to process. Otherwise, set a default (really for testing purposes). Then, we call on translate (taken from the original code) and store the results in a variable. Lastly, we return something that looks like a line from our routes.swift file. What we’re saying is to render transfer.leaf (which we’ll make in a second) and pass the translation as a parameter called output.

All roads lead to our routes

We finally circle back to routes.swift, where we’ll configure our two pages and work with our controller. For input, we can simply swap out “welcome” for “input” in the first route since it’s simply a GET, and we want that to be our default page.

router.get { req in
return
try req.view().render(“input”)
}

And then for our translate leaf and controller:

let translateController = TranslateKotlinController()
router.post(“translate”, use: translateController.store)

We set up an instance of our controller first, and then tell the router that, for the translate route, use our store function with the request as a parameter.

Results!

Now we hit Run again, go to localhost:8080, and give it a whirl.

Image for post
Image for post
Our two leaves and our converted Swift code, now in Kotlin!

Yes, the UI could stand a massive facelift, but what counts (to me and my team, at least) is that we now have our functionality on the browser! Now my colleagues can rejoice as they, too, can enjoy such a powerful Swift framework simply and effectively.

Swift Everywhere!

As I mentioned earlier, this is a very specific use case. Regardless, the concept of taking a Swift package and wrapping it for the web is the same, no matter the context. Knowing how simple and accessible it is, my hope is that it would at least tempt you to consider how you, too, can broaden the implementation of swift to the world!

See it on GitHub: https://github.com/dbolella/SwiftKotlinOnline

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store