September 11, 2024

Circe JSON: Use JsonObject instead of cursors

I’m using the Circe JSON library at work. I am not a fan of it. I recommend to stay away from it. Luckily I rarely have to touch JSON parsing code paths.

What makes my blood boil the most with Circe is small ad-hoc JSON parsing, where I need to extra some values from JSON, without going to create boiler plate class for it. [1]

My expectation for something like that I get a Map, maybe an extended map with some convenience functions. However, the Circe documentation guides you towards their cursor API for that. That API is (censored/insert swearwords/rant here).

Turning JSON complicated
Figure 1. Turning JSON complicated

Use the JsonObject instead

However, Circe has a way better API! That API isn’t awesome, but way closer to the Map API you expect. You can ask Circe to provide you with a JsonObject, that is a reasonable way to navigate to things:

val jsonBody = for {
  parsed  <- io.circe.parser.parse(result.body)
  jsonObj <- parsed.as[JsonObject]
} yield jsonObj

jsonBody match {
  case Right(jsonObj) =>

    val asMap: Map[String, Json] = jsonObj.toMap // you get an actual scala map
    val theField: Option[Json] =jsonObj("myField") // Access a field
    val aValue = theField.flatMap(_.asString)  // there are asString, asArray, asObject etc convenience functions
    val isNull = theField.map(_.isArray) // there are isNull, isString, isArray, isObject etc convenience functions

    // That's about it...these functions are way closer to standard Scala stuff
  case Left(error) => throw error // your error handling
}

1. Oh man, do I miss Clojure in these situations, to get away from Life-Sucking.
Tags: Scala Development