Swift, Perfect, mustache and PostgreSQL on Heroku — 4

Anatoly Rosencrantz
5 min readMay 4, 2016

--

First step is here, its code here. Previous step is here, its code here.

During three previous chapters we’ve built service that returns JSON of structure defined by mustache template and filled with some data (hardcoded or recieved from Postgres database), and deployed it to Heroku. The only thing that left to do is — make PostgreSQL work on Heroku.

Step 2.2 Set up Heroku database

This step is described in details in Heroku’s documentation.

Open Terminal, cd to your project’s directory and add new addon to your heroku app:

On postgres.heroku.com/databases you can see new db:

If you’ll click on its name, Overview page with open — with all secret data about your db. With use of it our app will connect to db; you can connect with Postico or using command line to manage database and review contents, also.

Now we want to pass our data from local database (stored on your mac) to heroku’s one. Make sure that your local Postgres server is up and and run:

but what is this DATABASE_URL? — you’ll ask

Let’s check that data is delivered. You can do it in Postico, but I’m too lazy to copy passwords, usernames, hosts of heroku’s db on Overview page. I’ll use heroku’s smart tool in Terminal:

Nice, all data on its place.

Step 2.2.1 Set environment variables

Remember we were hardcoding username and host and password in FoodListHandler.swift?

This is not good approach, cuz when we want to run server locally on our mac, we need this set of credentials, and on Heroku — another. Good solution is to use Environment Variables. Our application, wherever it runs, will request variable with specific name from operating system, OS X will take them from Xcode’s Scheme while debugging (or you can define them for a whole system), and for Heroku we will define them on dashboard’s Settings section:

this DATABASE_URL was added automatically when we’ve added postgre addon

That DATABASE_URL in pg:push command is nothing other than this config var. Add DATABASE_HOST, DATABASE_PASS, DATABASE_USER and DATABASE_NAME with values from db Overview page (Host, Password, User, Database respectfully).

Configure all four vars in Scheme settings also, but with values of local db:

to open this window click on PerfectServer HTTP App scheme and choose Edit Scheme… and use your username instead of that “vixi”

Step 2.2.2 Get environment variables

There are two ways to get environment variables in Swifty code:

  • using NSProcessInfo class from Foundation framework which is part of standard library on OS X… but is still in development for linux and is going to be shipped as part of Swift3 (I’m writing this tutorial on 3rd of May 2016). We still can use pre-release version in same way how we were working with PostgreSQL dependency — download from repository, add to project, update makefile to know how it should be built and liked and installed…
  • but for such basic thing as env vars we can use good old C libs that are already part of Swift standard library and are being maked by current makefile. I’m choosing this option (until I’ll need something more complicated from Foundation)!

For OS X this lib is Darwin, and for Linux — Glibc, so import them conditionally on the top of FoodListHandler.swift:

#if os(Linux)
import Glibc
#else
import Darwin
#endif

To class FoodListHandler add private method:

private func getEnvVar(name: String) -> String {
return String.fromCString(getenv(name)) ?? “”
}

It uses getenv(_:) C-function from imported Darwin or Glibc. Replace implementation of dbHost, dbName, dbUsername and dbPassword with this:

lazy var dbHost:String = self.getEnvVar(“DATABASE_HOST”)
lazy var dbName:String = self.getEnvVar(“DATABASE_NAME”)
lazy var dbUsername:String = self.getEnvVar(“DATABASE_USER”)
lazy var dbPassword:String = self.getEnvVar(“DATABASE_PASS”)

Run and check that nothing is broken and application works locally as before. (Yes, I know that I’d better use singleton to store these strings in memory and not bother getenv(_:) every time we’ll need them, but here i’m just trying to keep code simple)

Step 2.2.3 Push changes to Heroku

As we’ve done before, use git command push:

And check that you can retrieve data from database that is located on Heroku:

your app is on the ☁️!

Congratulations! You’ve developed back-end on Swift with use of Perfect webframework, used mustache templates, built PostgreSQL database, discovered what is makefile and deployed whole thing to the cloud! Objective-C developers can only be jealous ;)

Code of this step is here.

These tutorials are participating in Perfect’s contest. If you’ve liked — please, be kind to thumb up here, I’m running out of mice!

Bonus: make Heroku’s log work again

Logging is important. Heroic has special View Logs button for every app:

So I want see here everything my application writes with print(_:) function.

When you call print(“Hello World”) somewhere in your application, string Hello World should be added to the end of stdout file. In order to work faster, applications are caching these strings for some time, and write to file bunch of them. Read more here.

Heroku knows how to take data from stdout. But if we want message to appear in heroku’s Logs page without delay, we have to use fflush(_:) function.

I’m not sure it is good code, but I’ve done that this way:

And thanks NatashaTheRobot for tip of this enum with no cases idea.

--

--