DataStreamRequest: Try it Today!

One of the big features lost in Alamofire 5's new architecture is the ability to stream Data from a server rather than accumulate it in memory. In Alamofire 4, you could set a stream closure on a DataRequest that would be called whenever Data was received, but it was a rather dangerous way to do so. Instead of that sort of modification, I've created a DataStreamRequest type that's optimized for Data streaming. I've prototyped most of the important functionality, including Decodable stream parsing, as well as ensuring most of the other Alamofire features work as expected. You can try it out from the feature/data-streaming branch (requires Xcode 11). Here's a quick example:

AF.streamRequest("https://httpbin.org/stream/1").responseStreamString { output in
    switch output {
    case let .value(string): print(string)
    case .error: print("Error parsing stream.")
    case .complete: print("Stream complete.")
    }
}

I'm still working on the exact naming and API for handling the stream callbacks, so comments are welcome, as well as any additional capabilities you'd like to see when streaming Data from a server.

I didn't see anything in the code for this, but is there a way to hook up a DataStreamRequest as an InputStream for an API that takes one? Iā€™m thinking of something like making an XMLParser with an InputStream as a good example of something this API could help with.

Seems like getBoundStreams would be used to take output from the responseStream closure into the created OutboundStream. I could see what an integrated API looks like.

I've added an asInputStream() method that internally creates the bound pair and streams data through to the InputStream as well as the various streaming closures. However, it seems pretty touchy to the connected bufferSize as to the ability for things like XMLParser to handle the incoming Data properly. e.g. At bufferSize = 512, the added test fails due to an XMLParser error, but at bufferSize = 1024, it works fine. I'm not really sure why, as I'm not super familiar with the Stream APIs. I'm also unsure whether I should be opening the InputStream before returning it, or whether that should be a requirement on the consumer.

1 Like

DataStreamRequest has been updated with a new serialization system, support for content type validation, and various renamed types. Remaining works includes full usage documentation and additional EventMonitor events for streaming.

I believe DataStreamRequest is largely complete. If you haven't tried it yet, please do, we'd like any feedback, especially around the closure types and API, as well as response method naming.

So DataStreamRequest wasn't nearly as complete as I thought, as there was a lot of additional work around error handling and cancellation to do, but it's pretty close now.

Recent changes include:

  • Refactoring of the value passed to the Handler closure. It now captures both the Event enum as well as a CancellationToken which can be used to cancel an ongoing stream.
  • Handler closures now support throwing Errors, and the stream is cancelled when an Error is thrown, so custom actions which fail can end the stream.
  • DataStreamSerializers which produce errors can now automatically end the stream as well by passing the new automaticallyCancelOnStreamError parameter when creating streams.

There's still some question as to whether the error handling should be the same between closure errors and serializer errors, but I think that 's the last big design issue.

Here's an up to date example:

AF.streamRequest(...).responseStream { stream in
    switch stream.event {
    case let .stream(result): // Process incoming Data.
    case let .complete(completion): // Process the completion of the stream.
    }

    // If you want to cancel the stream.
    stream.cancel()
}

It also supports responseString for UTF8 strings, and responseDecodable for any Decodable type.

Terms of Service

Privacy Policy

Cookie Policy