The code in this blog post shows how to convert a Seq of Scala objects to their equivalent JSON representation using the Play Framework v2.3. Specifically, I’m working on an application to display Twitter data, and I want to convert a Seq[Tweet] to its JSON.
The goal
My goal in the following code is to return some JSON that looks like this:
[
{"username":"John", "tweet":"Scala rules!", "date":"Mon Sep 23 07:38:13 MDT 2013"},
{"username":"Jane", "tweet":"Play is awesome!", "date":"Mon Sep 23 07:38:15 MDT 2013"},
{"username":"Fred", "tweet":"FP rocks!", "date":"Mon Sep 23 07:38:17 MDT 2013"},
]
I get the actual data by querying Twitter, but that isn’t important. As far as the data source goes, the only important thing is that I call the TwitterDao.getTweetsInListAsSeq method, which returns an Option[Seq[Tweet]], and I create the JSON from that Seq.
The Play Framework Controller
My Play Framework Controller code looks like this:
package controllers
import play.api.mvc._
import play.api.data._
import play.api.libs.json.Json
import play.api.libs.json._
import models._
object Twitter extends Controller {
// returns a list of tweets from a twitter list named "Scala Peeps"
def peeps = Action {
val tweets = TwitterDao.getTweetsInListAsSeq("Scala Peeps") // Option[Seq[Tweet]]
tweets match {
case Some(seqOfTweet) => Ok(convertTweetsToJson(seqOfTweet))
case None => Ok("Bummer, technical error")
}
}
// this works because reads/writes are defined in Format[Tweet]
def convertTweetsToJson(tweets: Seq[Tweet]): JsValue = Json.toJson(tweets)
// more code ...
}
The peeps method in that code is a normal Play Action method. I need to use Async as well, but that’s not important here. (I also have an entry for it in the routes file, connecting it to a URI and request method, but that isn’t important for this example.)
The important code is the convertTweetsToJson method. It used to be much longer, but since I’m now using a Format object, the body of the method is only this:
Json.toJson(tweets)
Because of this, the convertTweetsToJson method isn’t really needed, but I’ve kept it in so you can compare it to a similar method below.
Creating an implicit Format object
To get that code to work I had to define this other code in a file named Tweet.scala:
import play.api.libs.json.Json
import play.api.libs.json._
case class Tweet(
username: String,
tweet: String,
date: String
)
object Tweet {
implicit object TweetFormat extends Format[Tweet] {
// convert from Tweet object to JSON (serializing to JSON)
def writes(tweet: Tweet): JsValue = {
// tweetSeq == Seq[(String, play.api.libs.json.JsString)]
val tweetSeq = Seq(
"username" -> JsString(tweet.username),
"tweet" -> JsString(tweet.tweet),
"date" -> JsString(tweet.date)
)
JsObject(tweetSeq)
}
// convert from JSON string to a Tweet object (de-serializing from JSON)
// (i don't need this method; just here to satisfy the api)
def reads(json: JsValue): JsResult[Tweet] = {
JsSuccess(Tweet("", "", ""))
}
}
}
The important part of this code is the writes method in the implicit TweetFormat object; it’s used to serialize the Scala object Tweet to its JSON representation. The code shown is a fairly standard implementation of this method.
Given all of that code, my peeps method returns the desired JSON.
Another approach
Before I thought to use the approach of creating an implicit Format object, my convertTweetsToJson method looked like this:
def convertTweetsToJsonOrig(tweets: Seq[Tweet]): JsValue = {
Json.toJson(
tweets.map { t =>
Map("username" -> t.username, "tweet" -> t.tweet, "date" -> t.date)
}
)
}
This code returns the same JSON as the previous approach, and it’s also simpler. I also think it’s a great use of the map method. (I found an example like this in the Play docs.) Frankly, for my purposes, I’ll probably go back to using it, but I wanted to show the other approach because it may come in handy in other situations.

