Will SwiftNIO adapt to the new Combine framework?

Great question!

Short version: Combine and SwiftNIO are a natural fit so yes, we will build tools to make them work together really well without much boilerplate. Starting probably with a simple ChannelHandler that will surface the values that flow through the ChannelPipeline as a Publisher. Best news is you can get started with that today!


Longer version:

The great thing is that Combine is a solution to a problem that libraries built with SwiftNIO have been struggling with: streaming data in a user-friendly way. SwiftNIO is a great way to do bi-directional streaming whilst retaining full control over more low-level network details. That makes SwiftNIO a great tool to develop many many networking protocols. At the end of the day however not every user who wants to just use a network library (for example an HTTP library) that happens to be implemented with NIO should be required to learn all about SwiftNIO's ChannelPipeline and ChannelHandlers in order to do something as common as issuing a HTTP request. That's why we always say 'SwiftNIO is a library to write networking libraries and applications'.

So far, higher-level libraries built in SwiftNIO fell into two cases:

  1. The ones where it's quite straightforward to develop a user-friendly API which are the ones that work 'one shot' (have unary requests/responses). For example imagine an HTTP request where the user wants the HTTP body back in one shot. Defining such an API is easy: func get(url: URL) -> EventLoopFuture<Data> for example.
  2. The cases where a 'one shot' call is not good enough because you need to stream the data because it might be too large to fit into memory in its entirety or might simply need to be processed bit by bit. Whilst these things are very easy to deal with in the NIO layer, finding a good user facing API for this was not. In those cases, library authors had to always invent an ad-hoc streaming abstraction for example with delegates or callbacks. Whilst that works, every single time things like the API and important back-pressure need to be reinvented. An example can be seen in the HTTP client proposal.

"Combine" does solve the 'streaming values over time' problem once and for all and that is great news for everybody, not just people who want to create a nice API for something built with SwiftNIO.

The other thing that I should mention is that the story for SwiftNIO & Combine is slightly different to SwiftNIO & Network.framework however. For Network.framework, SwiftNIO needed to add new fundamental core capabilities (like Channels, Bootstraps, and EventLoops that work with Network.framework). For Combine, everything is much simpler because Combine is a great too to surface something that's written with SwiftNIO in a good user-facing API. Fundamentally, Network.framework was a new way for SwiftNIO to use the system whilst Combine is a new way for libraries (using SwiftNIO or not) to design APIs. So in Network.framework's case the NIO team had to provide support whilst in Combine's case SwiftNIO might provide common tools but you can start NIO & Combine together today and together we can find common pieces that are used to bridge NIO & Combine and add them into SwiftNIO to save higher-level library developers for solving the same problems over and over again.

Likely the first thing I'd like to see in SwiftNIO itself is something akin to RequestResponseHandler which is a generic solution to make simple func doRequest(_ request: Request) -> EventLoopFuture<Response> kind of APIs out of a SwiftNIO ChannelPipeline. For Combine, we could start with a ChannelHandler that can do the same but not only for unary request types but for things that support streaming, like for example HTTP request/response bodies.

11 Likes