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 Container
s and an EventLoop
.
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.
Case Sensitive Routing
Should /helloWorld
and /helloworld
be sent to the same route? Should one throw 404
? Discuss!
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?>
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
.
Client Now Supports String URIs
This welcome update allows you to pass simple String
s as the URI
for requests made to Client
(i.e., EngineClient
).
req.make(Client.self).get("https://www.google.com")
Previously, only URI
s or literal strings (non-interpolated) could be used.
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.
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).
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 enum
s being used as database fields in models).
Eventloop and Future Optimizations
This PR adds some optimizations to the EventLoop and Future implementations.
- EventLoop: Minimize how many times an EventSource can be suspended/resumed by adding some internal state.
- Future: Minimize array appends by optimizing the case where a Future only has one awaiter.
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!
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! 🏎🏎🏎
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.
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()