A JSON configuration utility for Perfect Swift

I’m getting myself further into Perfect Swift server…

A JSON configuration utility for Perfect Swift
Download JSONConfig from GitHub

In the previous post, my Acronym sample starter for getting SSL working on your server, in Environment.swift, I hard coded stuff like ports. Sure, some of the things would change depending on conditional compilation, but that’s not the best way to go.

Better is an external file that contains configuration information.

iamjono has a great little utility that uses JSON. However, the JSON file is flat. I can’t organize the configuration information into groups. With JSON, more can be done than a flat file.

In the JSONConfig utility I posted on GitHub, you can set the source for your JSONConfig and then get values based on a key path.

For example, suppose your configuration JSON file looks like this:

{
    "server": {
        "name": "www.your-domain.com",
        "port": 80
    },
    "database": {
        "host":     "127.0.0.1",
        "username": "db_bob",
        "password": "bob_password",
        "database": "db_bob"
    }
}

In your project code, you an access values by key path.

let serverName = JSONConfig.shared.string(forKeyPath: server.name")

The default value for a String at a path is “”. You can specify something else. For example:

let serverName = JSONConfig.shared.string(forKeyPath: "server.name", otherwise: "sub.your-domain.com")

In the current release, I’m just providing convenience routines for string, integer, double, and bool. I’ll provide other data types soon. Regardless, you can get a value at a key path using:

let it = JSONConfig.shared.value(forKeyPath: "your.path.to.value") // Any?

As a last note, it is always good to validate your JSON. There are lots available online. 🙂

Perfect Swift Server Starter with SSL

I’m building an iOS app that will need a web service for the data management. I’ve looked at Firebase and CloudKit. Both are very good options but they are not going to quite fit my need with this project.

Normally, I would roll my own backend using PHP and MySQL. They are both quite familiar to me and I’ve built a number of my own frameworks to make my life easier with them. But… this is also a very good time to lift my head up and see what else is on the terrain.

Building a Perfect Swift Server Starter with SSL App
Download Acronym Project from GitHub

When Apple announced that Swift is open source, that was very exciting to me. I enjoy the language and with more people participating in its development, the quicker and the cooler the improvements would come. Swift 3 was a big change, as reflected in all the little things I had to fix in my code to migrate it from 2 to 3. But, Swift 3 seems to represent a major milestone in the language development.

In looking for back end solutions, I also looked at what was happening with Swift on the server. I found Ryan Collins post on medium.com, “Current Features & Benefits of the Top Server-Side Swift Frameworks,” very helpful. Where Perfect shines is important to me and where Perfect falls short isn’t that important to me. So I picked Perfect to examine further.

After perfect.org, my first stop was Ray Wenderlich with the great set of tutorials for Perfect.

I have a ubuntu 16.04 server that I’ve been using for Node.js and APNs. It wasn’t very hard to get going on the server. Follow the instructions found on their Getting Started page. Of course, you’ll need to also install swift. There is an script you can get from Perfect-Ubuntu or you can go Download Swift from swift.org.

The Perfect Assistant is super handy. Make sure you download/install that.

But, before you get too far down the road, get the PerfectTemplate running on your Mac and on your Ubuntu server. Once that’s running properly, we can move on to the next steps.

The next steps consist of building a basis for MySQL StORM then getting and using a certificate for https.

Ray Wenderlich’s tutorial videos talks about using PostgreSQL for its database backing for StORM. I’m wanting to use MySQL. Swapping MySQLStORM for PostgresStORM is trivial. Watch the whole series from Ray Wenderlich. The videos are short and informative.

In main.swift of my Acronym project, you can see that I’m not putting everything into main. I’m placing routes into controllers that conform to a ControllerProtocol. Database access is also separated out into an ORM object and an API class. It’s a step towards more SOLID coding.

You will also notice that I’m using a class called Environment (for the lack of a better name). Environment has a static variable isXcode that is true #if Xcode. Based on that variable, I return different values for things like serverPort. I’m also initializing the MySQLConnector in a static func in Environment. How to setup a MySQL database on your server is something I’m not going to cover here.

In Environment, you’ll also see that the serverName is returned as “sub.your-comain.com” — this will need to be updated to your actual domain.

Out of the box, Acronym will start the server on port 80 on Linux. It also will serve static files out of ./webroot with the FilesController. This is important to get the LetsEncrypt Certbot installed. Read the excellent post by Jonathan Guthrie titled Easily Secure your Perfect Server Side Swift code with HTTPS for instructions on how to install the LetsEncrypt Certbot.

The first step is to install certbot with the following:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

Because the Acronym app is serving up static pages out of ./webroot, when you run the following command, the certbot will be able to confirm your website by adding and removing some data in a specific path in ./webroot.

sudo certbot certonly --webroot -w /the/path/to/Acronym/webroot/ -d sub.your-domain.com

A couple notes here: 1) replace /the/path/to/Acronym/webroot/ with the actual path, and 2) replace sub.your-domain.com with your actual domain.

