Top Banner
Swift on the Server State of the Union Chris Bailey @Chris__Bailey
90

Swift Summit 2017: Server Swift State of the Union

Jan 22, 2018

Download

Software

Chris Bailey
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Swift Summit 2017: Server Swift State of the Union

Swift on the ServerState of the Union

Chris Bailey@Chris__Bailey

Page 2: Swift Summit 2017: Server Swift State of the Union

30-10-201707-1 1-201607-1 1-2016

Page 3: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

Page 4: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

Page 5: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

Page 6: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

Page 7: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

Page 8: Swift Summit 2017: Server Swift State of the Union

Swift 3.0

IBM Cloud

Page 9: Swift Summit 2017: Server Swift State of the Union
Page 10: Swift Summit 2017: Server Swift State of the Union
Page 11: Swift Summit 2017: Server Swift State of the Union

IBM Cloud

DRINKS

SOAKSCOVE

RS

Page 12: Swift Summit 2017: Server Swift State of the Union

Server API Workgroup

Page 13: Swift Summit 2017: Server Swift State of the Union

0.1.0: Draft HTTP Server API

Page 14: Swift Summit 2017: Server Swift State of the Union

import Foundationimport HTTP

func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing { response.writeHeader(status: .ok) response.writeBody("Hello, World!") response.done() return .discardBody}

let server = HTTPServer()try! server.start(port: 8080, handler: hello)

RunLoop.current.run()

0.1.0: Draft HTTP Server API

Page 15: Swift Summit 2017: Server Swift State of the Union

import Foundationimport HTTP

func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing { response.writeHeader(status: .ok) response.writeBody("Hello, World!") response.done() return .discardBody}

let server = HTTPServer()try! server.start(port: 8080, handler: hello)

RunLoop.current.run()

0.1.x: Draft HTTP Server API

0.2.x: Draft TLS support for HTTPS

Page 16: Swift Summit 2017: Server Swift State of the Union

import Foundationimport HTTP

func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing { response.writeHeader(status: .ok) response.writeBody("Hello, World!") response.done() return .discardBody}

let server = HTTPServer()try! server.start(port: 8080, handler: hello)

RunLoop.current.run()

0.1.x: Draft HTTP Server API

0.2.x: Draft TLS support for HTTPS

Page 17: Swift Summit 2017: Server Swift State of the Union

We need to talk About Foundation

Page 18: Swift Summit 2017: Server Swift State of the Union

0

20

40

60

80

100 Foundation: • ~1,700 APIs

Page 19: Swift Summit 2017: Server Swift State of the Union

0

20

40

60

80

100 Foundation: • ~1,700 APIs

Used on GitHub in: • 39.7% of all Obj-C files that import

Page 20: Swift Summit 2017: Server Swift State of the Union

0

20

40

60

80

100 Foundation: • ~1,700 APIs

Used on GitHub in: • 39.7% of all Obj-C files that import

• 90.7% of all Swift files that import

Page 21: Swift Summit 2017: Server Swift State of the Union

0

20

40

60

80

100

Open Source

Page 22: Swift Summit 2017: Server Swift State of the Union

0

20

40

60

80

100

Open Source

Swift 3.0

Page 23: Swift Summit 2017: Server Swift State of the Union

Sho Ikeda@ikesyo

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Simon Evans @spevans

Sergey Minakov @naithar

0

20

40

60

80

100

Open Source

Swift 3.0

Page 24: Swift Summit 2017: Server Swift State of the Union

Sho Ikeda@ikesyo

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Simon Evans @spevans

Sergey Minakov @naithar

0

20

40

60

80

100

Open Source

Swift 3.0

Page 25: Swift Summit 2017: Server Swift State of the Union

Sho Ikeda@ikesyo

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Simon Evans @spevans

Sergey Minakov @naithar

0

20

40

60

80

100

Open Source

Swift 3.0

Page 26: Swift Summit 2017: Server Swift State of the Union

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Simon Evans @spevans

Sergey Minakov @naithar

0

20

40

60

