浏览代码

Swiftperfect (#4048)

* added graphql-express-mongodb to the express configurations

* refactored code to use a single routes.js file passing in app and a resolver file

* initial commit of perfect swift framework incorporating two tests /json and /plaintext

* configured .gitignore

* renamed folder

* added perfect-mysql test

* added perfect-mongodb configuration

* made adjustments to the dockerfiles to accomodate the addition of the mongodb dependencies, made minor alterations to the main.swift files -- adjusting the random values by 1 and removing superfluous code and comments
jenriquez-techempower 7 年之前
父节点
当前提交
b3b2089895

+ 6 - 0
frameworks/Swift/perfect/.gitignore

@@ -0,0 +1,6 @@
+.DS_Store
+.build
+build_gcd
+.swiftenv
+Packages
+*.xcodeproj

+ 25 - 0
frameworks/Swift/perfect/Package.swift

@@ -0,0 +1,25 @@
+// swift-tools-version:4.0
+
+import PackageDescription
+
+let package = Package(
+	name: "Perfect-TechEmpower",
+	products: [
+		.executable(name: "Perfect", targets: ["Perfect"]),
+		.executable(name: "Perfect-MySQL", targets: ["Perfect-MySQL"]),
+		.executable(name: "Perfect-PostgreSQL", targets: ["Perfect-PostgreSQL"]),
+		.executable(name: "Perfect-MongoDB", targets: ["Perfect-MongoDB"])
+	],
+	dependencies: [
+		.package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0"),
+		.package(url:"https://github.com/PerfectlySoft/Perfect-MySQL.git", from: "3.0.0"),
+		.package(url: "https://github.com/PerfectlySoft/Perfect-PostgreSQL.git", from: "3.0.0"),
+		.package(url:"https://github.com/PerfectlySoft/Perfect-MongoDB.git", from: "3.0.0")
+	],
+	targets: [
+		.target(name: "Perfect", dependencies: ["PerfectHTTPServer"]),
+		.target(name: "Perfect-MySQL", dependencies: ["PerfectHTTPServer", "PerfectMySQL"]),
+		.target(name: "Perfect-PostgreSQL", dependencies: ["PerfectHTTPServer", "PerfectPostgreSQL"]),
+		.target(name: "Perfect-MongoDB", dependencies: ["PerfectHTTPServer", "PerfectMongoDB"])
+	]
+)

+ 25 - 0
frameworks/Swift/perfect/README.md

@@ -0,0 +1,25 @@
+# [Perfect](https://www.perfect.org) Benchmark Test
+
+This is the [Perfect](https://www.perfect.org) portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms.
+
+## Variants
+
+There is one version of the benchmark, not using any backend:
+- `Perfect`: No DB
+
+Each listens on port 8080, and use common URLs described below.
+
+## Versions and Dependencies
+
+This version of the benchmark requires Swift 4.1, and uses the following versions of Perfect and dependencies:
+
+- [Perfect 3.0](https://github.com/PerfectlySoft/Perfect-HTTPServer.git)
+
+## Test URLs
+### JSON serialization
+
+http://localhost:8080/json
+
+### Plaintext
+
+http://localhost:8080/plaintext

+ 310 - 0
frameworks/Swift/perfect/Sources/Perfect-MongoDB/main.swift

@@ -0,0 +1,310 @@
+import PerfectHTTP
+import PerfectHTTPServer
+import PerfectLib
+import PerfectMongoDB
+import Foundation
+
+let tfbHost = "tfb-database"
+let database = "hello_world"
+let username = "benchmarkdbuser"
+let password = "benchmarkdbpass"
+
+let client = try! MongoClient(uri: "mongodb://\(tfbHost)")
+let db = client.getDatabase(name: database)
+let World = db.getCollection(name: "world")
+let Fortune = db.getCollection(name: "fortune")
+
+
+class LinearCongruntialGenerator {
+ 
+    var state = 0 //seed of 0 by default
+    let a, c, m, shift: Int
+ 
+    init() {
+        self.a = 214013
+        self.c = 2531011
+        self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648
+        self.shift = 16
+    }
+ 
+    func random() -> Int {
+        state = (a * state + c) % m
+        return state >> shift
+    }
+}
+
+let numGenerator = LinearCongruntialGenerator()
+
+func fetchFromWorld(id: String?) -> [String: Any] {
+
+    var rand:Int = 0
+
+    if id == nil {
+        rand = numGenerator.random() % 10000 + 1
+    } else {
+        rand = Int(id!)!
+    }
+
+    if let world = World {
+
+        var json = [String:Any]()
+        json["id"] = rand
+
+        var fields = [String: Any]()
+        fields["id"] = 1
+        fields["randomNumber"] = 1
+        fields["_id"] = 0
+
+        var fieldString: String = ""
+
+        do {
+            fieldString = try fields.jsonEncodedString()
+        } catch {
+            fieldString = String(describing: fields)
+        }
+
+        do {
+            let jsonString = try json.jsonEncodedString()
+            do {
+                let results = try world.find(query: BSON( json: jsonString ), fields: BSON( json: fieldString ))
+
+                if let res = results {
+                    for item in res {
+                        let itemString = String(describing: item)
+                        return convertStringToDictionary(str: itemString)
+                    }
+                } else {
+                    print("results couldn't be unwrapped: ", rand)
+                }
+            } catch {
+                //
+            }
+        } catch {
+            // empty on purpose
+        } 
+    } else {
+        //
+    }
+    
+    let emptyObj = [String: Any]()
+    return emptyObj
+}
+
+func updateOneFromWorld() -> [String: Any] {
+
+    let rand = numGenerator.random() % 10000
+    let rand2 = numGenerator.random() % 10000
+    var errorObj = [String: Any]()
+
+    if let world = World {
+
+        var json = [String:Any]()
+        json["id"] = rand
+
+        var fields = [String: Any]()
+        fields["id"] = 1
+        fields["randomNumber"] = 1
+        fields["_id"] = 0
+
+        var update = [String: Any]()
+        update["randomNumber"] = rand2
+
+        var fieldString: String = ""
+
+        do {
+            fieldString = try fields.jsonEncodedString()
+        } catch {
+            fieldString = String(describing: fields)
+        }
+
+        var updateString: String = ""
+        var jsonString: String = ""
+
+        do {
+            updateString = try update.jsonEncodedString()
+        } catch {
+            updateString = String(describing: update)
+        }
+
+        do {
+            jsonString = try json.jsonEncodedString()
+        } catch {
+            jsonString = String(describing: json)
+        }
+
+        do {
+            let results = try world.findAndModify(query: BSON( json: jsonString ), sort: nil, update: BSON( json: updateString ), fields: BSON( json: fieldString ), remove: false, upsert: false, new: true)
+            let resultsStr = String(describing: results)
+            return convertUpdateStringToDictionary(str: resultsStr, id: rand)
+        } catch {
+            errorObj["id"] = "Error running query findAndModify"
+            return errorObj
+        }
+    } else {
+        errorObj["id"] = "world is empty"
+        return errorObj
+    }
+}
+
+func updatesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var updateArr: Array = [[String: Any]]()
+
+    while 0 < totalQueries {
+        updateArr.append(updateOneFromWorld())
+        totalQueries -= 1
+    }
+
+    do {
+
+        response.appendBody(string: try updateArr.jsonEncodedString())
+    } catch {
+
+        response.appendBody(string: String(describing: updateArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var queryArr = [[String: Any]]()
+
+    while 0 < totalQueries {
+
+        queryArr.append(fetchFromWorld(id: nil))
+        totalQueries -= 1
+    }  
+
+    do {
+        response.appendBody(string: try queryArr.jsonEncodedString())
+    } catch {
+        response.appendBody(string: String(describing: queryArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let res = fetchFromWorld(id: nil)
+
+    do {
+        response.appendBody(string: try res.jsonEncodedString())
+    } catch {
+        response.appendBody(string: String(describing: res))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+    response.completed()
+}
+
+// Helpers
+
+func setHeaders(response: HTTPResponse, contentType: String) {
+
+    response.setHeader(.contentType, value: contentType)
+    response.setHeader(.custom(name: "Server"), value: "Perfect")
+
+    let currDate: String = getCurrDate()
+
+	response.setHeader(.custom(name: "Date"), value: currDate)
+}
+
+func getCurrDate() -> String {
+
+    let now = getNow()
+
+    do {
+        let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil)
+        return formatted
+    } catch {
+        return "error formatting date string"
+    }
+}
+
+func returnCorrectTuple(queryArr: [(String, String)]) -> String {
+
+    for tup in queryArr {
+        if String(describing: tup.0) == "queries" {
+            return String(describing: tup.1)
+        }
+    }
+
+    return "nil"
+}
+
+func sanitizeQueryValue(queryString: String) -> Int {
+
+    if let queryNum = Int(queryString) {
+
+        if queryNum > 0 && queryNum < 500 {
+            return queryNum
+        } else if queryNum > 500 {
+            return 500
+        } else {
+            return 1
+        }
+    } else {
+        return 1
+    }
+}
+
+func spoofHTML(fortunesArr: [[String: Any]]) -> String {
+
+    var htmlToRet = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>"
+
+    for fortune in fortunesArr {
+
+        htmlToRet += "<tr><td>\(fortune["id"]!)</td><td>\(fortune["message"]!)</td></tr>"
+    }
+
+    htmlToRet += "</table></body></html>";
+
+    return htmlToRet
+}
+
+func convertStringToDictionary(str: String) -> [String: Any] {
+
+    let strOfWordsArray = str.components(separatedBy: " ")
+
+    var returnObj = [String: Any]()
+
+    returnObj["id"] = Int(strOfWordsArray[3].dropLast())
+    returnObj["randomNumber"] = Int(strOfWordsArray[6])
+
+    return returnObj
+}
+
+func convertUpdateStringToDictionary(str: String, id: Int) -> [String: Any] {
+
+    let strOfWordsArray = str.components(separatedBy: " ")
+
+    var returnObj = [String: Any]()
+    returnObj["id"] = id
+    returnObj["randomNumber"] = Int(strOfWordsArray[16])
+
+    return returnObj
+}
+
+var routes = Routes()
+routes.add(method: .get, uri: "/updates", handler: updatesHandler)
+routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler)
+routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler)
+routes.add(method: .get, uri: "/**",
+		   handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest)
+try HTTPServer.launch(name: "localhost",
+    port: 8080,
+    routes: routes,
+    responseFilters: [
+    (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)])

+ 322 - 0
frameworks/Swift/perfect/Sources/Perfect-MySQL/main.swift

@@ -0,0 +1,322 @@
+import PerfectHTTP
+import PerfectHTTPServer
+import PerfectLib
+import PerfectMySQL
+import Foundation
+
+let tfbHost = "tfb-database"
+let database = "hello_world"
+let username = "benchmarkdbuser"
+let password = "benchmarkdbpass"
+
+let mysql = MySQL()
+let connected = mysql.connect(host: tfbHost, user: username, password: password)
+let _ = mysql.selectDatabase(named: database)
+
+class LinearCongruntialGenerator {
+ 
+    var state = 0
+    let a, c, m, shift: Int
+ 
+    init() {
+        self.a = 214013
+        self.c = 2531011
+        self.m = Int(pow(2.0, 31.0))
+        self.shift = 16
+    }
+ 
+    func random() -> Int {
+        state = (a * state + c) % m
+        return state >> shift
+    }
+}
+
+let numGenerator = LinearCongruntialGenerator()
+
+func fetchFromFortune() -> [[String: String]] {
+
+    var arrOfFortunes = [[String: String]]()
+    
+    let querySuccess = mysql.query(statement: "SELECT id, message FROM fortune")
+
+    guard querySuccess else {
+
+        let errorObject = ["id": "Failed to execute query"]
+        arrOfFortunes.append(errorObject)
+        
+        return arrOfFortunes
+    }
+ 
+    let results = mysql.storeResults()!
+
+    results.forEachRow { row in
+
+        if let id = row[0], let message = row[1] {
+            
+            let resObj = ["id": String(describing: id), "message": message]
+            arrOfFortunes.append(resObj)
+        } else {
+            print("not correct values returned: ", row)
+        }
+    }
+
+    return arrOfFortunes
+}
+
+func fetchFromWorld(id: String?) -> [String:Any] {
+
+    var returnObj = [String: Any]()
+    var errorObject = [String: Any]()
+    var rand:Int = 0
+
+    if id == nil {
+        rand = numGenerator.random() % 10000 + 1
+    } else {
+        rand = Int(id!)!
+    }
+
+    let querySuccess = mysql.query(statement: "SELECT id, randomNumber FROM World WHERE id = \(rand)")
+
+    guard querySuccess else {
+
+        errorObject["id"] = "Failed to execute query"
+
+        return errorObject
+    }
+ 
+    let results = mysql.storeResults()!
+
+    results.forEachRow { row in
+
+        if let id = row[0], let randomNumber = row[1] {
+
+            returnObj["id"] = id
+            returnObj["randomNumber"] = randomNumber
+        } else {
+
+            returnObj["id"] = "No return value"
+            returnObj["randomNumber"] = "what happened?"
+        }
+    }
+
+    return returnObj
+}
+
+func updateOneFromWorld() -> [String: Any] {
+
+    var returnObj = [String: Any]()
+    var errorObject = [String: Any]()
+
+    let rand = numGenerator.random() % 10000
+    let rand2 = numGenerator.random() % 10000
+
+    let querySuccess = mysql.query(statement: "UPDATE World SET randomNumber = \(rand) WHERE id = \(rand2)")
+
+    guard querySuccess else {
+
+        errorObject["id"] = "Failed to execute query"
+
+        return errorObject
+    }
+ 
+    if let results = mysql.storeResults() {
+
+        results.forEachRow { row in
+
+            if let id = row[0], let randomNumber = row[1] {
+
+                returnObj["id"] = id
+                returnObj["randomNumber"] = randomNumber
+            } else {
+
+                returnObj["id"] = "No return value"
+                returnObj["randomNumber"] = "what happened?"
+            }
+        }
+
+        return returnObj
+    } else {
+
+        returnObj["id"] = rand2
+        returnObj["randomNumber"] = rand
+        return returnObj
+    }
+}
+
+func fortunesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    var arrOfFortunes = fetchFromFortune()
+
+    let newObj: [String: String] = ["id": "0", "message": "Additional fortune added at request time."]
+
+    arrOfFortunes.append(newObj)
+
+    let sortedArr = arrOfFortunes.sorted(by: ({ $0["message"]! < $1["message"]! }))
+
+    let htmlToRet = spoofHTML(fortunesArr: sortedArr)
+
+    response.appendBody(string: htmlToRet)
+    
+    setHeaders(response: response, contentType: "text/html")
+    response.setHeader(.custom(name: "CustomLength"), value: String(describing: htmlToRet.count + 32))
+
+    response.completed()
+}
+
+func updatesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var updateArr: Array = [[String: Any]]()
+
+    while 0 < totalQueries {
+        updateArr.append(updateOneFromWorld())
+        totalQueries -= 1
+    }
+
+    do {
+
+        response.appendBody(string: try updateArr.jsonEncodedString())
+    } catch {
+
+        response.appendBody(string: String(describing: updateArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var queryArr: Array = [[String: Any]]()
+
+    while 0 < totalQueries {
+
+        queryArr.append(fetchFromWorld(id: nil))
+        totalQueries -= 1
+    }  
+
+    do {
+
+        response.appendBody(string: try queryArr.jsonEncodedString())
+    } catch {
+
+        response.appendBody(string: String(describing: queryArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let res = fetchFromWorld(id: nil)
+
+    let errorPayload: [String: Any] = [
+        "error": "Could not set body!"
+    ]
+
+    var responseString: String = ""
+    var errorString: String = ""
+    do {
+        errorString = try errorPayload.jsonEncodedString()
+    } catch {
+        // Nothing to do here - we already have an empty value
+    }
+
+    do {
+        responseString = try res.jsonEncodedString()
+        response.appendBody(string: responseString)
+    } catch {
+        response.status = HTTPResponseStatus.internalServerError
+        response.appendBody(string: errorString)
+    }
+
+
+    setHeaders(response: response, contentType: "application/json")
+    response.completed()
+}
+
+// Helpers
+
+func setHeaders(response: HTTPResponse, contentType: String) {
+
+    response.setHeader(.contentType, value: contentType)
+    response.setHeader(.custom(name: "Server"), value: "Perfect")
+
+    let currDate: String = getCurrDate()
+
+	response.setHeader(.custom(name: "Date"), value: currDate)
+}
+
+func getCurrDate() -> String {
+
+    let now = getNow()
+
+    do {
+        let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil)
+        return formatted
+    } catch {
+        return "error formatting date string"
+    }
+}
+
+func returnCorrectTuple(queryArr: [(String, String)]) -> String {
+
+    for tup in queryArr {
+        if String(describing: tup.0) == "queries" {
+            return String(describing: tup.1)
+        }
+    }
+
+    return "nil"
+}
+
+func sanitizeQueryValue(queryString: String) -> Int {
+
+    if let queryNum = Int(queryString) {
+
+        if queryNum > 0 && queryNum < 500 {
+            return queryNum
+        } else if queryNum > 500 {
+            return 500
+        } else {
+            return 1
+        }
+    } else {
+        return 1
+    }
+}
+
+func spoofHTML(fortunesArr: [[String: Any]]) -> String {
+
+    var htmlToRet = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>"
+
+    for fortune in fortunesArr {
+
+        htmlToRet += "<tr><td>\(fortune["id"]!)</td><td>\(fortune["message"]!)</td></tr>"
+    }
+
+    htmlToRet += "</table></body></html>";
+
+    return htmlToRet
+}
+
+var routes = Routes()
+routes.add(method: .get, uri: "/fortunes", handler: fortunesHandler)
+routes.add(method: .get, uri: "/updates", handler: updatesHandler)
+routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler)
+routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler)
+routes.add(method: .get, uri: "/**",
+		   handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest)
+try HTTPServer.launch(name: "localhost",
+    port: 8080,
+    routes: routes,
+    responseFilters: [
+    (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)])

+ 226 - 0
frameworks/Swift/perfect/Sources/Perfect-PostgreSQL/main.swift

@@ -0,0 +1,226 @@
+import PerfectHTTP
+import PerfectHTTPServer
+import PerfectLib
+import PerfectPostgreSQL
+import Foundation
+
+let tfbHost = "tfb-database"
+let database = "hello_world"
+let username = "benchmarkdbuser"
+let password = "benchmarkdbpass"
+
+let p = PGConnection()
+let status = p.connectdb("postgresql://\(username):\(password)@\(tfbHost):5432/\(database)")
+
+class LinearCongruntialGenerator {
+ 
+    var state = 0 //seed of 0 by default
+    let a, c, m, shift: Int
+ 
+    init() {
+        self.a = 214013
+        self.c = 2531011
+        self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648
+        self.shift = 16
+    }
+ 
+    func random() -> Int {
+        state = (a * state + c) % m
+        return state >> shift
+    }
+}
+
+let numGenerator = LinearCongruntialGenerator()
+
+func fetchFromWorld(id: String?) -> [String:Any] {
+
+    var returnObj = [String: Any]()
+    var rand:Int = 0
+
+    if id == nil {
+        rand = numGenerator.random() % 10000
+    } else {
+        rand = Int(id!)!
+    }
+
+    let results = p.exec(statement: "select id, randomNumber from world where id = \(rand)")
+
+    returnObj["id"] = results.getFieldString(tupleIndex: 0, fieldIndex: 0)!
+    returnObj["randomNumber"] = results.getFieldString(tupleIndex: 0, fieldIndex: 1)!
+    
+    return returnObj
+}
+
+func updateOneFromWorld() -> [String: Any] {
+
+    var returnObj = [String: Any]()
+    let rand = numGenerator.random() % 10000 + 1
+    let rand2 = numGenerator.random() % 10000 + 1
+
+    let _ = p.exec(statement: "UPDATE world SET randomNumber = \(rand) WHERE id = \(rand2)")
+
+    // let checkIfCorrect = fetchFromWorld(id: String(describing: rand2))
+
+    //The exec statement for update doesn't return the updated values. I used to checkIfCorrect variable to confirm that the updates were taking place.
+    returnObj["id"] = rand2
+    returnObj["randomNumber"] = rand
+
+    return returnObj
+}
+
+func updatesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var updateArr: Array = [[String: Any]]()
+
+    while 0 < totalQueries {
+        updateArr.append(updateOneFromWorld())
+        totalQueries -= 1
+    }
+
+    do {
+
+        response.appendBody(string: try updateArr.jsonEncodedString())
+    } catch {
+
+        response.appendBody(string: String(describing: updateArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let queryStr = returnCorrectTuple(queryArr: request.queryParams)
+    var totalQueries = sanitizeQueryValue(queryString: queryStr)
+
+    var queryArr: Array = [[String: Any]]()
+
+    while 0 < totalQueries {
+
+        queryArr.append(fetchFromWorld(id: nil))
+        totalQueries -= 1
+    }  
+
+    do {
+
+        response.appendBody(string: try queryArr.jsonEncodedString())
+    } catch {
+
+        response.appendBody(string: String(describing: queryArr))
+    }
+
+    setHeaders(response: response, contentType: "application/json")
+
+    response.completed()
+}
+
+func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    let res = fetchFromWorld(id: nil)
+
+    let errorPayload: [String: Any] = [
+        "error": "Could not set body!"
+    ]
+
+    var responseString: String = ""
+    var errorString: String = ""
+    do {
+        errorString = try errorPayload.jsonEncodedString()
+    } catch {
+        // Nothing to do here - we already have an empty value
+    }
+
+    do {
+        responseString = try res.jsonEncodedString()
+        response.appendBody(string: responseString)
+    } catch {
+        response.status = HTTPResponseStatus.internalServerError
+        response.appendBody(string: errorString)
+    }
+
+
+    setHeaders(response: response, contentType: "application/json")
+    response.completed()
+}
+
+// Helpers
+
+func setHeaders(response: HTTPResponse, contentType: String) {
+
+    response.setHeader(.contentType, value: contentType)
+    response.setHeader(.custom(name: "Server"), value: "Perfect")
+
+    let currDate: String = getCurrDate()
+
+	response.setHeader(.custom(name: "Date"), value: currDate)
+}
+
+func getCurrDate() -> String {
+
+    let now = getNow()
+
+    do {
+        let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil)
+        return formatted
+    } catch {
+        return "error formatting date string"
+    }
+}
+
+func returnCorrectTuple(queryArr: [(String, String)]) -> String {
+
+    for tup in queryArr {
+        if String(describing: tup.0) == "queries" {
+            return String(describing: tup.1)
+        }
+    }
+
+    return "nil"
+}
+
+func sanitizeQueryValue(queryString: String) -> Int {
+
+    if let queryNum = Int(queryString) {
+
+        if queryNum > 0 && queryNum < 500 {
+            return queryNum
+        } else if queryNum > 500 {
+            return 500
+        } else {
+            return 1
+        }
+    } else {
+        return 1
+    }
+}
+
+func spoofHTML(fortunesArr: [[String: Any]]) -> String {
+
+    var htmlToRet = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>"
+
+    for fortune in fortunesArr {
+
+        htmlToRet += "<tr><td>\(fortune["id"]!)</td><td>\(fortune["message"]!)</td></tr>"
+    }
+
+    htmlToRet += "</table></body></html>";
+
+    return htmlToRet
+}
+
+var routes = Routes()
+routes.add(method: .get, uri: "/updates", handler: updatesHandler)
+routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler)
+routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler)
+routes.add(method: .get, uri: "/**",
+		   handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest)
+try HTTPServer.launch(name: "localhost",
+    port: 8080,
+    routes: routes,
+    responseFilters: [
+    (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)])

+ 78 - 0
frameworks/Swift/perfect/Sources/Perfect/main.swift

@@ -0,0 +1,78 @@
+import PerfectHTTP
+import PerfectHTTPServer
+import PerfectLib
+import Foundation
+
+func plaintextHandler(request: HTTPRequest, response: HTTPResponse) {
+
+	response.appendBody(string: "Hello, World!")
+
+    setHeaders(response: response, contentType: "text/plain")
+
+	response.completed()
+}
+
+func jsonHandler(request: HTTPRequest, response: HTTPResponse) {
+
+    var helloDictionary: [String: String] = [:]
+    helloDictionary["message"] = "Hello, World!"
+
+    let errorPayload: [String: Any] = [
+        "error": "Could not set body!"
+    ]
+
+    var responseString: String = ""
+    var errorString: String = ""
+    do {
+        errorString = try errorPayload.jsonEncodedString()
+    } catch {
+        // Nothing to do here - we already have an empty value
+    }
+
+    do {
+        responseString = try helloDictionary.jsonEncodedString()
+        response.appendBody(string: responseString)
+    } catch {
+        response.status = HTTPResponseStatus.internalServerError
+        response.appendBody(string: errorString)
+    }
+
+
+    setHeaders(response: response, contentType: "application/json")
+    response.completed()
+}
+
+// Helpers
+
+func setHeaders(response: HTTPResponse, contentType: String) {
+
+    response.setHeader(.contentType, value: contentType)
+    response.setHeader(.custom(name: "Server"), value: "Perfect")
+
+    let currDate: String = getCurrDate()
+
+	response.setHeader(.custom(name: "Date"), value: currDate)
+}
+
+func getCurrDate() -> String {
+
+    let now = getNow()
+
+    do {
+        let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil)
+        return formatted
+    } catch {
+        return "error formatting date string"
+    }
+}
+
+var routes = Routes()
+routes.add(method: .get, uri: "/json", handler: jsonHandler)
+routes.add(method: .get, uri: "/plaintext", handler: plaintextHandler)
+routes.add(method: .get, uri: "/**",
+		   handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest)
+try HTTPServer.launch(name: "localhost",
+    port: 8080,
+    routes: routes,
+    responseFilters: [
+    (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)])

+ 76 - 0
frameworks/Swift/perfect/benchmark_config.json

@@ -0,0 +1,76 @@
+{
+  "framework": "perfect",
+  "tests": [{
+    "default": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "None",
+      "framework": "Perfect",
+      "language": "Swift",
+      "orm": "Raw",
+      "platform": "Perfect",
+      "webserver": "Perfect",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Perfect",
+      "notes": ""
+    },
+    "mysql": {
+      "update_url": "/updates?queries=",
+      "query_url": "/queries?queries=",
+      "db_url": "/db",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "Perfect",
+      "language": "Swift",
+      "orm": "Raw",
+      "platform": "Perfect",
+      "webserver": "Perfect",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Perfect",
+      "notes": ""
+    },
+    "postgresql": {
+      "update_url": "/updates?queries=",
+      "query_url": "/queries?queries=",
+      "db_url": "/db",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "Perfect",
+      "language": "Swift",
+      "orm": "Raw",
+      "platform": "Perfect",
+      "webserver": "Perfect",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Perfect",
+      "notes": ""
+    },
+    "mongodb": {
+      "update_url": "/updates?queries=",
+      "query_url": "/queries?queries=",
+      "db_url": "/db",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MongoDB",
+      "framework": "Perfect",
+      "language": "Swift",
+      "orm": "Raw",
+      "platform": "Perfect",
+      "webserver": "Perfect",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Perfect",
+      "notes": ""
+    }
+  }]
+}

+ 7 - 0
frameworks/Swift/perfect/perfect-mongodb.dockerfile

@@ -0,0 +1,7 @@
+FROM swift:4.1
+
+ADD . /perfect
+WORKDIR /perfect
+RUN apt update -yqq && apt install -yqq libpq-dev && apt install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0
+RUN swift build
+CMD .build/debug/Perfect-MongoDB

+ 7 - 0
frameworks/Swift/perfect/perfect-mysql.dockerfile

@@ -0,0 +1,7 @@
+FROM swift:4.1
+
+ADD . /perfect
+WORKDIR /perfect
+RUN apt update -yqq && apt install -yqq libpq-dev && apt install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0
+RUN swift build
+CMD .build/debug/Perfect-MySQL

+ 7 - 0
frameworks/Swift/perfect/perfect-postgresql.dockerfile

@@ -0,0 +1,7 @@
+FROM swift:4.1
+
+ADD . /perfect
+WORKDIR /perfect
+RUN apt update -yqq && apt install -yqq libpq-dev && apt install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0
+RUN swift build
+CMD .build/debug/Perfect-PostgreSQL

+ 7 - 0
frameworks/Swift/perfect/perfect.dockerfile

@@ -0,0 +1,7 @@
+FROM swift:4.1
+
+ADD . /perfect
+WORKDIR /perfect
+RUN apt update -yqq && apt install -yqq libpq-dev && apt install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0
+RUN swift build
+CMD .build/debug/Perfect