Pro Yearly is on sale from $80 to $50! »

The iOS Developer’s Introduction to Vapor (3)

The iOS Developer’s Introduction to Vapor (3)

Server-side Swift has been around for a couple of years and as time goes by the maturity of putting Swift on the server grows. With this talk, I will give an introduction to one of the most popular server-side Swift frameworks called Vapor, which recently released a new major version. I will talk a bit about how I ended up doing server-side Swift development after working with iOS for years and I’ll look at the potential synergy between Vapor and iOS. This talk requires no prior knowledge to server-side Swift.

9993186221ec65f6f10db0dc9cff7c07?s=128

Steffen D. Sommer

October 04, 2018
Tweet

Transcript

  1. Introduction to Vapor The Developer’s 3

  2. " Head of Vapor Development at Nodes Full time Vapor

    developer since January 2017 Background in iOS development ~50 customer projects and ~40 packages @steffendsommer
  3. None
  4. “Platform support for all Apple platforms as well as Linux”

  5. None
  6. A web framework built in Swift Official support for SQLite,

    MySQL, PostgreSQL and Redis Built on top of SwiftNIO
  7. None
  8. Frontend Backend Static websites Dynamic websites API

  9. Backend API Android application iOS application Single page application Illustration

    borrowed from Jonas Schwartz
  10. 1.0 Sep, 2016 2.0 May, 2017 3.0 April, 2018 0.1

    Jan, 2016 Timeline borrowed from Tanner Nelson
  11. ⚙ Configs Codable Async

  12. import Vapor let app = try Application() let router =

    try app.make(Router.self) router.get("hello") { req in return "Hello, world." } try app.run()
  13. Strong, safe and modern language Fast and has a low

    memory footprint (aka. ) Tech awesomeness ♻ Potential synergy between iOS and Vapor
  14. ♻ Models ⚠ Errors Frameworks used in both places Endpoints

    & Environments Business logic Styling Test code (e.g. mocks) ✅ Validation ☂ A framework that wraps the endpoints
  15. Modern and Swifty API’s Great community Growing eco system Most

    popular
  16. Everything is “new” Tooling ⚙ Foundation Eco system Resources

  17. Number of users 1 ≠ ∞

  18. Performance ? ≠ < 2 sec

  19. Performance Free ≠ Pricy

  20. Platforms iOS tvOS macOS watchOS ≠ macOS Linux

  21. Bug fixing Next release cycle ≠ Fix it now

  22. User Interfaces Storyboards Auto Layout Xib ≠ HTML CSS JavaScript


    Leaf
  23. The Xcode Project File Merge madness ≠ What file?

  24. State Used when needed ≠ It’s all about the request

  25. Persistence Used ≠ Very central

  26. Architecture MVC MVVM MVP VIPER ≠ MVC

  27. ?

  28. https://www.serversideswift.work

  29. Create a new post Show all published posts, sorted by

    a publish date Show details of a single post
  30. brew install vapor/tap/vapor 1

  31. vapor new ServerSideSwiftWork 2

  32. vapor xcode 3

  33. None
  34. http://localhost:8080/hello

  35. SQLite Fluent Leaf

  36. None
  37. // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ServerSideSwiftWork",

    dependencies: [ // A server-side Swift web framework. .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), // Swift ORM (queries, models, relations, etc) built on SQLite 3. .package(url: "https://github.com/vapor/fluent-sqlite.git", from: "3.0.0"), // Template engine .package(url: "https://github.com/vapor/leaf.git", from: "3.0.1"), ], targets: [ .target(name: "App", dependencies: ["Leaf", "FluentSQLite", "Vapor"]), .target(name: "Run", dependencies: ["App"]), .testTarget(name: "AppTests", dependencies: ["App"]) ] )
  38. None
  39. final class Work: Codable { public var id: Int? public

    var company: String public var location: String public var title: String public var description: String public var externalUrl: String public var publishedAt: Date? public init( company: String, location: String, title: String, description: String, externalUrl: String, publishedAt: Date? = nil ) { self.company = company self.location = location self.title = title self.description = description self.externalUrl = externalUrl self.publishedAt = publishedAt } }
  40. extension Work: SQLiteModel {} extension Work: Migration {} extension Work:

    Content {} extension Work: Parameter {}
  41. None
  42. func create(_ req: Request) throws -> Future<Work> { return try

    req .content .decode(Work.self) .save(on: req) }
  43. func index(_ req: Request) throws -> Future<[Work]> { return Work

    .query(on: req) .filter(\.publishedAt != nil) .sort(\.publishedAt, .descending) .all() }
  44. struct ViewData: Codable { let work: [Work] } func renderIndex(_

    req: Request) throws -> Future<View> { return Work .query(on: req) .filter(\.publishedAt != nil) .sort(\.publishedAt, .descending) .all() .flatMap { items in try req.view().render("index", ViewData(work: items)) } }
  45. func show(_ req: Request) throws -> Future<Work> { return try

    req .parameters .next(Work.self) }
  46. None
  47. <h1>Work</h1> <ul> #for(item in work) { <li> <b>#(item.title) at #(item.company)</b><br>

    #(item.description) </li> } </ul>
  48. None
  49. public func routes(_ router: Router) throws { let workController =

    WorkController() router.get("api/work", use: workController.index) router.get("api/work", Work.parameter, use: workController.show) router.post("api/work", use: workController.create) router.get("work", use: workController.renderIndex) }
  50. public func configure(_ config: inout Config, _ env: inout Environment,

    _ services: inout Services) throws { /// Register providers first try services.register(FluentSQLiteProvider()) try services.register(LeafProvider()) config.prefer(LeafRenderer.self, for: ViewRenderer.self) /// Register routes to the router let router = EngineRouter.default() try routes(router) services.register(router, as: Router.self) /// Register middleware var middlewares = MiddlewareConfig() middlewares.use(ErrorMiddleware.self) services.register(middlewares) // Configure a SQLite database let sqlite = try SQLiteDatabase(storage: .memory) /// Register the configured SQLite database to the database config. var databases = DatabasesConfig() databases.add(database: sqlite, as: .sqlite) services.register(databases) /// Configure migrations var migrations = MigrationConfig() migrations.add(model: Work.self, database: .sqlite) services.register(migrations) }
  51. None
  52. try services.register(FluentSQLiteProvider()) try services.register(LeafProvider()) config.prefer(LeafRenderer.self, for: ViewRenderer.self)

  53. let router = EngineRouter.default() try routes(router) services.register(router, as: Router.self)

  54. let sqlite = try SQLiteDatabase(storage: .memory) var databases = DatabasesConfig()

    databases.add(database: sqlite, as: .sqlite) services.register(databases)
  55. var migrations = MigrationConfig() migrations.add(model: Work.self, database: .sqlite) services.register(migrations)

  56. None
  57. None
  58. None
  59. None
  60. GET http://localhost:8080/work

  61. Yes, async is hard at first RxSwift/ReactiveSwift can be a

    plus Async/await would be great
  62. None
  63. vapor cloud deploy

  64. https://vapor.cloud

  65. Multiple regions and cloud providers Custom docker templates ♻ Internal

    DNS setup Build pipeline ✏ Releases and rollback Public API Database IP Built-in Git server Commands in separate replicas ⚙ Loadbalancer configuration More statistics All features in the dashboard Config updates without redeployment And much more… Version 2
  66. Public alpha Now-ish Week 40-41

  67. https://docs.vapor.codes https://discord.gg/vapor Tim Condon - Getting Started with Server Side

    Swift and Vapor (Codemobile 2018) ? https://www.serversideswift.work https://www.serversideswift.info
  68. None
  69. None
  70. @steffendsommer