Bart Simons

swift

A 3 post collection


Swift + Perfect + Authentication API Example

 •  Filed under swift, perfect, example, authentication

So you want to build your next backend API in Swift? No problem! Perfect has got you covered. Perfect is a collection of libraries to turn your next server-side Swift application into reality. It is blazingly fast and awesome!

So I decided to dive a little bit deeper into the possibilities of Swift and Perfect, and so I quickly decided that an authentication API would be a 'perfect' idea (see what I did there?) to get started. So, what do we need?

  • A computer running Linux or macOS
  • Swift 3 installed
  • A MySQL Server

That's basically all that's needed. Now we need a functional database, so I came up with a SQL table like this:

CREATE TABLE `users` (  
  `id` int(32) NOT NULL,
  `username` varchar(128) NOT NULL,
  `password` varchar(128) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `users`  
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `username` (`username`),
  ADD UNIQUE KEY `id` (`id`);

INSERT INTO `users` (`id`, `username`, `password`) VALUES  
(1, 'user1', '7c12772809c1c0c3deda6103b10fdfa0'),
(2, 'user2', '7c12772809c1c0c3deda6103b10fdfa0');

ALTER TABLE `users`  
  MODIFY `id` int(32) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;

Perfect. Now - for the next part - initialize a new Swift package in an empty folder:

swift package init --type executable  

This will generate an empty package, so now it's time to edit our Package.swift file. You'll need to add 2 repositories to your project, this is how I have done that:

import PackageDescription

let package = Package(  
    name: "backend-api",
    dependencies: [
        .Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 2),
        .Package(url: "https://github.com/PerfectlySoft/Perfect-MySQL.git", majorVersion: 2)
    ]
)

Cool. So now it is about time to work on the real deal - programming! I've split the project into two separate swift files

  • main.swift : this is for all things related to the web server processing
  • DBOperations.swift : this is a provider to execute MySQL (prepared) statements in the form of a function

My main.swift:

import PerfectLib  
import PerfectHTTP  
import PerfectHTTPServer  
import Foundation

let server = HTTPServer()  
var routes = Routes()

server.serverPort = 8000

routes.add(method: .get, uri: "/", handler: {  
    request, response in

    response.status = HTTPResponseStatus.ok
    response.setHeader(.contentType, value: "application/json")

    response.setBody(string: "{\"status\":\"Backend server is up and running\"}")
    response.completed()
})

routes.add(method: .get, uri: "/oauth", handler: {  
    request, response in

    response.setHeader(.contentType, value: "application/json")

    let username = request.param(name: "username", defaultValue: "")
    let password = request.param(name: "password", defaultValue: "")

    if ((username ?? "").isEmpty || (password ?? "").isEmpty) {
        response.status = HTTPResponseStatus.ok
        response.setBody(string: "{\"status\":\"Invalid request\"}")
    } else {
        if (username ?? "").characters.count >= 8 || (username ?? "").characters.count <= 24{
            if (password ?? "").characters.count == 32 {
                if (username ?? "").rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) == nil && (password ?? "").rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) == nil {
                    response.status = HTTPResponseStatus.ok
                    let queryResult: [[[String: String]]] = executeQuery(query: "SELECT * FROM users WHERE username = ?", parameters: [username ?? ""])
                    if (queryResult.count == 1) {
                        if  ((queryResult[0][2]["password"] ?? "") as String == password ?? "") {
                            response.setBody(string: "{\"status\":\"Authentication request succeeded!\"}")
                        } else {
                            response.setBody(string: "{\"status\":\"Invalid request\"}")
                        }
                    } else {
                        response.setBody(string: "{\"status\":\"Invalid request\"}")
                    }
                } else {
                    response.status = HTTPResponseStatus.ok
                    response.setBody(string: "{\"status\":\"Invalid request\"}")
                }
            } else {
                response.status = HTTPResponseStatus.ok
                response.setBody(string: "{\"status\":\"Invalid request\"}")
            }
        } else {
            response.status = HTTPResponseStatus.ok
            response.setBody(string: "{\"status\":\"Invalid request\"}")
        }
    }

    response.completed()
})

server.addRoutes(routes)

do {  
    try server.start()
} catch PerfectError.networkError(let err, let msg) {
    print("Network error thrown: \(err) \(msg)")
}

My DBOperations.swift:

import MySQL

let sqlHost     = "127.0.0.1"  
let sqlUser     = "app_authentication"  
let sqlPassword = "testing01"  
let sqlDB       = "app_authentication"

func executeQuery(query: String, parameters: [String]? = nil) -> [[[String: String]]] {  
    var fStore = [[[String: String]]]()

    let mysql = MySQL()
    let connection = mysql.connect(host: sqlHost, user: sqlUser, password: sqlPassword, db: sqlDB)

    guard connection else {
        print(mysql.errorMessage())
        return [[[String: String]]]()
    }

    defer {
        mysql.close()
    }

    let fQuery = MySQLStmt(mysql)

    _ = fQuery.prepare(statement: query)

    if parameters != nil {
        for parameter in parameters! {
            fQuery.bindParam(parameter)
        }
    }

    _ = fQuery.execute()

    let fResults = fQuery.results()

    _ = fResults.forEachRow {
        e in

        var fSubStore = [[String: String]]()

        for i in 0..<e.count {
            let fFieldName: String? = fQuery.fieldInfo(index: i)!.name
            fSubStore.append(["\(fFieldName!)": "\(e[i]!)"])
        }

        fStore.append(fSubStore)
    }

    return fStore
}

You need to save both of these files inside the Sources folder of your package.

To build and run your app, run this in the root of your package directory:

swift build  
.build/debug/backend-api

Now it is time to test if everything works:
It works!

So: this is how you can build authentication APIs with Swift. Please bare in mind that all code examples given are NOT production ready. I know that it works, but I can definitely already see some points of improvements - too bad that I don't have time to fix that. This demo project is soon to be expected on my GitHub. Thanks for reading and have a nice day ;)

Using MySQL in Swift with Perfect

 •  Filed under swift, mysql, perfect

So I recently got a chance to play around with Perfect - a "web app framework" for Swift that provides you with multiple building blocks to get your project going. One of the really neat things about this framework is that it contains anything you need to get stuff connected. I came across their MySQL library that can be used in projects with or without the other Perfect dependencies involved. You can't get any more modular than this!


My development environment

I tend to always use Linux for my projects, and this little project is no exception. My dev box is equipped with the following stuff:

  • Ubuntu Server 16.04 LTS
  • MySQL Server
  • Swift 3.0.2

You also need to install the libmysqlclient-dev package through apt-get in order to use and build the Swift MySQL package.


Creating a new project

Create a new directory for this project on your server. I called mine mysql-app. Change your current directory to that directory and run swift package init --type executable to generate a blank Swift project. If you have a Mac and plan to use Xcode for your project: you can initialize an Xcode project file with swift package generate-xcodeproj


Adding Perfect-MySQL to the project

Edit your Package.swift file and include Perfect-MySQL as a dependency, like this:

import PackageDescription

let package = Package(  
    name: "mysql-app",
    dependencies: [
        .Package(url: "https://github.com/PerfectlySoft/Perfect-MySQL.git", majorVersion: 2)
    ]
)

Now it's time to write some code!


The database structure


The code

Just put the following code inside Sources/main.swift:

import MySQL

let sqlHost     = "127.0.0.1"  
let sqlUser     = "app_authentication"  
let sqlPassword = "testing01"  
let sqlDB       = "app_authentication"

func fetchData()  
{
    let mysql   = MySQL()
    guard mysql.connect(host: sqlHost, user: sqlUser, password: sqlPassword, db: sqlDB) else
    {
        print(mysql.errorMessage())
        return
    }

    defer {
        mysql.close()
    }

    let theStatement = MySQLStmt(mysql)

    _ = theStatement.prepare(statement: "SELECT * FROM users")
    _ = theStatement.execute()

    let theResults = theStatement.results()

    print("\r\n")

    _ = theResults.forEachRow {
        e in

        for i in 0..<e.count {
            let theFieldName = theStatement.fieldInfo(index: i)!.name
            print("\(theFieldName): \(e[i]!)")
        }

        print("\r\n")
    }
}

fetchData()  


Build and run

Just run swift build to build your project and run .build/debug/mysql-app to run your application. It should return this as the output in your terminal:


Extra information

I made this small tutorial after I had to fiddle around with this library for one whole day. The documentation suggests to use mysql.query to run queries, but there's too little information available about running prepared statements. Not only in the documentation of Perfect, but also on the whole web. Then - a couple hours later - I discovered the MySQLStmt class, after digging into the Swift Tests available on their Github repo.

Another reason to only use the MySQLStmt class is because the class contains a function called fieldInfo which returns the name of a column by ID. mysql.query simply doesn't have that...

Oh well, at least I got some of my code fixed today. Enjoy programming in Swift!

Controlling iTunes via Swift using SBApplication

 •  Filed under swift, itunes, sbapplication, scriptingbridge

Since I took my hands down on Swift, I discovered SBApplication, Apple's take on making scriptable calls to the applications you already have on your computer. Want to get a list of currently opened tabs in Safari, and each of their titles? No problem!

I used tingraldi's SwiftScripting repository to generate Swift headers for any application that is scriptable. The generated headers give you full access to all the available calls you can make to a scriptable application.

I came up with an idea that might be great for demoing the purposes of the SBApplication class: a simple command-line application that controls and/or fetches information from and to iTunes. I uploaded my code as a Github repository, it should work for any Intel-based Mac.

https://github.com/bmsimons/itunescli

The how-to-use and build guide can be found inside the readme file on my repository.