All Versions
12
Latest Version
Avg Release Cycle
62 days
Latest Release
207 days ago

Changelog History
Page 1

  • v4.0.0

    August 02, 2019
    • ⚡️ Updated to OpenCrypto alpha 2 (#2031)
    • ⚡️ Updated to SSWG's official AsyncHTTPClient package (#2031)
    • 🔀 Merged server and client websocket code into WebSocket (#2031)

      // client return WebSocket.connect( to: "ws://echo.websocket.org/", on: req.eventLoop) { ws in ws.send("Hello, world!") ws.onText { ws, text in promise.succeed(text) ws.close().cascadeFailure(to: promise) } }// serverrouter.webSocket("bar") { req, ws in ws.send("Hello, world!") ws.onText { ws, text in promise.succeed(text) ws.close().cascadeFailure(to: promise) } }

    • BCrypt renamed to Bcrypt and included in Vapor (#2031)

      let hash = try Bcrypt.hash("vapor")print(hash) // $2b$12$Lmw/Zx2jSXgxE.r/8uipROCoh64KdPL7/mdEz38EqEFZDEu5JsAH2try Bcrypt.verify("vapor", created: hash) // truetry Bcrypt.verify("foo", created: hash) // false

  • v4.0.0-beta.3

    December 14, 2019

    Example output:

    # TYPE http_requests_total counter
    http_requests_total 0
    http_requests_total{status="200", path="GET /hello/:name", method="GET"} 7
    http_requests_total{status="200", path="GET /metrics", method="GET"} 3
    # TYPE http_request_duration_seconds summary
    http_request_duration_seconds{quantile="0.01"} 0.000115894
    http_request_duration_seconds{quantile="0.05"} 0.000115894
    ...
    

    ⚡️ Updates to RoutingKit beta 3 (#2126)

    ClientResponse, HTTPStatus, and HTTPHeaders are now Codable (#2124)

    Environment variables loaded from .env files can now be accessed immediately after Application has initialized (#2125)

    📦 .env (in same folder as Package.swift)

    FOO=BAR
    

    main.swift

    let app = Application(...)defer { app.shutdown() } let foo = Environment.get("FOO") print(foo) // BAR
    
  • v4.0.0-beta.2

    December 09, 2019
    • ♻️ Services has been refactored to be more type-safe. (#2098)

    Services, Container, and Provider have been replaced by a pattern built on Swift extensions. This is best explained with examples.

    Telling Vapor to use Leaf:

    import Leafimport Vapor// beta.1s.register(ViewRenderer.self) { c inreturn c.make(LeafRenderer.self) }// beta.2app.views.use(.leaf)
    

    Registering a factory service:

    // beta.1s.register(Foo.self) { c inreturn Foo(...) } app.make(Foo.self).bar()// beta.2extension Application { var foo: Foo { return Foo(...) } } app.foo.bar()
    

    Registering a singleton service:

    // beta.1s.register(Foo.self) { c inreturn Foo(...) } app.make(Foo.self).bar = 0app.make(Foo.self).bar += 1print(app.make(Foo.self).bar) // 1// beta.2extension Application { var foo: Foo { if let existing = self.storage[FooKey.self] as? Foo { return existing } else { let new = Foo() self.storage[FooKey.self] = new return new } } private struct FooKey: StorageKey { typealias Value = Foo } } app.foo.bar = 0app.foo.bar += 1print(app.foo.bar) // 1
    

    This new pattern of extending Application also works with Request:

    extension Application { var foo: Foo { ... } }extension Request { var bar: Bar { return self.application.foo.bar(for: self) } }
    

    ♻️ Validations has been refactored to yield better and more type-safe errors (#2071)

    Authentication methods are now grouped under a new req.auth helper (#2111)

    All authenticators now accept Request in their authenticate methods (#2111)

    ➕ Added new ErrorSource struct to the AbortError protocol (#2093)

    🔊 This new struct makes it easier to pass around information about where an error came from. It also makes it easier to indicate that a given error has no source information. This helps the logger avoid muddying logs with useless error source information.

    👍 RouteBuilder HTTP method helpers now support an array of [PathComponent] (#2097)

    ✅ User-provided HTTP headers are no longer ignored when using XCTVapor test methods (#2108)

    🐧 Enabled test discovery on Linux (#2118)

  • v4.0.0-beta.1

    October 24, 2019
    • Application is now a global container. (#2079)

    👀 See below for a more in-depth explanation of this change, but these code examples explain it best:

    Vapor 4 alpha:

    let app = Application { s in s.register(Foo.self) { ...} }defer { app.shutdown() }let container = try app.makeContainer().wait()defer { container.shutdown() }let foo = try container.make(Foo.self)
    

    Vapor 4 beta:

    let app = Application()defer { app.shutdown() } app.register(Foo.self) { ... }let foo = app.make(Foo.self)
    

    🔀 In Vapor 3 and Vapor 4 alpha, Vapor's service architecture enforced a 1:1 relation between containers and event loops. This is a useful pattern for minimizing the amount of effort that needs to be spent on synchronizing concurrent access to services.

    🚀 However, as Swift on the server continues to evolve it is becoming evident that this pattern may hinder Vapor's ability to take full advantage of packages designed to be thread-safe. For example, the swift-server/async-http-client package which recently saw a 1.0.0 release. This HTTP client supports being used across many event loops on a given event loop group. To avoid inefficiencies caused by hopping between event loops, the API allows users to specify event loop preferences with varying degrees of strictness. By giving the API consumer the ability to communicate exactly what they need, the HTTP client can choose the most performant option. This decision may change depending on the current state of its internal connection pool and other parameters.

    For example, imagine the following scenario: Request A comes into your application on event loop 1 resulting in an external API request to foo.com. Request A completes and the HTTP client stores event loop 1's connection to foo.com into its pool. Request B comes into your application on event loop 2 and also wants to make an external API request to foo.com. In this situation, two things could happen:

    1: Request B could make a new connection to foo.com on event loop 2 at the cost of TCP handshake.
    2: Request B could re-use event loop 1's connection to foo.com at the cost of thread-hopping.

    In this case option 2 is the clear winner as establishing new TCP connections is much more time consuming.

    📦 Requiring distinct copies of each service on a per event loop basis prevents these kinds of optimizations. Exceptions could be made for things like HTTP client, but that would mean adding extra complexity to the already complex services architecture. Additionally, async-http-client was built as a model for what good server-side Swift packages should look like.

    • Application is now a RoutesBuilder. (#2079)

    🏗 Now that services are global, Application can be a routes builder. This makes single-file Vapor applications a lot more concise and is more similar to Vapor 3.

    import Vaporlet app = try Application(environment: .detect()) app.get("hello") { req inreturn "Hello, world!"}try app.run()
    
    • Request now has access to the application. (#2079)

    Since all reference type, singleton services are now expected to be thread-safe, Request can safely use the Application to create services as needed. Where this is especially useful is in creating request-specific contexts into services. A good example of this is how Database works in Fluent 4 beta.

    app.get("todos") { req inreturn Todo.query(on: req.db).all() }
    

    This is powered by the following extension to Request:

    extension Request { var db: Database { return self.application.make(Database.self).with(req) } }
    

    The key here is that Database is passed a reference to the current Request for context. This enables database operations to do things like:

    • Delegate callbacks to the request event loop
    • 🌲 Log query information and errors to the request's logger
    • Report metrics information on a per-request basis

    🚑 Having explicit access to the context provided by request may be critical in production use cases. (See http://asim-malik.com/the-perils-of-node-continuation-local-storage/)

    • Service creation methods no longer throw. (#2079)

    🔧 Errors thrown during service creation indicate a configuration failure. These errors should only happen during development-time and to make them easier to track down, they will now result in fatalError. This also makes it easier to use providers to extend Application in ways that feel native.

    For example, this is how Application now conforms to RoutesBuilder:

    extension Application: RoutesBuilder { public var routes: Routes { self.make() } public func add(route: Route) { self.routes.add(route: route) } }
    
    • 🍎 macOS 10.14+ and Linux are now the only officially supported platforms. (#2067, #2070)
    • ✅ Multipart parsing and serialization was broken out into vapor/multipart-kit (#2080)
    • ✅ WebSocket client module was broken out into vapor/websocket-kit (#2074)
    • UUID is now LosslessStringConvertible.
    • XCTVapor is now exported as a product.
    • Vapor repos are moving to GitHub actions for CI. (#2072)
    • 👍 HTTP body stream strategy .collect now supports an optional max size. (#2076)
  • v4.0.0-alpha.3

    August 26, 2019
    • Request no longer requires a Channel to init. Now, it requires an EventLoop and SocketAddress?. (#2037)

    ✅ > Note: This makes testing a Request easier since you can pass in either EmbeddedEventLoop or a real event loop from a group used elsewhere in your tests. Prior to this change, you were required to use EmbeddedChannel and EmbeddedEventLoop both of which are incompatible with real event loops.

    • 🛠 Fixed a data race accessing Application.running. (#2027, #2037)

    🔀 > Note: Application.running allows you to programmatically shutdown your HTTP server from anywhere that you can access Application. This includes routes, commands, etc. Because this can be accessed from any thread, it required synchronization (NSLock) to access.

    • XCTApplication test helpers now require explicit start / shutdown. (#2037)

    ✅ > Note: Although a bit more verbose, explicitly starting and shutting down test helpers gives the user more options for how they test their application. It also cuts down on edge cases in the testing implementation.

    ✅ Example from Vapor's tests with explicit start / shutdown:

    let app = Application.create(routes: { r, c in r.get("hello", ":a") { req inreturn req.parameters.get("a") ?? "" } r.get("hello", ":a", ":b") { req inreturn [req.parameters.get("a") ?? "", req.parameters.get("b") ?? ""] } })defer { app.shutdown() }let server = try app.testable().start()defer { server.shutdown() }try server.test(.GET, "/hello/vapor") { res inXCTAssertEqual(res.status, .ok) XCTAssertContains(res.body.string, "vapor") }.test(.POST, "/hello/vapor") { res inXCTAssertEqual(res.status, .notFound) }.test(.GET, "/hello/vapor/development") { res inXCTAssertEqual(res.status, .ok) XCTAssertEqual(res.body.string, #"["vapor","development"]"#) }
    
    • 🛠 Fixed an issue causing Request.query.get / Request.query.subscript to crash. (#2018)
  • v4.0.0-alpha.2

    August 02, 2019
    • ⚡️ Updated to OpenCrypto alpha 2 (#2031)
    • ⚡️ Updated to SSWG's official AsyncHTTPClient package (#2031)
    • 🔀 Merged server and client websocket code into WebSocket (#2031)

      // client return WebSocket.connect( to: "ws://echo.websocket.org/", on: req.eventLoop) { ws in ws.send("Hello, world!") ws.onText { ws, text in promise.succeed(text) ws.close().cascadeFailure(to: promise) } }// serverrouter.webSocket("bar") { req, ws in ws.send("Hello, world!") ws.onText { ws, text in promise.succeed(text) ws.close().cascadeFailure(to: promise) } }

    • BCrypt renamed to Bcrypt and included in Vapor (#2031)

      let hash = try Bcrypt.hash("vapor")print(hash) // $2b$12$Lmw/Zx2jSXgxE.r/8uipROCoh64KdPL7/mdEz38EqEFZDEu5JsAH2try Bcrypt.verify("vapor", created: hash) // truetry Bcrypt.verify("foo", created: hash) // false

  • v3.3.3

    February 15, 2020
    • 🌲 Log the request path of a failed request in the ErrorMiddleware (#2170).
  • v3.3.2

    February 10, 2020

    ⚡️ Update due to vulnerability in NIO

    🚀 See https://forums.swift.org/t/swiftnio-security-releases-2-13-1-and-1-14-2/33671 for more information.

  • v3.3.1

    September 18, 2019

    🚀 Semver Patch release

    • 🛠 Fix: Identifier not used in Abort init (#1923 @mikkelu)
    • 🐧 Use FoundationNetworking on Linux for Swift 5.1 (#2028 @joscdk)