Week 0

The format is heavily inspired by Swift Weekly (RIP) and Swift Web Weekly to a lesser extent.

Discussions

Listing discussions will hopefully attract folks who are current heavy Vapor users or have a lot of server-side experience in general.

Naming changes to Request

This week in discussion is the proposal to rename Request to RequestContext in order to differentiate between HTTPRequest and Request which in addition to an HTTPRequest (req.http) also contains Containers and an EventLoop.

vapor/vapor#1443

Maximum Body Size

This discussion is around the question of whether or not small request bodies should be treated differently than larger request bodies; specifically if small ones should be accessed synchronously. After a pull request to support streaming bodies the week before, all content access was required to be treated as asynchronous, but the changed also increased complexity of user code.

vapor/engine#205

Case Sensitive Routing

Should /helloWorld and /helloworld be sent to the same route? Should one throw 404? Discuss!

vapor/vapor#1196

New Features

New features are listed after PRs are merged. New features are specifically user facing changes, and should come with a short description and a minimal code sample that displays usage. Small userfacing tweaks will not be listed.

Fluent Cache

You can now use your Fluent database as a KeyedCache. Any struct/class that conforms to Codable can be stored (data is JSON-encoded).

Setup looks like ths:

/// Register providers
try services.register(FluentSQLiteProvider())

...

/// Setup a simple in-memory SQLite database
var databases = DatabaseConfig()
let sqlite = try SQLiteDatabase(storage: .memory)
databases.add(database: sqlite, as: .sqlite)
services.register(databases)

/// Configure migrations
var migrations = MigrationConfig()
/// Ensure SQLiteCache has the tables it will need
migrations.prepareCache(for: .sqlite)
services.register(migrations)

Usage like this:

let cache = try req.make(KeyedCache.self)
cache.get(Foo.self, forKey: "my-foo") // Future<Foo?>

vapor/fluent#358

PostgreSQL Support for JSON/JSONB and Arrays

With this update, you can now store arbitrarily structured data in your PostgreSQL database.

final class User: PostgreSQLModel, Migration {
    static let idKey = \User.id
    var id: Int?
    var name: String
    var age: Int?
    var favoriteColors: [String]
    var pet: Pet
    var dict: [String: String]

    init(id: Int? = nil, name: String, pet: Pet) {
        self.favoriteColors = []
        self.dict = [:]
        self.id = id
        self.name = name
        self.pet = pet
    }
}

struct Pet: PostgreSQLJSONType {
    var name: String
}

The above Swift class and struct result in the following schema:

CREATE TABLE "users" (
    "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    "name" TEXT NOT NULL,
    "age" BIGINT,
    "favoriteColors" TEXT[] NOT NULL,
    "pet" JSONB NOT NULL,
    "dict" JSONB NOT NULL
)

vapor/postgresql#2 vapor/fluent-postgresql#4

KeyedCache Sessions

This update allows you to use any KeyedCache conformer to power your SessionsMiddleware. Just make sure to configure KeyedCacheSessions as your preferred Sessions conformer, and Vapor will automatically create an instance of your preferred KeyedCache.

vapor/vapor#1444

Client Now Supports String URIs

This welcome update allows you to pass simple Strings as the URI for requests made to Client (i.e., EngineClient).

req.make(Client.self).get("https://www.google.com")

Previously, only URIs or literal strings (non-interpolated) could be used.

vapor/vapor#1446

Vapor 3 Compiles With Swift 4.1

XCode 9.3 is now in public beta and ships with Swift 4.1, which includes conditional conformance. Conditional conformance is sure to eliminate significant parts of the Vapor codebase. Yay! You can read more about the changes coming with Swift 4.1 here.

Note: You don’t actually need Xcode 9.3 as you can also install Swift 4.1 toolchains to Xcode 9.2.

vapor/vapor#1384

Under The Hood

Under the hood changes are things like refactors or optimizations that do not add any significant userfacing features. Everything in this section should come with a short description, but it can be as simple as “Optimizes X.

Stream Refactor

Simplifies Async streams. This has potential to simplify quite a bit of our async code.

This change removes the ability to request an arbitrary number of output from a connected upstream. Now, only one output request can be outstanding at a time. This allows for the protocol to be implemented by a simple Promise<Void> (previously used ConnectionContext has been deleted).

This change should better match the semantics of co-routine style streams as well (thinking ahead to future Swift versions).

vapor/async#52

Better CodingKey Decoding

Significantly improves handling of key-string decoding by using conditional conformances (where available) and providing much better error messages if a type doesn’t conform to KeyStringDecodable (most often enums being used as database fields in models).

vapor/core#86

Eventloop and Future Optimizations

This PR adds some optimizations to the EventLoop and Future implementations.

vapor/async#57

Community Contributions

In this section I’d like to highlight some community PRs that got merged this week and inspire others to submit their first PR to Vapor. Proving that you don’t have to know everything to write a small bugfix 😀

Fix parsing WebSocket close frame length

Props to @tiwoc for their contribution! They fixed a websocket bug and ensured reliability in only 5 lines of code!

vapor/engine#203

Starter Tasks

This section consists of tasks that would be good for beginners to tackle. They do not necessarily have to be issues in the Vapor codebase itself, but they should contribute in some way to Vapor.

Swift Is Broken in Techempower’s Framework Benchmarks

It would be awesome to for Vapor to compete in TechEmpower’s Framework Benchmarks, however, their installation of Swift is both broken and a version behind. Their instructions will be helpful along with the Vapor/Swift on Unbuntu tutorial below. Drop into the #beta channel if you decide to give this issue a go and you have questions 😀 

TechEmpower/FrameworkBenchmarks#3181

Benchmarks

This is where Vapor gets to flex a little 💪 It’ll be nice to let readers track improvements and achievement.

Vapor’s engine nearly matches Go’s FastHTTP

Joannis benchmarked Vapor/Engine at 111,324.52 requests/second and FastHTTP at 118,479.28 requests/second. Nice! 🏎🏎🏎

vapor/engine#211

Tutorials

This is where any newly written tutorials pertaining to Vapor will be listed. I’m hoping doing so will give the content creators a little bump in traffic

Vapor 3 with Docker

In this tutorial learn how to run Vapor 3 in Docker! Why? One of the best reasons right now is that Swift (and Vapor) often behaves differently on Linux than on macOS, so being able to locally test your code in a Linux container is much faster than pushing to Heroku every time you need to test something. 10 minute build times anyone?

bygri.github.io/2018/01/25/vapor-3-with-docker.html

How to Install Swift and Vapor on Ubuntu

In this guide, you’ll install Swift and Vapor on Ubuntu 16.04. Then you’ll test your setup by creating a simple web application using one of Vapor’s templates.

digitalocean.com/community/tutorials/how-to-install-swift-and-vapor-on-ubuntu-16-04

Built With Vapor

To showcase what people are doing with Vapor and to inspire others to create and share.

Leaderboard App

Keep track of your office games.

leaderboardapp.com

Micro Tutorial

I think it’d be fun to include a tiny tutorial at the end. Ideally it’d just be a code snippet that showcases some Vapor syntax that the devs are proud of along with a short description of what it does.

Very appropriately, the simplest possible Vapor 3 Hello World:

import Vapor

let app = try Application()

let router = try app.make(Router.self)
router.get("hello") { req -> String in
  return "Hello, world!"
}

try app.run()

Credits:

@gwynne
@calebkleveter
@tanner0101
@twof