With the typical Apple understatement, Craig Federighi defined Swift as "how really everyone should be programming for the next 20 years".
Is it true? Is it convenient? Is it safe? Is it fun?
In this talk, we'll see what happened since Swift was released, and then OpenSourced, presenting pros and cons of using it as Server Side programming language.
We'll see the major web frameworks in the Swift ecosystem, similarities and differences, and finally, we'll tinker with two "real world" Swift on Linux apps.
93. Let's make it run
// main.swift
import Foundation
import HTTP
import Vapor
let wheaterUndergroundKey = "KEY"
let wheaterUndergroundDomain = "api.wunderground.com"
let drop = Droplet()
drop.get("/hello") { _ in
return "Hello World"
}
drop.run()
94. $ swift build
> Cloning https://github.com/vapor/vapor.git
> HEAD is now at 453f7cf Merge pull request #628
> Resolved version: 1.0.3
> Cloning https://github.com/vapor/crypto.git
> HEAD is now at 0aaa68b Merge pull request #15
> Resolved version: 1.0.1
> Cloning https://github.com/vapor/core.git
....
....
> Compile Swift Module 'TypeSafeRouting' (3 sources)
> Compile Swift Module 'Vapor' (83 sources)
> Compile Swift Module 'MrDrizzleServer' (1 sources)
> Linking ./.build/debug/MrDrizzleServer
$ .build/debug/MrDrizzleServer
95. > Could not load localization files
> No cipher key was set, using blank key.
> Chacha20 cipher requires an initialization
> No command supplied, defaulting to serve
> No preparations.
> No servers.json configuration found.
> Starting server at 0.0.0.0:8080
96.
97.
98. $ swift package generate-xcodeproj
> generated: ./MrDrizzleServer.xcodeproj
104. The list of the stations:
struct StationInfo {
let name: String
let stationId: String
let lat: Float
let lon: Float
}
let stationsInfo = [
StationInfo(name: "Chelsea",
stationId: "ILONDON330",
lat: 51.479633, lon:-0.180277),
StationInfo(name: "Westminster",
stationId: "ILONDON120",
lat: 51.65343, lon:-0.183732)
//...
]
106. Model schema in pseudocode
object Stations {
Array of Station stations
}
object Station {
string id
float lat
float lon
string name
Array of HourlyMeasure measures
}
object HourlyMeasure {
int32 hour
float temp_f
float temp_c
}
110. Given this:
syntax = "proto3";
message Stations {
repeated Station stations = 1;
}
message Station {
string id = 1;
float lat = 2;
float lon = 3;
string name = 4;
repeated HourlyMeasure measures = 5;
}
message HourlyMeasure {
int32 hour = 1;
float temp_f = 2;
float temp_c = 3;
}
111. /*
* DO NOT EDIT.
*
* Generated by the protocol buffer compiler.
* Source: mrdrizzle.proto
*
*/
public struct Stations: ProtobufGeneratedMessage {
public var swiftClassName: String {return "Stations"}
public var protoMessageName: String {return "Stations"}
public var protoPackageName: String {return ""}
//...
}
public struct Station: ProtobufGeneratedMessage {
public var swiftClassName: String {return "Station"}
public var protoMessageName: String {return "Station"}
public var protoPackageName: String {return ""}
//...
}
public struct HourlyMeasure: ProtobufGeneratedMessage {
public var swiftClassName: String {return "HourlyMeasure"}
public var protoMessageName: String {return "HourlyMeasure"}
public var protoPackageName: String {return ""}
//...
}
112. We extend these structs to
instantiate from the
wunderground JSON
126. struct Resource<A> {
let url: URL
let parse: (Data) -> A?
}
for example:
let url = URL(string: "http://mrdrizzle.com:8080/hello")!
let helloResource = Resource<String>(url: url, parse: { data in
return String(data: data, encoding: .utf8)
})
127. class ApiService {
func load<A>(resource: Resource<A>, completion: @escaping (A?) -> ()) {
URLSession.shared.dataTask(with: resource.url) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let data = data
else {
completion(nil)
return
}
completion(resource.parse(data))
}.resume()
}
}
128. let url = URL(string: "http://mrdrizzle.com:8080/hello")!
let helloResource = Resource<String>(url: url) { data in
return String(data: data, encoding: .utf8)
}
ApiService().load(resource: helloResource) {
guard let hello = $0 else {
print("ERROR - Hello")
return
}
print(hello)
}
129. let url = URL(string: "http://mrdrizzle.com:8080/hello")!
let stationResources = Resource<Stations>(url: url) { data in
return try? Stations(protobuf: data)
}
ApiService().load(resource: stationResources) {
guard let stations = $0 else {
print("ERROR - Stations")
return
}
print(stations)
}
157. // main.swift
import Foundation
import Vapor
import HTTP
let PAGE_ACCESS_TOKEN = "STUFF"
let fbURL = "https://graph.facebook.com/v2.6/me/messages?access_token=" +
PAGE_ACCESS_TOKEN
let uncleLucio = UncleLucio(jokesDB: JokesDB())
let drop = Droplet()
175. class JokesDB {
private let jokes: [Joke] = [
("Harry", "Harry up and let me in!"),
("Wanda", "Wanda hang out with me right now?"),
("Olive", "Olive you and I don’t care who knows it!"),
("Ho-ho", "You know, your Santa impression could use a little work."),
("Hanna", "...Hanna partridge in a pear tree!"),
("Mary and Abbey", "Mary Christmas and Abbey New Year!"),
("Irish", "Irish you a Merry Christmas!"),
("Yule log", "Yule log the door after you let me in, won’t you?"),
("Ya", "I’m excited to see you too!"),
("Sherlock", "Sherlock your door shut tight!"),
("Scold", "Scold outside—let me in!"),
("Robin", "Robin you! Hand over your cash!"),
("Needle", "Needle little help gettin’ in the door."),
("Nana", "Nana your business who’s there."),
("Luke", "Luke through the keyhole to see!"),
("Isabelle", "Isabelle working, or should I keep knocking?"),
].map {
Joke(subject: $0.0,
punchline: $0.1)
}
func randomJoke() -> Joke {
return jokes.randomItem()
}
}
176. extension Array {
func randomItem() -> Element {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}