Max Rosenbaum
Software developer
Friday, 5 November 2021
Send a binary payload in akka http (play)
I didn't find a clearly documented way to send a byte string in an HTTP response. Fortunately this is a super simple
problem to solve with akka and play. So long as you're able to convert whatever datatype you have (like Array[Byte]
)
to a ByteString
all of the magic happens automatically.
package controllers
import play.api.libs.ws.WSClient
import play.api.mvc._
import javax.inject._
import scala.concurrent.ExecutionContext
import os.Path
// We inject the WSClient so that we can make a HTTP request to place kitten.
class KittenController @Inject()(ws: WSClient, cc: ControllerComponents)
(implicit ec: ExecutionContext) extends AbstractController(cc) {
// `ws` will return a future so we need to use Action.async here
def fromRemoteSource: Action[AnyContent] = Action.async {
ws.url("https://placekitten.com/200/300").get().map { response =>
// Simply take the result (as a ByteString) and set the image headers!
Ok(response.bodyAsBytes).as("image/jpg")
}
}
def fromDisk: Action[AnyContent] = Action {
// os lib is a really nice functional library by Li Haoyi which can be found here:
// https://github.com/com-lihaoyi/os-lib
// `os.pwd` takes the place where sbt was executed and is running from.
val wd: Path = os.pwd
// ByteString converts an Array[Byte]
val image = ByteString(os.read.bytes(wd / "kittens.jpg"))
// Send as normal with the image headers!
Ok(image).as("image/jpg")
}
}