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).
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
}