Books

Play 2.5 has made several major changes to how it streams data and response bodies.

Play 2.5 uses Akka Streams for streaming. Previous versions of Play used iteratees for streaming as well as several other ad-hoc types of streaming, such as WebSocket, Chunks, etc.

There are two main benefits of the change to use Akka Streams. First, Java users can now access the full feature set of Play, e.g. writing body parsers and filters. Second, the streaming library is now more consistent across Play.

Play 2.5 uses ByteString to hold packets of bytes. Previously, Play used byte arrays (byte[]/ArrayByte) to hold bytes.

The ByteString class is immutable like Java’s String, so it’s safer and easier to use. Like String it does have a small performance cost, because it copies its data when it is constructed, but this is balanced by its cheap concatenation and substring operations.

Play 2.5 has a new HttpEntity type for response bodies. Previously response bodies were a plain stream of bytes. HTTP bodies are now a type of HttpEntity: Strict, Streamed or Chunked.

By telling Play what type of entity to use, applications can have more control over how Play sends HTTP responses. It also makes it easier for Play to optimize how it delivers the body.

In Play 2.4 you would create chunked results in Scala with an Enumerator and in Java with a Results.Chunked object. In Play 2.5 these parts of the API are still available, but they have been deprecated.

If you choose to migrate to the new API, you can create a chunked result by calling the chunked method on a StatusHeader object and providing an Akka Streams Source object for the stream of chunks.

More advanced users may prefer to explicitly create an HttpEntity.Chunked object and pass it into the Result object constructor.

In Play 2.4 Scala users could stream results by passing an Enumerator to the feed or stream method. (Java users didn’t have a way to stream results, apart from chunked results.) The feed method streamed the Enumerator’s data then closed the connection. The stream method, either streamed or chunked the result and possibly closed the connection, depending on the HTTP version of the connection and the presence or absence of the Content-Length header.

In Play 2.5, the stream method has been removed and the feed method has been deprecated. You can choose whether or not to migrate the feed method to the new API. If you use the stream method your code will need to be changed.

The new API is to create a Result object directly and choose an HttpEntity to represent its body. For streamed results, you can use the HttpEntity.Streamed class. The Streamed class takes a Source as a body and an optional Content-Length header value. The Source’s content will be sent to the client. If the entity has a Content-Length header then the connection will be left open, otherwise it will be closed to signal the end of the stream.

In Play 2.4, a WebSocket’s bidirectional stream was represented in Java with a pair of WebSocket.In and WebSocket.Out objects and in Scala with a pair of Enumerator and Iteratee objects. In Play 2.5, both Java and Scala now use an Akka Streams Flow to represent the bidirectional stream.

To migrate your WebSockets code in Play 2.5 you have two options.

The first option is to use the old Play API, which has been deprecated and renamed to LegacyWebSocket. This is the easiest option. You just need to change your code that refers to WebSocket to refer to LegacyWebSocket instead. The LegacyWebSocket class gives you an easy migration path from Play 2.4 to Play 2.5.

The second option is to change to the new Play API. To do this you’ll need to change your WebSocket code to use an Akka Streams Flow object.

The Play 2.4 Scala WebSocket API requires an Enumerator/Iteratee pair that produces In objects and consumes Out objects. A pair of FrameFormatters handle the job of getting the data out of the In and Out objects.

The Play 2.5 Scala WebSocket API is built around a Flow of Messages. A Message represents a WebSocket frame. The MessageFlowTransformer type handles transforming high-level objects, like JSON, XML and bytes into Message frames. A set of built-in implicit MessageFlowTransformers are provided, and you can also write your own.

To migrate, you’ll need to translate the bidirectional Enumerator/Iteratee stream into a Flow. You may also need to convert your In/Out objects into Messages using a MessageFlowTransformer, although this is not necessary for common types like JSON, since some built-in implicit conversions are provided.

