Vapor 3 on Cloud Foundry

You are interested in how you can write server-side swift code and after the first hello world you hear a voice in your head, like “where the hell I can run this”? So one solution is, run it on Cloud Foundry inside the swift runtime. I know that swift on the server side is currently a rare requested topic, but when I start working with Vapor 3, I recognized that it took me some time and some research to get this run on Cloud Foundry. My hope is, if somebody out there who is trying the same will find this blog post and it helps to get this stuff run. Now let’s get started, let me explain how you bring your Vapor 3 app to Cloud Foundry.

At first you need access to your cloud foundry environment where your app should run. The next thing you need is a swift app, in my case it is a simple CRUD service which handles todo items. As the title 
let assume, this app uses the vapor 3 web framework. I choose this web framework, because I would use the latest swift network stack, better known as Swift NIO (released March 2018).

One of the concepts of Cloud Foundry (CF) is greatly support of the “12 factor app” pattern. And CF expect, that you follow this pattern and read all your configuration from environment variables as described in topic 3 on the “12 factor app” webpage. In my case I have to provide a database config, which is a PostgreSQL and for the cf runtime I have to read in the socket config, both will be provided via environment variable. The name of environment variables for the server socket are based on the cf runtime. The runtime uses for that, standard variables VCAP_APP_HOST and PORT to provide the socket configuration. To simplify my local development setup, I took the same and reuse it. For the database I use my own set of environment variables and prefixed them all with PSQL*.

For my local development I configured everything to local resources, the socket to 127.0.0.1:8080 and the database to my local PostgreSQL database. In the CF runtime the socket config is always provided for me, but the database variables have to be provided be my own, so I had to add the PostgreSQL variables with cf set-env to my CF app runtime. With this, I can read the config for my hosted cloud PostgreSQL database instance from the cf environment, in the same way I did on my local machine.

bash$ cf set-env snatch-todos PSQLHOSTNAME psql.clouddb.hostname.com
bash$ cf set-env snatch-todos PSQLPORT 5432
bash$ cf set-env snatch-todos PSQLUSERNAME "xxxxx"
bash$ cf set-env snatch-todos PSQLDATABASE "xxxxx"
bash$ cf set-env snatch-todos PSQLPASSWORD "*****"

Now that you know, how the environment behave, you have to adopt this in your swift app. And for this you have to load the config in Vapor from the environment. This is a important task, because Vapor has a fallback to start your app with a default socket on localhost:8080. This works perfect for your local development, but not in the CF runtime.

So we have to add the code for loading the environment variables for the socket to the config.swift file, which is in `Sources/App`. And create a new service object with the values from the environment.

the same is necessary for the database configuration.

If this works for you, you are ready to push your app to cloud foundry. The best thing on cloud foundry is cf push.

“here is my source code run it on the cloud for me i do not care how” Onsi Fakhouri

But before you can do this, you need to know the push command for swift runtime. The experience between all the runtimes is a bit different for some of the runtimes you only need cf push and rest works automagically, but for some them, you have to specify a “Procfile” or add the start command with the option “-c” to your cf push command. The “Procfile” or -c option (Startup command) describe, how to start the app. This explains CF how to run your app in the cloud. Swift is one of the runtimes which expect a “Procfile” or a start command. The simplest way is to build your swift app and the name of the executable is the run command. In my case as you know I use Vapor and my swift binary is called “Run”.

So before I could simply push my app, I have to create a “Procfile” with the content web: Run or extend my cli command with the -c option cf push <my-app-name> 32M -c Run. If you don’t like “Run” as the swift binary name you can rename this with the help of the Swift Package Manager.

This example show, how you can rename your executable from Run to “snatch-todos-service”

import PackageDescription
let package = Package(
name: “snatch-todos”,
products: [

.executable(name: “snatch-todos-service”, targets: [“Run”]),
],
dependencies: [

],
targets: [

.target(name: “Run”, dependencies: [“App”]),
]
)

And after the rename, you can do cf push <my-app-name> 32M -c snatch-tods-service instead.

But let‘s go back to the push, the last important thing for my Vapor based app with Swift NIO under the hood is that I need swift 4.1 and this will be provided by the latest buildpack, which is already available on IBM Cloud Foundry. I think, I have to be more specific here why I mention explicit IBM. Because IBM Cloud Foundry is currently the only CF provider I know, which provide swift as runtime out of the box and this make your life as a developer much easier. So finally, let me summarise the cf deployment command. I need the name of my app, I wanna specify the memory usage of my app with 32MByte per instance and I have to tell how to start my app.

And this is the cf push command:

cf push <my-app-name> 32M -c Run 

That’s everything! Now that you know, how it works, try it out! Write your own app or clone my example from here. Then follow Onsi’s advice, “run it on the cloud for me, I do not care how”.

Cheers

Norman

Links:

Example on github:

Example app in action 😀

http://snatch-todos.eu-gb.mybluemix.net/todos