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 Cloud Workshop - Codable, the key to Fullstack Swift

335 views

Published on

Codable, introduced in Swift 4, makes is possible to share Swift classes and structs between client and server, making it easy to share data. It can also be used to add such more type safety to other parts of Fullstack Swift. This presentations shows some of the many ways that Codable is being using in Kitura to enable Fullstack Swift.

Published in: Software
  • Be the first to comment

Swift Cloud Workshop - Codable, the key to Fullstack Swift

  1. 1. Codable
 The key to Fullstack Swift Swift Cloud Workshop 3
 February 23rd, 2018 Chris Bailey
 (@Chris__Bailey)
  2. 2. Codable
  3. 3. struct Profile { var name: String var photo: Data var dateOfBirth: Date } let profile = Profile(name: “Chris”, photo: image, dateOfBirth: Date(“06-06-1980”))
  4. 4. struct Profile : Codable { var name: String var photo: Data var dateOfBirth: Date } let profile = Profile(name: “Chris”, photo: image, dateOfBirth: Date(“06-06-1980”))
  5. 5. struct Profile : Codable { var name: String var photo: Data var dateOfBirth: Date } let profile = Profile(name: “Chris”, photo: image, dateOfBirth: Date(“06-06-1980”)) let encoder = JSONEncoder() let jsonData = try encoder.encode(profile)
  6. 6. struct Profile : Codable { var name: String var photo: Data var dateOfBirth: Date } let profile = Profile(name: “Chris”, photo: image, dateOfBirth: Date(“06-06-1980”)) let encoder = JSONEncoder() let jsonData = try encoder.encode(profile) let decoder = JSONDecoder() let person = try decoder.decode(Profile.self, from: jsonData)
  7. 7. Fullstack
 Development
  8. 8. { "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 KITURA
  9. 9. let profile = Profile(name: name, photo: photo)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 photo = Data(base64Encoded: photoString) else { response.status(.unprocessableEntity) response.send(json: JSON([ "error": "Type mismatch, `photo` expected to be Base64 encoded data" ])) 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() }
  10. 10. struct Profile { var name: String var photo: Data var dateOfBirth: Date } Swift
  11. 11. struct Profile { var name: String var photo: Data var dateOfBirth: Date } Swift Swift KITURA
  12. 12. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift KITURA
  13. 13. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } KITURA
  14. 14. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } let encoder = JSONEncoder() let data = try encoder.encode(profile) KITURA
  15. 15. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } let decoder = JSONDecoder() let person = try decoder.decode(Person.self, from: jsonData) KITURA
  16. 16. { "name": "", "photo": "", "dateOfBirth": "" } { "name": "", "photo": "", "dateOfBirth": "" } struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } KITURA
  17. 17. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } KITURA
  18. 18. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } KITURA
  19. 19. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } Swift Swift struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } KITURA
  20. 20. Under the Hood
  21. 21. struct Profile { var name: String var photo: Data var dateOfBirth: Date }
  22. 22. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date }
  23. 23. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 

  24. 24. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Decodable { init(from decoder: Decoder) throws { } }
  25. 25. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Decodable { init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self)
 } }
  26. 26. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Decodable { init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self)
 name = try values.decode(String.self, forKey: .name) } }
  27. 27. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Decodable { init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self)
 name = try values.decode(String.self, forKey: .name) photo = try values.decode(Data.self, forKey: .photo) } }
  28. 28. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Decodable { init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self)
 name = try values.decode(String.self, forKey: .name) photo = try values.decode(Data.self, forKey: .photo) dateOfBirth = try values.decode(Date.self, forKey: .dateOfBirth) } }
  29. 29. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Encodable { func encode(to encoder: Encoder) throws { } }
  30. 30. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Encodable { func encode(to encoder: Encoder) throws { var container = try encoder.container(keyedBy: CodingKeys.self)
 } }
  31. 31. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } extension Profile { enum CodingKeys: String, CodingKey { case name = "name"
 case photo = "photo" case dateOfBirth = "dateOfBirth" } }
 
 extension Profile : Encodable { func encode(to encoder: Encoder) throws { var container = try encoder.container(keyedBy: CodingKeys.self)
 try container.encode(name, forKey: .name) try container.encode(photo, forKey: .photo) try container.encode(dateOfBirth, forKey: .dateOfBirth) } }
  32. 32. Body Data
  33. 33. { "name": "John Doe", "photo": "jbbkj362", "dateOfBirth": "06-06-1980“ }
  34. 34. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date }
  35. 35. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles)
  36. 36. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(request: RouterRequest, response: RouterResponse, next: () -> Void) -> Void { }
  37. 37. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(request: RouterRequest, response: RouterResponse, next: () -> Void) -> Void { var profile = request.read(as: Profile.Type) }
  38. 38. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { }
  39. 39. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  40. 40. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) router.post("/profile", handler: addProfile) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  41. 41. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) router.post("/profile", handler: addProfile) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) } func addProfile(profile: Profile, respondWith: @escaping (Profile?, Error?) -> Void) -> Void { ... respondWith(profile, nil) }
  42. 42. guard let backend = KituraKit(baseURL: "http://localhost:8080") else { print("Error creating KituraKit client") return } backend.get("/profile") { (profiles: [Profile]?, error: RequestError?) in ... } KITURAKIT
  43. 43. Query Parameters
  44. 44. GET: /profile?name=“John Doe”#
  45. 45. { "name": "John Doe", "photo": "jbbkj362", "dateOfBirth": "06-06-1980“ }
  46. 46. {"name": "John Doe","photo": "jbbkj362","dateOfBirth": "06-06-1980"}
  47. 47. {"name": "John Doe" }
  48. 48. {"name": "John Doe"}
  49. 49. {“name"= "John Doe"}
  50. 50. { name = "John Doe"}
  51. 51. ? name = "John Doe"}
  52. 52. ? name = "John Doe"#
  53. 53. ?name="John Doe"#
  54. 54. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  55. 55. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  56. 56. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles( , respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  57. 57. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  58. 58. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles , nil) }
  59. 59. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles.filter{ ($0.name == query.name), nil) }
  60. 60. What Else?
  61. 61. SELECT * from Profiles
  62. 62. name,, photo, dateOfBirth, "John Doe", "jbbkj362", "06-06-1980",
  63. 63. name,, photo, dateOfBirth "John Doe", "jbbkj362", "06-06-1980"
  64. 64. name:”John Doe”,photo:”jbbkj362”,dateOfBirth:”06-06-1980"
  65. 65. {name:”John Doe”,photo:”jbbkj362”,dateOfBirth:”06-06-1980”}
  66. 66. struct Profile: Codable { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  67. 67. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { ... respondWith(profiles, nil) }
  68. 68. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll() respondWith(profiles, nil) }
  69. 69. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(respondWith) respondWith(profiles, nil) }
  70. 70. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(respondWith: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(respondWith) }
  71. 71. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(completion) }
  72. 72. SELECT * from Profiles
  73. 73. SELECT * from Profiles
  74. 74. SELECT * from Profiles WHERE name = “John Doe”
  75. 75. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } router.get("/profile", handler: getProfiles) func getProfiles(completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(completion) }
  76. 76. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(completion) }
  77. 77. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(completion) }
  78. 78. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll( completion) }
  79. 79. struct Profile: Model { var name: String var photo: Data var dateOfBirth: Date } struct Query: QueryParams { var name: String } router.get("/profile", handler: getProfiles) func getProfiles(query: Query, completion: @escaping ([Profile]?, Error?) -> Void) -> Void { Profile.getAll(matching: query, completion) }
  80. 80. Codable
  81. 81. Dynamic Swift
  82. 82. Questions

×