All Versions
59
Latest Version
Avg Release Cycle
6 days
Latest Release
1217 days ago

Changelog History
Page 6

  • v4.0.0-beta.1 Changes

    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 Changes

    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 Changes

    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-alpha.1 Changes

    May 31, 2019

    ๐Ÿš€ More information on Vapor 4 alpha releases:

    ๐Ÿš€ https://medium.com/@codevapor/vapor-4-alpha-1-releases-begin-94a4bc79dd9a

    ๐Ÿ“„ API Docs:

    https://api.vapor.codes/vapor/master/Vapor/index.html

  • v3.3.3 Changes

    February 15, 2020
    • ๐ŸŒฒ Log the request path of a failed request in the ErrorMiddleware (#2170).
  • v3.3.2 Changes

    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 Changes

    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)
  • v3.3.0 Changes

    February 28, 2019

    ๐Ÿ†• New:

    • โž• Adds new supportCompression member to NIOServerConfig. When true, HTTP server will support gzip and deflate. (#1909)
    • ๐Ÿ‘€ ErrorMiddleware now checks for and utilizes ResponseEncodable conformance on errors. (#1875)
  • v3.2.2 Changes

    February 15, 2019

    ๐Ÿ†• New:

    ๐Ÿ›  Fixed:

    • โช Reverted retain cycle fix that could cause Application to not deinit. (#1898).