Skip to content

Instantly share code, notes, and snippets.

Last active February 13, 2019 01:52
Show Gist options
  • Save 0xTim/b372f91c8bd71ea757d1da526058f2d9 to your computer and use it in GitHub Desktop.
Save 0xTim/b372f91c8bd71ea757d1da526058f2d9 to your computer and use it in GitHub Desktop.
Changes for the Ray Wenderlich Vapor Videos for Vapor 3 RC 2

Vapor 3 RC 2 Updates

Vapor 3 RC 2 is out! To update, ensure that your Package.swift contains something like:

.package(url: "", from: "3.0.0-rc"),
.package(url: "", from: "3.0.0-rc"),
.package(url: "", from: "3.0.0-rc"),

Depending on your dependenices - make sure that you use the "X.X.X-rc" - that's the important bit.

You will also need to update your toolbox - Vapor 3 RC2 now requires LibreSSL for macOS with NIO - you can either upgrade you toolbox (brew upgrade vapor) or just install LibreSSL (brew install libressl)

Section 1

Video 4 - Accepting Data

The await(on:) function has now been deprecated, and was always a stopgap. To accept data before learning about Futures you can use the POST helper function:, at: "info") { req, data -> InfoResponse in
  return InfoResponse(request: data)

Video 5 - Challenge Your Own Routes

As above, use the new function for your POST route:, at: "user-info") { req, userInfo -> String in
  return "Hello \(, you are \(userInfo.age)!"

Section 2

Video 3 - Controllers and CRUD

Remove the await(on:) call in AcronymsController.swift. You can now call save(on:) directly on a Future<Model>:

func createHandler(_ req: Request) throws -> Future<Acronym> {
  let acronym = try req.content.decode(Acronym.self)
  return req)

Video 5 - Challenge Users and Categories

As for Video 3, in CategoriesController.swift you should now have:

func createHandler(_ req: Request) throws -> Future<Category> {
  let category = try req.content.decode(Category.self)
  return req)

Video 6 - Parent Child Relationships

Fluent's get(on:) query now throws so the getCreatorHandler(_:) in AcronymsController.swift now looks like:

func getCreatorHandler(_ req: Request) throws -> Future<User> {
  return try req.parameter(Acronym.self).flatMap(to: User.self) { acronym in
  return try acronym.creator.get(on: req)

Video 8 - Fluent Queries

Fluent's group(_:) and filter(_:) queries throw so the searchHandler(_:) in AcronymsController.swift now looks like:

func searchHandler(_ req: Request) throws -> Future<[Acronym]> {
  guard let searchTerm = req.query[String.self, at: "term"] else {
    throw Abort(.badRequest)
  return try Acronym.query(on: req).group(.or) { or in
    try or.filter(\.short == searchTerm)
    try or.filter(\.long == searchTerm)

Video 9 - Persisting Data with MySQL

The configuration for MySQLDatabase is now provided in a separate type. In configure.swift it should now look like:

var databases = DatabaseConfig()
let mysqlConfig = MySQLDatabaseConfig(hostname: "localhost", port: 3306, username: "til", password: "password", database: "vapor")
let database = MySQLDatabase(config: mysqlConfig)
databases.add(database: database, as: .mysql)

Section 3

Video 3 - Powerful Templates

As Fluent's get(on:) query now throws, the acronymHandler(_:) now looks like:

func acronymHandler(_ req: Request) throws -> Future<View> {
  return try req.parameter(Acronym.self).flatMap(to: View.self) { acronym in
    return try acronym.creator.get(on: req).flatMap(to: View.self) { creator in
      let context = AcronymContext(title: acronym.long, acronym: acronym, creator: creator)
      return try req.leaf().render("acronym", context)

Section 4

Video 2 - Passwords

Crypto's Random functions have been tweaked. The Token extension to generate a token should now look like:

extension Token {
  static func generate(for user: User) throws -> Token {
    let random = try CryptoRandom().generateData(count: 16)
    return try Token(token: random.base64EncodedString(), userID: user.requireID())

BCrypt functions have been renamed as well. In your UsersController you'll need to import Crypto and change your createHandler(_:) should look like:

func createHandler(_ req: Request) throws -> Future<User> {
  return try req.content.decode(User.self).flatMap(to: User.self) { user in
    let hasher = try req.make(BCryptDigest.self)
    user.password = try String.convertFromData(hasher.hash(user.password))
    return req)

Video 3 - API Authentication

When creating the basicAuthMiddleware you need to rename the Verifier. Your line should look like:

let basicAuthMiddleware = User.basicAuthMiddleware(using: BCryptDigest())

Video 4 - Website Authentication

When creating the verifier BCrypt types have been renamed:

let verifier = try req.make(BCryptDigest.self)
Copy link

I think the code for Section 1 / Video 4 should be:, at: "user-info") { req, userInfo in
return "Hello ( you are (userInfo.age)"

as we are only to return a String.
Your solution returns a JSON, which is also nice.
Thanks for your gist, as I watched to video and use Vapor 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment