Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Swift on the Server
State of the Union
Chris Bailey
@Chris__Bailey
30-10-201707-1 1-201607-1 1-2016
Swift 3.0
Swift 3.0
Swift 3.0
Swift 3.0
Swift 3.0
Swift 3.0
IBM Cloud
IBM Cloud
DRINKS
SOAKS
COVERS
Server API
Workgroup
0.1.0: Draft HTTP Server API
import Foundation
import HTTP
func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing {
resp...
import Foundation
import HTTP
func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing {
resp...
import Foundation
import HTTP
func hello(request: HTTPRequest, response: HTTPResponseWriter ) -> HTTPBodyProcessing {
resp...
We need to talk
About Foundation
0
20
40
60
80
100
Foundation:
• ~1,700 APIs
0
20
40
60
80
100
Foundation:
• ~1,700 APIs

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

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...
0
20
40
60
80
100
Open Source
0
20
40
60
80
100
Open Source
Swift 3.0
Sho Ikeda

@ikesyo
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
Joh...
Sho Ikeda

@ikesyo
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
Joh...
Sho Ikeda

@ikesyo
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
Joh...
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
John Holdsworth
@johnn...
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
John Holdsworth
@johnn...
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
David Dunn
@ddunn2
John Holdsworth
@johnno1962
Philippe Hausler
...
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
David Dunn
@ddunn2
John Holdsworth
@johnno1962
Philippe Hausler
...
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
David Dunn
@ddunn2
John Holdsworth
@johnno1962
Philippe Hausler
...
Sho Ikeda

@ikesyo
Ian Partridge
@ianpartridge
Pushkar N Kulkarni
@pushkarnk
Bartek Chlebek
@bubski
David Dunn
@ddunn2
Joh...
Commercial Support
for Swift on Linuxfrom
Commercial Support
for Swift on Linuxfrom
Commercial Support
for Swift on Linux
IBM Cloud
from
Commercial Support
for Kitura Ecosystemfrom
Commercial Support
for Kitura Ecosystemfrom
IBM Cloud
07-1 1-2016
“Software interop is hard”
—Rocket Scientists
Deploy Deploy
Deploy DeployGenerate
{
"name": "",
"photo": "",
"dateOfBirth": ""
}
{
"name": "",
"photo": "",
"dateOfBirth": {
"year":
"month":
"day":
}
}
str...
Codable
let json = JSON(data: data)

guard json["name"].exists() else {
response.status(.unprocessableEntity)
response.send(json: ...
var profile: Profile
do {
var data = Data()
_ = try request.read(into: &data)
profile = try JSONDecoder().decode(Profile.T...
var profile: Profile
do {
profile = try request.read(as: Profile.self)
} catch let error {
response.status(.unprocessableE...
var profile: Profile
do {
profile = try request.read(as: Profile.self)
} catch let error {
response.status(.unprocessableE...
router.post,(“/profile", handler: storeProfile)
func storeProfile(request: RouterRequest, response: RouterResponse, next: ...
router.post,(“/profile", handler: storeProfile)
func storeProfile(request: RouterRequest, response: RouterResponse, next: ...
router.post,(“/profile", handler: storeProfile)
func storeProfile(request: RouterRequest, response: RouterResponse, next: ...
router.post,(“/profile", handler: storeProfile)
func storeProfile(request: RouterRequest, response: RouterResponse, next: ...
router.post,(“/profile", handler: storeProfile)
func storeProfile(request: RouterRequest, response: RouterResponse, next: ...
func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void
{

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

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

...
}
Swift Type
Completion
Han...
Codable Routing
func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void
{

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

...
}
Swift Type
(Codable)
func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void
{

...
}
Swift Type
(Codable)
Swif...
func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void
{

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

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

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

...
}
func get(profile id: Int,...
Deploy Deploy
Deploy Deploy
Client/Server
Contract
KituraKit
guard let backend = KituraKit(baseURL: "http://localhost:8080") else {
print("Error creating KituraKit client")
return
}
guard let backend = KituraKit(baseURL: "http://localhost:8080") else {
print("Error creating KituraKit client")
return
}
b...
guard let backend = KituraKit(baseURL: "http://localhost:8080") else {
print("Error creating KituraKit client")
return
}
b...
guard let backend = KituraKit(baseURL: "http://localhost:8080") else {
print("Error creating KituraKit client")
return
}
b...
Kitura 2.0
The Future
Optimized Transports
Optimized Transports Implicit Security
Optimized Transports Implicit Security
User Domains
API Protocols
Optimized Transports Implicit Security
User Domains
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
public struct ToDoItem : Codable {
public var user: String
public var title: String
public var order: Int
public var compl...
Swift on the Server
The Future, available Today
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
Upcoming SlideShare
Loading in …5
×

Swift Summit 2017: Server Swift State of the Union

862 views

Published on

Server Swift has come a long way in the last 12 months, reaching a point where there are multiple successful frameworks and clouds. This session reviews the last year, announces some new capabilities, and outlines some of what to expect in the (near) future.

Published in: Software
  • Be the first to comment

Swift Summit 2017: Server Swift State of the Union

  1. 1. Swift on the Server State of the Union Chris Bailey @Chris__Bailey
  2. 2. 30-10-201707-1 1-201607-1 1-2016
  3. 3. Swift 3.0
  4. 4. Swift 3.0
  5. 5. Swift 3.0
  6. 6. Swift 3.0
  7. 7. Swift 3.0
  8. 8. Swift 3.0 IBM Cloud
  9. 9. IBM Cloud DRINKS SOAKS COVERS
  10. 10. Server API Workgroup
  11. 11. 0.1.0: Draft HTTP Server API
  12. 12. import Foundation import 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
  13. 13. import Foundation import 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
  14. 14. import Foundation import 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
  15. 15. We need to talk About Foundation
  16. 16. 0 20 40 60 80 100 Foundation: • ~1,700 APIs
  17. 17. 0 20 40 60 80 100 Foundation: • ~1,700 APIs
 Used on GitHub in: • 39.7% of all Obj-C files that import

  18. 18. 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
  19. 19. 0 20 40 60 80 100 Open Source
  20. 20. 0 20 40 60 80 100 Open Source Swift 3.0
  21. 21. 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
  22. 22. 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
  23. 23. 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
  24. 24. 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
  25. 25. 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
  26. 26. 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
  27. 27. 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
  28. 28. 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
  29. 29. 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
  30. 30. Commercial Support for Swift on Linuxfrom
  31. 31. Commercial Support for Swift on Linuxfrom
  32. 32. Commercial Support for Swift on Linux IBM Cloud from
  33. 33. Commercial Support for Kitura Ecosystemfrom
  34. 34. Commercial Support for Kitura Ecosystemfrom IBM Cloud
  35. 35. 07-1 1-2016
  36. 36. “Software interop is hard” —Rocket Scientists
  37. 37. Deploy Deploy
  38. 38. Deploy DeployGenerate
  39. 39. { "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
  40. 40. Codable
  41. 41. 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)
  42. 42. 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() }
  43. 43. var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(try JSONEncoder().encode(error)) next() }
  44. 44. var profile: Profile do { profile = try request.read(as: Profile.self) } catch let error { response.status(.unprocessableEntity) response.send(error) next() }
  45. 45. 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() } ... }
  46. 46. 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
  47. 47. 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 Web Response
  48. 48. 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 Web Response Next ??
  49. 49. 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 Web Response Next ?? Validate and Convert parameters 3/10
  50. 50. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... }
  51. 51. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... } Swift Type
  52. 52. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... } Swift Type Completion Handler
  53. 53. Codable Routing
  54. 54. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... }
  55. 55. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... } Swift Type (Codable)
  56. 56. func store(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void {
 ... } Swift Type (Codable) Swift Type (RequestError)
  57. 57. 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)
  58. 58. 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)
  59. 59. 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)
  60. 60. 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)
  61. 61. Deploy Deploy
  62. 62. Deploy Deploy Client/Server Contract
  63. 63. KituraKit
  64. 64. guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return }
  65. 65. 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 ... }
  66. 66. 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)
  67. 67. 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)
  68. 68. Kitura 2.0
  69. 69. The Future
  70. 70. Optimized Transports
  71. 71. Optimized Transports Implicit Security
  72. 72. Optimized Transports Implicit Security User Domains
  73. 73. API Protocols Optimized Transports Implicit Security User Domains
  74. 74. 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
  75. 75. 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
  76. 76. 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
  77. 77. 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
  78. 78. 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
  79. 79. 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
  80. 80. 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
  81. 81. Swift on the Server The Future, available Today

×