80

100

Sho Ikeda@ikesyo

Open Source

Swift 3.0

Page 27: Swift Summit 2017: Server Swift State of the Union

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Sergey Minakov @naithar

0

20

40

60

80

100

Sho Ikeda@ikesyo

Simon Evans @spevans

Open Source

Swift 3.0

Page 28: Swift Summit 2017: Server Swift State of the Union

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Sergey Minakov @naithar

0

20

40

60

80

100

Sho Ikeda@ikesyo

Simon Evans @spevans

Bartek Chlebek @bubski

Open Source

Swift 3.0

Page 29: Swift Summit 2017: Server Swift State of the Union

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

0

20

40

60

80

100

Sho Ikeda@ikesyo

Simon Evans @spevans

Bartek Chlebek @bubski

Sergey Minakov @naithar

Open Source

Swift 3.0

Page 30: Swift Summit 2017: Server Swift State of the Union

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

0

20

40

60

80

100

Sho Ikeda@ikesyo

Simon Evans @spevans

Bartek Chlebek @bubski

Sergey Minakov @naithar

Mamatha Busi @mamabusi

Nethra Ravindran @nethraravindran

Open Source

Swift 3.0

Page 31: Swift Summit 2017: Server Swift State of the Union

Sho Ikeda@ikesyo

Ian Partridge @ianpartridge

Pushkar N Kulkarni @pushkarnk

Bartek Chlebek @bubski

David Dunn @ddunn2

John Holdsworth @johnno1962

Philippe Hausler @phausler

Alex Blewitt @alblue

Simon Evans @spevans

Sergey Minakov @naithar

0

20

40

60

80

100

Mamatha Busi @mamabusi

Nethra Ravindran @nethraravindran

Open Source

Swift 3.0

Today

Page 32: Swift Summit 2017: Server Swift State of the Union

Commercial Support for Swift on Linux

from

Page 33: Swift Summit 2017: Server Swift State of the Union

Commercial Support for Swift on Linux

from

Page 34: Swift Summit 2017: Server Swift State of the Union

Commercial Support for Swift on Linux

IBM Cloud

from

Page 35: Swift Summit 2017: Server Swift State of the Union

Commercial Support for Kitura Ecosystem

from

Page 36: Swift Summit 2017: Server Swift State of the Union

Commercial Support for Kitura Ecosystem

from

IBM Cloud

Page 37: Swift Summit 2017: Server Swift State of the Union

07-1 1-2016

Page 38: Swift Summit 2017: Server Swift State of the Union

“Software interop is hard” —Rocket Scientists

Page 39: Swift Summit 2017: Server Swift State of the Union
Page 40: Swift Summit 2017: Server Swift State of the Union

Deploy Deploy

Page 41: Swift Summit 2017: Server Swift State of the Union

Deploy DeployGenerate

Page 42: Swift Summit 2017: Server Swift State of the Union
Page 43: Swift Summit 2017: Server Swift State of the Union
Page 44: Swift Summit 2017: Server Swift State of the Union
Page 45: Swift Summit 2017: Server Swift State of the Union
Page 46: Swift Summit 2017: Server Swift State of the Union
Page 47: Swift Summit 2017: Server Swift State of the Union
Page 48: Swift Summit 2017: Server Swift State of the Union

{ "name": "", "photo": "", "dateOfBirth": ""}

{ "name": "", "photo": "", "dateOfBirth": { "year": "month": "day": }}

struct Profile { var name: String var photo: Data var dateOfBirth: Date}

Swift

var profile: [String : Any]

Swift

Page 49: Swift Summit 2017: Server Swift State of the Union

Codable

Page 50: Swift Summit 2017: Server Swift State of the Union

let json = JSON(data: data) guard json["name"].exists() else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Missing reqired property `name`" ])) next() } guard let name = json["name"].string else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Type mismatch, `name` expected to be a String" ])) next() } guard json["photo"].exists() else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Missing reqired property photo`" ])) next() } guard let photoString = json[“photo"].string else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Type mismatch, `photo` expected to be a String" ])) next() } guard let photo = Data(base64Encoded: photoString) else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Type mismatch, `photo` expected to be Base64 encoded data" ])) next() } let profile = Profile(name: name, photo: photo)

Page 51: Swift Summit 2017: Server Swift State of the Union

var profile: Profile do { var data = Data() _ = try request.read(into: &data) profile = try JSONDecoder().decode(Profile.Type, from: data) } catch let error { response.status(.unprocessableEntity) response.send(try JSONEncoder().encode(error)) next() }

Page 52: Swift Summit 2017: Server Swift State of the Union

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(try JSONEncoder().encode(error)) next() }

Page 53: Swift Summit 2017: Server Swift State of the Union

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() }

Page 54: Swift Summit 2017: Server Swift State of the Union

router.post,(“/profile", handler: storeProfile)

func storeProfile(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) { guard let contentType = request.headers["Content-Type"], contentType.hasPrefix("application/json") else { response.status(.unsupportedMediaType) response.send(error) return next() }

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() } ... }

Page 55: Swift Summit 2017: Server Swift State of the Union

router.post,(“/profile", handler: storeProfile)

func storeProfile(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) { guard let contentType = request.headers["Content-Type"], contentType.hasPrefix("application/json") else { response.status(.unsupportedMediaType) response.send(error) return next() }

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() } ... }

Web Request

Page 56: Swift Summit 2017: Server Swift State of the Union

router.post,(“/profile", handler: storeProfile)

func storeProfile(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) { guard let contentType = request.headers["Content-Type"], contentType.hasPrefix("application/json") else { response.status(.unsupportedMediaType) response.send(error) return next() }

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() } ... }

Web RequestWeb Response

Page 57: Swift Summit 2017: Server Swift State of the Union

router.post,(“/profile", handler: storeProfile)

func storeProfile(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) { guard let contentType = request.headers["Content-Type"], contentType.hasPrefix("application/json") else { response.status(.unsupportedMediaType) response.send(error) return next() }

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() } ... }

Web RequestWeb Response

Next ??

Page 58: Swift Summit 2017: Server Swift State of the Union

router.post,(“/profile", handler: storeProfile)

func storeProfile(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) { guard let contentType = request.headers["Content-Type"], contentType.hasPrefix("application/json") else { response.status(.unsupportedMediaType) response.send(error) return next() }

var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() } ... }

Web RequestWeb Response

Next ??

Validate and Convert parameters

3/10

Page 59: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Page 60: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type

Page 61: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type

Completion Handler

Page 62: Swift Summit 2017: Server Swift State of the Union

Codable Routing

Page 63: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Page 64: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type (Codable)

Page 65: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type (Codable)

Swift Type (RequestError)

Page 66: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func get(profile id: Int, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type (Codable)

Swift Type (RequestError)

Page 67: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func get(profile id: Int, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

Swift Type (Codable)

Swift Type (Identifier)

Swift Type (RequestError)

Page 68: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func get(profile id: Int, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func delete(profile id: Int, respondWith: @escaping (Error?) -> Void) -> Void {

... }

Swift Type (Codable)

Swift Type (Identifier)

Swift Type (RequestError)

Page 69: Swift Summit 2017: Server Swift State of the Union

func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func get(profile id: Int, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {

... }

func delete(profile id: Int, respondWith: @escaping (Error?) -> Void) -> Void {

... }

router.post("/profile", handler: store)router.get("/profile", handler: get)router.delete("/profile", handler: delete)

Swift Type (Codable)

Swift Type (Identifier)

Swift Type (RequestError)

Page 70: Swift Summit 2017: Server Swift State of the Union

Deploy Deploy

Page 71: Swift Summit 2017: Server Swift State of the Union

Deploy Deploy

Client/Server Contract

Page 72: Swift Summit 2017: Server Swift State of the Union

KituraKit

Page 73: Swift Summit 2017: Server Swift State of the Union

guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return}

Page 74: Swift Summit 2017: Server Swift State of the Union

guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return}

backend.post("/profile", data: profile) { (profile: Profile?, error: RequestError?) in ...

}

Page 75: Swift Summit 2017: Server Swift State of the Union

guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return}

backend.post("/profile", data: profile) { (profile: Profile?, error: RequestError?) in ...

} Swift Type (Codable)

Page 76: Swift Summit 2017: Server Swift State of the Union

guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return}

backend.post("/profile", data: profile) { (profile: Profile?, error: RequestError?) in ...

} Swift Type (Codable)

Swift Type (RequestError)

Page 77: Swift Summit 2017: Server Swift State of the Union

Kitura 2.0

Page 78: Swift Summit 2017: Server Swift State of the Union

The Future

Page 79: Swift Summit 2017: Server Swift State of the Union

Optimized Transports

Page 80: Swift Summit 2017: Server Swift State of the Union

Optimized Transports Implicit Security

Page 81: Swift Summit 2017: Server Swift State of the Union

Optimized Transports Implicit Security

User Domains

Page 82: Swift Summit 2017: Server Swift State of the Union

API Protocols

Optimized Transports Implicit Security

User Domains

Page 83: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

Client/Server Contract

Client Server

Page 84: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

Client/Server Contract

Client Server

Page 85: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

class ToDoBackend: APIController, ToDoAPI { func store(_ item: ToDoItem, completion: …) { } func get(_ id: Int, completion: …) { } func update(_ id: Int, _ item: ToDoItem completion: …) { } func index(completion: …) { } func delete(_ id: Int, completion: …) { } }

router.registerAPI(api: ToDo())

Client/Server Contract

Client Server

Page 86: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

class ToDoBackend: APIController, ToDoAPI { func store(_ item: ToDoItem, completion: …) { } func get(_ id: Int, completion: …) { } func update(_ id: Int, _ item: ToDoItem completion: …) { } func index(completion: …) { } func delete(_ id: Int, completion: …) { } }

router.registerAPI(api: ToDo())

Client/Server Contract

Client Server

User provided implementation

Page 87: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

class ToDoBackend: APIController, ToDoAPI {

}

class ToDoBackend: APIController, ToDoAPI { func store(_ item: ToDoItem, completion: …) { } func get(_ id: Int, completion: …) { } func update(_ id: Int, _ item: ToDoItem completion: …) { } func index(completion: …) { } func delete(_ id: Int, completion: …) { } }

router.registerAPI(api: ToDo())

Client/Server Contract

Client Server

User provided implementation

Page 88: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

class ToDoBackend: APIController, ToDoAPI {

}

class ToDoBackend: APIController, ToDoAPI { func store(_ item: ToDoItem, completion: …) { } func get(_ id: Int, completion: …) { } func update(_ id: Int, _ item: ToDoItem completion: …) { } func index(completion: …) { } func delete(_ id: Int, completion: …) { } }

router.registerAPI(api: ToDo())

Client/Server Contract

KituraKit provides implementation

Client Server

User provided implementation

Page 89: Swift Summit 2017: Server Swift State of the Union

public struct ToDoItem : Codable { public var user: String public var title: String public var order: Int public var completed: Bool}

public protocol todoStoreAPI: Store, Get, Update, Index, Delete { typealias In, Out = ToDoItem typealias Id = Int}

class ToDoBackend: APIController, ToDoAPI {

}

let backend = ToDoBackend()

backend.store(data: item) { id?, created?, error? in print(id!)}backend.get(id: id) { todo, err in print(todo!.title)}

class ToDoBackend: APIController, ToDoAPI { func store(_ item: ToDoItem, completion: …) { } func get(_ id: Int, completion: …) { } func update(_ id: Int, _ item: ToDoItem completion: …) { } func index(completion: …) { } func delete(_ id: Int, completion: …) { } }

router.registerAPI(api: ToDo())

Client/Server Contract

KituraKit provides implementation

Client Server

User provided implementation

Page 90: Swift Summit 2017: Server Swift State of the Union

Swift on the ServerThe Future, available Today