It' been a while since I used Swift on the backend. Since then, it has come a long way. Frameworks like Vapor and Kitura went through several iterations and have become more mature. So did the Swift package manager which saved me while working on this project from my last year's chore of resolving all dependency conflicts. While I was back then playing around with Vapor as my server-side framework of choice, I decided this year to give Kitura a try. For my server side application I chose a highscore server for TicTacToe. Since I already wrote an implementation of TicTacToe in Swift, I only needed to implement the server side code and add a network layer to the client to connect both.
The first step was to setup the package manager configuration file, which basically meant running "swift package init" and adding Kitura as a dependency to Package.swift. Although vi is my command line editor of choice, I prefer Xcode for coding. Hence I ran the package manager again with "swift package generate-xcodeproj" to turn my Package.swift file into an Xcode project. After that, I was finally ready for some coding.
The highscore server consists of 3 files: main.swift to configure Kitura and to setup the required routes, HighscoreRouter.swift to handle the routing requests and Highscore.swift to manage the highscore.
I wanted to be able to handle 3 requests:
GET: /highscore.json to retrieve the whole highscore
POST: /highscore.json to add a new score to the highscore
GET: /highscore.html to show the current highscore in a browser.
So main.swift creates an instance of HighscoreRouter, sets up the aforementioned routes and links those routes to the responsible methods in HighscoreRouter. Last but not least, it tells Kitura on what port to listen to and to start listening.
Incoming routes are routed through Kitura and if they match the configured routes, are eventually handled by HighscoreRouter. HighscoreRouter itself as mentioned above doesn't manage the highscore. It delegates that task to an instance of Highscore. Highscore has 2 methods for this. The all() method returns the whole highscore and the addScore() method adds a score to the correct position in the highscore. So for every GET request the result from all() is passed back by the router and for every POST request the JSON is passed on to addScore().
I also wanted to see my highscore in a browser. This can be done quite easily with Kitura as well. For this, I added KituraStencil to Package.swift, configured the route in main and delegated the result from Highscore's all() method to a KituraStencil template which can be found in the Views folder. The result can be seen in Picture 2.
After that I started adding the network layer to TicTacToe. I created one restful API agnostic layer with TTTNetworklayer and one API aware layer that sits on top of the former with TTTBackendClient, which basically made Highscore's class interface method all() and addScore() available to the client via its methods getHighScore() and postHighscore().
At start-up the TicTacToe app then tries to connect to the server by retrieving the current highscore. If the server can be reached and a highscore is returned, a corresponding highscore button is shown in the UI. To decouple network and UI, I store the incoming highscore in CoreData. The highscore UI itself is shown in HighscoreTableViewController. HighscoreTableViewController relies on a NSFetchedResultscontroller to retrieve the highscore and to sort it correctly. From there on, it is the usual tableview data flow where tableView:cellForRowAtIndexPath: eventually passes the CoreData model to a view model which then again is used in the cell's configure() method to setup the cell.
Build & Run
Since I didn't want to start my highscore server manually, I added a prebuild step to TicTacToe's prebuild configuration (edit Schema -> Run -> Pre actions). The script in there basically looks for the highscore server's binary and starts it. To make sure the binary is actually there, I added a dependency to the TicTacToe target in the form of an aggregate target. This target contains nothing but a build script to generate the binary of the highscore server.
Writing an highscore server for my TicTacToe implementation was a fun exercise. I admit it is not utterly useful but the exercise whet my appetite to do more with Swift on the backend. And since I currently don't get the chance to use Swift 4 features in production, I seized the opportunity to play around with these in this project as well.
While I was coding, I also ran into a problem with Xcode 9's Swift 4 compiler for which I created a radar. So all in all, it was a pretty good exercise.
While Swift is getting more mature, its server frameworks get richer in their feature set. They are of course not comparable yet to what's available with other languages, but the gap is closing. Give server side Swift a chance and play around with it a little. You don't have to start from scratch since the source code for this exercise can be found on GitHub.