To use [Comet](https://en.wikipedia.org/wiki/Comet_(programming)) in Play you need to produce a chunked HTTP response with specially formatted chunks. Play has a Comet class to help produce events on the server that can be sent to the browser. In Play 2.4.x, a new Comet instance had to be created and used callbacks for Java, and an Enumeratee was used for Scala. In Play 2.5, there are new APIs added based on Akka Streams.

Create an Akka Streams source for your objects, and convert them into either String or JsonNode objects. From there, you can use play.libs.Comet.string or play.libs.Comet.json to convert your objects into a format suitable for Results.ok().chunked(). There is additional documentation in JavaComet.

Because the Java Comet helper is based around callbacks, it may be easier to turn the callback based class into a org.reactivestreams.Publisher directly and use Source.fromPublisher to create a source.

Create an Akka Streams source for your objects, and convert them into either String or JsValue objects. From there, you can use play.api.libs.Comet.string or play.api.libs.Comet.json to convert your objects into a format suitable for Ok.chunked(). There is additional documentation in ScalaComet.

To use Server-Sent Events in Play you need to produce a chunked HTTP response with specially formatted chunks. Play has an EventSource interface to help produce events on the server that can be sent to the browser. In Play 2.4 Java and Scala each had quite different APIs, but in Play 2.5 they have been changed so they’re both based on Akka Streams.

In Play 2.4’s Java API you produce your stream of chunks with EventSource, which is a class that extends Chunks<String>. You can construct Event objects from strings or JSON objects and then send them in the response by calling EventSource’s send method.

In Play 2.5 you’ll typically create an Akka Streams Source for your application objects, use Source.map to convert your objects to Events then finally use EventSource.chunked to convert the Events into chunked values. The example below shows how this works for sending a stream of strings.

To migrate EventSource.onConnected, EventSource.send, etc to a Source, implement org.reactivestreams.Publisher on the class and use Source.fromPublisher to create a source from the callbacks.

If you still want to use the same API as in Play 2.4 you can use the LegacyEventSource class. This class is the same as the Play 2.4 API, but it has been renamed and deprecated. If you want to use the new API, but retain the same feel as the old imperative API, you can try GraphStage.

To use Play 2.4’s Scala API you provide an Enumerator of application objects then use the EventSourceEnumeratee to convert them into Events. Finally you pass the Events to the chunked method where they’re converted into chunks.

In Play 2.5 using EventSource with Enumerators and Enumeratees has been deprecated. You can still use an Enumerator and Enumeratee, but it is recommended that you convert your code to use a Source and a Flow instead. The Source produces the stream of objects and EventSource.flow’s Flow converts them into Events. For example, code above would be rewritten as:

Most Scala users will use the Action class for their actions. The Action class is a type of EssentialAction that always parses its body fully before running its logic and sending a result. Some users may have written their own custom EssentialActions so that they can do things like incrementally processing the request body.

If you’re only using normal Actions in your Play 2.4 application then they do not need any migration. However, if you’ve written an EssentialAction, then you’ll need to migrate it to the new API in Play 2.5. The behavior of an EssentialAction is still the same, but the signature has changed from Play 2.4:

The Result object has changed how it represents the result body and the connection close flag. Instead of taking body: Enumerator[Array[Byte]], connection: Connection, it now takes body: HttpEntity. The HttpEntity type contains information about the body and implicit information about how to close the connection.

You can migrate your existing Enumerator by using a Streamed entity that contains a Source and an optional Content-Length and Content-Type header.

This section explains how to migrate your byte arrays and streams to the new Akka Streams APIs.

Akka Streams is part of the Akka project. Play uses Akka Streams to provide streaming functionality: sending and receiving sequences of bytes and other objects. The Akka project has a lot of good documentation about Akka Streams. Before you start using Akka Streams in Play it is worth looking at the Akka Streams documentation to see what information is available.

When you’re first getting started with Akka Streams, the Basics and working with Flows section of the Akka documentation is worth a look. It will introduce you to the most important parts of the Akka Streams API.

You don’t need to convert your whole application in one go. Parts of your application can keep using iteratees while other parts use Akka Streams. Akka Streams provides a reactive streams implementation, and Play’s iteratees library also provides a reactive streams implementation, consequently, Play’s iteratees can easily be wrapped in Akka Streams and vice versa.

// Get the empty ByteString (this instance is cached)
ByteString.empty
// Create a ByteString from a String
ByteString("hello")
ByteString.fromString("hello")
// Create a ByteString from an Array[Byte]
ByteString(arr)
ByteString.fromArray(arr)

Java:

// Get the empty ByteString (this instance is cached)
ByteString.empty();
// Create a ByteString from a String
ByteString.fromString("hello");
// Create a ByteString from an Array[Byte]
ByteString.fromArray(arr);

Play now uses a Source to generate events instead of its old WebSocket.Out, Chunks.Out and EventSource.Out classes. These classes were simple to use, but they were inflexible and they didn’t implement backpressure properly.

You can replace your *.Out class with any Source that produces a stream. There are lots of ways to create Sources (Java/Scala.

If you want to replace your *.Out with a simple object that you can write messages to and then close, without worrying about back pressure, then you can use the Source.actorRef method:

If you use Results.chunked or Results.feed you can continue to use the existing methods. These methods have been deprecated, so you may want to change your code anyway.

Step 2: Convert Enumerator to Source with an adapter

You can convert your existing Enumerator to a Source by first converting it to a reactive streams Publisher using Streams.enumeratorToPublisher, and then you can convert the publisher to a source using Source.fromPublisher, for example:

You can convert your existing Iteratee to a Sink by first converting it to a reactive streams Subscriber using Streams.iterateeToSubscriber, and then you can convert the subscriber to a sink using Sink.fromSubscriber, for example:

You can convert your existing Enumeratee to a Flow by first converting it to a reactive streams Processor using Streams.enumerateeToProcessor, and then you can convert the processor to a flow using Flow.fromProcessor, for example: