Slide 1

Slide 1 text

Introduction to Vapor The Developer’s 3

Slide 2

Slide 2 text

" Head of Vapor Development at Nodes Full time Vapor developer since January 2017 Background in iOS development ~50 customer projects and ~40 packages @steffendsommer

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

“Platform support for all Apple platforms as well as Linux”

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

A web framework built in Swift Official support for SQLite, MySQL, PostgreSQL and Redis Built on top of SwiftNIO

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Frontend Backend Static websites Dynamic websites API

Slide 9

Slide 9 text

Backend API Android application iOS application Single page application Illustration borrowed from Jonas Schwartz

Slide 10

Slide 10 text

1.0 Sep, 2016 2.0 May, 2017 3.0 April, 2018 0.1 Jan, 2016 Timeline borrowed from Tanner Nelson

Slide 11

Slide 11 text

⚙ Configs Codable Async

Slide 12

Slide 12 text

import Vapor let app = try Application() let router = try app.make(Router.self) router.get("hello") { req in return "Hello, world." } try app.run()

Slide 13

Slide 13 text

Strong, safe and modern language Fast and has a low memory footprint (aka. ) Tech awesomeness ♻ Potential synergy between iOS and Vapor

Slide 14

Slide 14 text

♻ Models ⚠ Errors Frameworks used in both places Endpoints & Environments Business logic Styling Test code (e.g. mocks) ✅ Validation ☂ A framework that wraps the endpoints

Slide 15

Slide 15 text

Modern and Swifty API’s Great community Growing eco system Most popular

Slide 16

Slide 16 text

Everything is “new” Tooling ⚙ Foundation Eco system Resources

Slide 17

Slide 17 text

Slide 18

Slide 18 text

Number of users 1 ≠ ∞

Slide 19

Slide 19 text

Performance ? ≠ < 2 sec

Slide 20

Slide 20 text

Performance Free ≠ Pricy

Slide 21

Slide 21 text

Platforms iOS tvOS macOS watchOS ≠ macOS Linux

Slide 22

Slide 22 text

Bug fixing Next release cycle ≠ Fix it now

Slide 23

Slide 23 text

User Interfaces Storyboards Auto Layout Xib ≠ HTML CSS JavaScript
 Leaf

Slide 24

Slide 24 text

The Xcode Project File Merge madness ≠ What file?

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Persistence Used ≠ Very central

Slide 27

Slide 27 text

Architecture MVC MVVM MVP VIPER ≠ MVC

Slide 28

Slide 28 text

?

Slide 29

Slide 29 text

https://www.serversideswift.work

Slide 30

Slide 30 text

Create a new post Show all published posts, sorted by a publish date Show details of a single post

Slide 31

Slide 31 text

brew install vapor/tap/vapor 1

Slide 32

Slide 32 text

vapor new ServerSideSwiftWork 2

Slide 33

Slide 33 text

vapor xcode 3

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

http://localhost:8080/hello

Slide 36

Slide 36 text

SQLite Fluent Leaf

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

// 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"]) ] )

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

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 } }

Slide 41

Slide 41 text

extension Work: SQLiteModel {} extension Work: Migration {} extension Work: Content {} extension Work: Parameter {}

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

func create(_ req: Request) throws -> Future { return try req .content .decode(Work.self) .save(on: req) }

Slide 44

Slide 44 text

func index(_ req: Request) throws -> Future<[Work]> { return Work .query(on: req) .filter(\.publishedAt != nil) .sort(\.publishedAt, .descending) .all() }

Slide 45

Slide 45 text

struct ViewData: Codable { let work: [Work] } func renderIndex(_ req: Request) throws -> Future { return Work .query(on: req) .filter(\.publishedAt != nil) .sort(\.publishedAt, .descending) .all() .flatMap { items in try req.view().render("index", ViewData(work: items)) } }

Slide 46

Slide 46 text

func show(_ req: Request) throws -> Future { return try req .parameters .next(Work.self) }

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Work

    #for(item in work) {
  • #(item.title) at #(item.company)
    #(item.description)
  • }

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

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) }

Slide 51

Slide 51 text

Slide 52

Slide 52 text

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) }

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

try services.register(FluentSQLiteProvider()) try services.register(LeafProvider()) config.prefer(LeafRenderer.self, for: ViewRenderer.self)

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

let sqlite = try SQLiteDatabase(storage: .memory) var databases = DatabasesConfig() databases.add(database: sqlite, as: .sqlite) services.register(databases)

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

GET http://localhost:8080/work

Slide 63

Slide 63 text

Yes, async is hard at first RxSwift/ReactiveSwift can be a plus Async/await would be great

Slide 64

Slide 64 text

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

vapor cloud deploy

Slide 67

Slide 67 text

https://vapor.cloud

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

Public alpha Now-ish Week 40-41

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

@steffendsommer