Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vapor State of the Union

Tanner
September 13, 2018

Vapor State of the Union

The creator of Vapor gives an overview of what the core team has been working on this past year. He also discusses the future of Vapor and some exciting developments in server-side Swift.

Tanner

September 13, 2018
Tweet

More Decks by Tanner

Other Decks in Programming

Transcript

  1. let port = env.isRelease ? 80 : 8080
 let config

    = NIOServerConfig .default(hostname: "localhost", port: port) services.register(config) ⚙ Config 3.0
  2. Codable final class Post: Model { let content: String let

    storage = Storage() init(row: Row) throws { content = try row.get("content") } func makeRow() throws -> Row { var row = Row() try row.set("content", content) return row } } 2.0
  3. SwiftNIO let todos = Todo.query(on: req).all() print(todos) // Future<[Todo]> return

    todos.map { todos in print(todos.count) return todos } 3.0
  4. func foo() async -> String let string = await foo()

    Coroutines (async / await) Swift 7
  5. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  6. import NIO import NIOHTTP1 private final class HTTPHandler: ChannelInboundHandler {

    typealias InboundIn = HTTPServerRequestPart typealias OutboundOut = HTTPServerResponsePart func channelRead(ctx: ChannelHandlerContext, data: NIOAny) { let req = unwrapInboundIn(data) switch req { case .end: let message = "Hello, world!" let res = HTTPResponseHead( version: .init(major: 1, minor: 1), status: .ok, headers: HTTPHeaders.init([ ("Content-Length", message.count.description), ("Content-Type", "text/plain") ]) ) ctx.write(wrapOutboundOut(.head(res)), promise: nil) var buffer = ctx.channel.allocator.buffer(capacity: message.count) buffer.write(string: message) ctx.write(wrapOutboundOut(.body(.byteBuffer(buffer))), promise: nil) ctx.writeAndFlush(wrapOutboundOut(.end(nil)), promise: nil) case .body, .head: break } } } let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) let bootstrap = ServerBootstrap(group: group) .serverChannelOption(ChannelOptions.backlog, value: 256) .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelInitializer { channel in channel.pipeline.configureHTTPServerPipeline(withErrorHandling: true).then { channel.pipeline.add(handler: HTTPHandler()) } } .childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1) .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 1) defer { try! group.syncShutdownGracefully() } let channel = try bootstrap.bind(host: "localhost", port: 8080).wait() print("Server booted") try channel.closeFuture.wait() “Hello World” in SwiftNIO ~50 LoC
  7. HTTP import HTTP struct Hello: HTTPServerResponder { func respond(to req:

    HTTPRequest, on worker: Worker) -> Future<HTTPResponse> { let res = HTTPResponse(body: "Hello, world!") return worker.future(res) } } let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { try! group.syncShutdownGracefully() } let server = try HTTPServer.start( hostname: "localhost", port: 8080, responder: Hello(), on: group ).wait() try server.onClose.wait() <20 LoC 3.0
  8. HTTP import HTTP struct Hello: HTTPServerResponder { func respond(to req:

    HTTPRequest, on worker: Worker) -> Future<HTTPResponse> { let res = HTTPResponse(body: "Hello, world!") return worker.future(res) } } <20 LoC 3.0
  9. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  10. import WebSocket
 
 let ws = HTTPServer.webSocketUpgrader(shouldUpgrade: { req in

    return [:] }, onUpgrade: { ws, req in ws.onText { ws, string in ws.send(string.reversed()) } }) WebSocket 3.0
  11. import WebSocket
 
 let ws = HTTPServer.webSocketUpgrader(shouldUpgrade: { req in

    return [:] }, onUpgrade: { ws, req in ws.onText { ws, string in ws.send(string.reversed()) } }) let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) defer { try! group.syncShutdownGracefully() } let server = try HTTPServer.start( hostname: "localhost", port: 8080, responder: ..., upgraders: [ws], on: group ).wait() WebSocket 3.0
  12. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  13. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  14. + SQL 3.0 conn.select().all().from(Galaxy.self) .join(Planet.self, on: \Galaxy.id == \Planet.galaxyID) .where(\Galaxy.type

    == .spiral) .where(\Planet.type == .smallRocky) .all(decoding: Planet.self, Galaxy.self)
  15. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  16. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  17. Vapor router.get("hello") { req in return "Hello, world!" } 3.0

    $ curl localhost:8080/hello Hello, world!
  18. Vapor 3.0 router.get("hello", String.parameter) { req in let name =

    try req.parameters.next(String.self) return "Hello, \(name)!" }
  19. Vapor router.get("hello", String.parameter) { req in let name = try

    req.parameters.next(String.self) return "Hello, \(name)!" } 3.0 $ curl localhost:8080/hello/Swift Hello, Swift!
  20. Vapor 3.0 struct LoginInfo: Content { var email: String var

    password: String } router.post("login") { req in return try req.content.decode(LoginInfo.self).map { info in return "\(info.email): \(info.password)" } }
  21. Vapor struct LoginInfo: Content { var email: String var password:

    String } router.post("login") { req in return try req.content.decode(LoginInfo.self).map { info in return "\(info.email): \(info.password)" } } 3.0 $ curl -X POST -H 'Content-Type: application/json' -d '{"email": "[email protected]", "password": "123"}' localhost:8080/login [email protected]: 123
  22. HTTP PostgreSQL Console Core JWT + SQL ⚡ Redis Vapor

    DatabaseKit MySQL TemplateKit Routing Crypto Auth Leaf ✅ Validation Multipart Fluent URL-Encoded Form SQLite WebSocket Service
  23. ~/dev/tanner0101/TodoAPI master $ vapor cloud deploy app: Server-side Swift 18

    git: [email protected]:tanner0101/sss-berlin—18.git env: production db: none replicas: 1 replica size: large branch: master build: incremental Creating deployment [Done] Connecting to build logs ... Waiting in Queue [Done] Starting deployment: 'sss-berlin-18' [Done] Getting project from Git '[email protected]:tanner0101/sss-berlin—18.git' [Done] ... Building container [Done] Pushing container to registry [Done] Updating replicas [Done] Deployment succeeded: https://sss-berlin-18.vapor.cloud [Done] Successfully deployed. Cloud 1.0