If all works well, you will see out put that ends with something like:

...
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/test.mydomain.com/fullchain.pem. Your cert
will expire on 2017–09–18. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run “certbot
renew”

Success! Now to you just need to do a couple things in Environment.swift to get Acronym to run on port 443.

  1. Have the serverPort method return 443 when !self.isXcode.
  2. Check that the keyPath string in the tls method is the same as what was stated after the “Creating CSR” above.

Now you can rebuild Acronym and launch it. When you direct your browser to https://sub.your-domain.com, you should see the little closed lock showing up!

NSPersistentDocument and Swift

It’s been a while since I’ve worked with NSPersistentDocument. My last dabbling with it was back in the days of Objective-C. Ahh Objective-C. Oh, and I was using xibs instead of storyboards.

With xibs, the user interface file had an object called “File’s Owner” which would be a handy reference right directly to my subclass of NSPersistentDocument. That would give me easy access to the all important managed object context (moc).

With Objective-C, I could conveniently override the - (id)initWithType:(NSString *)typeName error:(NSError **)outError method in NSPersistentDocument to populate a newly created document with whatever entities I wished.

Easy. Or at least it was easy after I had figured all that out some 5 years ago.

Now it is easy again but I had to burn up a couple of days figuring it all out all over again.

Stuff I learned over the weekend…

Where to start… let’s start with populating your subclass of NSPersistentDocument when it is instanced for a new document.

You can’t override a convenience initializer in Swift. Well… actually you can but then you lose all the goodness that comes from NSPersistentDocument version of the convenience initializer. Inconvenient? You betcha. That was the way I could populate a new document in the old days. But we love Swift so we will find a workaround.

I looked all over the Internet for this workaround and didn’t find anything satisfying. But what I did do is quickly read this “Discussion” in the documentation for managedObjectContext:

If a managed object context for the document does not exist, one is created automatically. If you want to customize the creation of the persistence stack, reimplement this property in your custom subclass and use your implementation to create the appropriate objects.

Quickly reading this I got “blah blah create blah objects.” So I thought this might be the hook to populate a new document with entities. It seemed to work. I could add stuff to the moc. The storyboard would show what was created in the interface. Seemed to be working.

But not saving. I was adding stuff to the moc before it was ready. The place I’m looking at now to populate the document is at the end of the override func makeWindowControllers() method. I don’t know if this is the best place to do it but a) it works, b) all the goodies that NSPersistentDocument needs to create are in place at this time. It might be better at the start of the method… but stuff is working as it is so… I’ll poke the bear later.

My populate method needs to check the state of the document and add things that are missing. In the old days, I’d know what the state was and it wouldn’t be required when opening an existing document.

Next… getting that all important managedObjectContext in the storyboard. Or “The Magic of the RepresentedObject.”

I only really like magic in my D&D games or in the movies and definitely not in my code. But the representedObject in a NSViewController is magic. If you don’t cast this spell just right, the magic won’t work.

I asked and answered the question on stackoverflow so you can see the details there.

Things that don’t seem to work…

I saw somewhere that someone wrote in makeWindowsController: windowController.contentViewController!.representedObject = windowController.document Don’t do it. Even though it seems to be right (didSet in the controller’s representedObject shows the right object being setted), the magic didn’t work for me.

Don’t try to be tidy and create a method to skirt around the Model Key Path of self.representedObject.managedObjectContext in your storyboard. Your tidy method will look tidy and right but the magic won’t work. At least it didn’t for me. And I tried many many different variations.

Anyhow… looking at it all now, it is all pretty easy. It just took the weekend to tease it all out.

In summary, In Swift, NSPersistentDocument doesn’t have a handy spot to hook in populating a new document like Objective-C had. I’ll have to test every document created to see if it is populated or not and go from there. And with storyboards, representedObject is your new temperamental friend. Treat it nicely, pass it nicely around to other view controllers, and it will give you much moc.