Week 5

News

Swift NIO

This week, Apple released Swift NIO at the try! Swift Conference in Tokyo. Apple describes NIO as “a cross-platform asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.” For all you droplets that have been following Vapor 3 development, that means NIO will be replacing a significant portion of the code supporting Vapor behind the scenes. To quote Tanner,

Swift NIO directly replaces:

Vapor will take a performance hit until NIO’s HTTP parser can be optimized, but the long-term benefits greatly outweigh the short-term drawbacks. Having a dedicated team at Apple working on all of the low level code leaves the Vapor team free to make large user-facing improvements with all that time previously spent mucking around with libraries that are being deprecated!

This raises the question as to whether or not Vapor Nation should cover updates to NIO. What do you think? Drop your opinion in #vapor-nation on Slack, or @VaporNationNews on Twitter!

https://github.com/apple/swift-nio

Swift By Sundell Featuring Tanner

Swift By Sundell is a Swift podcast hosted by @JohnSundell. This week’s guest is @tanner0101, founder of Vapor. John is accepting questions right now, so get them in soon!

https://twitter.com/johnsundell/status/970580124998434816

New Features

RSA Encription Implemented and Made Available To JWT

// create public and private key (only public required for verification)
let privateKey: Data = ...
let publicKey: Data = ...
let privateSigner = JWTSigner.rs256(key: .private2048(privateKey))
let publicSigner = JWTSigner.rs256(key: .public2048(publicKey))

// serialize jwt (requires private key)
let payload: TestPayload = ...
var jwt = JWT(payload: payload)
_ = try jwt.sign(using: publicSigner) // throws, can't sign w/ public signer
let data = try jwt.sign(using: privateSigner)

// parse jwt (public and private key work)
let parsed = try JWT<TestPayload>(from: data, verifiedUsing: publicSigner)
let parsed2 = try JWT<TestPayload>(from: data, verifiedUsing: privateSigner) // also works
print(parsed.payload)
print(parsed2.payload)

vapor/jwt#83
vapor/crypto#39

Support For NULL In MySQL

Adds support for NULL values when fetching data.

vapor/mysql#133

Added Support For Default Values In PostgreSQL

You can now set default values to be saved to the database for optional properties. The defaults will be used when such properties are nil during saving.

vapor/fluent-postgresql#19

Foundation Client

Adds a FoundationClient class which implements the Client protocol using URLSession. This provides a more configurable (but less performant) alternative to EngineClient.

Create a single FoundationClient

let client = try req.make(FoundationClient.self)

Or prefer FoundationClient globally

var config = Config.default()
config.prefer(FoundationClient.self, for: Client.self)
let app = try Application(config: config)
let client = try app.make(Client.self)
print(client is FoundationClient) // true

Use just like EngineClient

let res = try client.send(.get, to: "http://vapor.codes")
debugPrint(res)

vapor/vapor#1529

Community Contributions

Made Router.on() Public

@calebkleveter opened up the Router.on(:at:use:) method for public use, allowing the HTTP method for newly registered routes to be specified as a parameter for routes that automaticly decode the request’s body, along with those that don’t.

vapor/vapor#1528

Added Support For BIT and TIMESTAMP Types In MySQL

@PitchLabsAsh added support to vapor/mysql for the BIT and TIMESTAMP types. Vapor already had support for DATETIME, which differs slightly from TIMESTAMP.

vapor/mysql#131

Add Typealias For UserIDKey

@0xTim removed some boilerplate by typealiasing WritableKeyPath<Self, UserType.ID> to UserIDKey

vapor/auth#25

Made For Vapor

Vapor Test Tools

@rafiki270 says he has “long struggled with testing so I have decided to publish my library of testing helpers as an SPM framework”

https://github.com/LiveUI/VaporTestTools

Microtutorial

HTTP requests have held the Internet together for tens of years, but they do have limitations. Some of those limitations have been addressed by HTTP/2, but not quite all. Among those limitations is that the a server must wait for a client to send a request before it can send data to that client. It makes sense that the protocol is designed in this way, and I’d hate to be getting spammed by random servers all day. However, there are many cases where the server wants to be able to push additional data to the client on-demand after a connection has been established, and plain HTTP can’t do that. That means if you want to run a server for something like, say, an instant messaging chat, the client must to continuously poll the server to check for new messages. This places a heavy load on both client and server, wasting a lot of time and data.

Websockets solve this problem by leaving established HTTP connections open and converting them to specially formatted binary data streams. This allows the server and client to exchange information as needed, an ideal solution for realtime applications such as chatting, videoconferencing, and more. The best news of all is, Vapor supports them out of the box!

router.websocket("echo") { (req, ws) in
    ws.onString({ (ws, msg) in
        ws.send(string: msg)
    })
}

This example sets up a websocket route on ws://localhost:8080/echo. Any data sent to that connection will echoed right back.


Credits

@twof @gwynne @calebkleveter