Link Signing With Play JSON

Play provides powerful tools for (de)serializing and manipulating JSON values but this power isn't always obvious from the documentation. One problem we recently encountered was signing links to S3 objects before they were serialized to JSON.

Consider that we have a case class that contains some path to an object in S3 and we have a function that given that path returns a signed URL.

case class S3File(id: String, path: String)

object S3File {
  implicit def s3FileFormat: Format[S3File] = Json.format[S3File]

  def generateSignedLink(path: String): String = ???
}

Taking advantages of Play’s JSON transformers we wrote a Writes instance that picks out the “path” value and updates it with a new value which in this case is the signed URL.

Now whenever we have a need for a JSON value with the signed S3 link in it we can easily override the implicit JSON formatter with this new Writes instance.

object S3File {
  // ...
  def linkSigningWrites: Writes[S3File] = s3FileFormat.writes.transform(
    (JsPath \ "path").json.update(JsPath.read[JsString].map(path => {
      JsString(generateSignedLink(path))
    }))
  )
}

import S3File

object HelloWorldController extends Controller {
  def index = {
    val file = S3File("id", "path/to/file")
    val json = Json.toJson(file)(S3File.linkSigningS3FileWrites)
    Ok(json)
  }  
}

Built With: Play 2.3.8, Scala 2.10.5