Search code examples
scalacirce

Reuse Decoder For Different JSON payloads


I have the following JSON structure:

{
   "e":[],
   "r":{
      "foo":[
         [
            "abc",
            1
         ],
         [
            "def",
            2
         ],

      ]
   }
}

I am trying to decode this structure and have set up the following case class:

case class Baz(e : List[String], r : List[Data])

where Data is

case class Data(a : String, b : Int)

So I setup my circe decoder as follows:

object Data{
  implicit val decoder : Decoder[Data]  (c : HCursor) =>
   for {
     a <- c.downN(0).as[String]
     b <- c.downN(1).as[Int]
   }yield(Data(a,b))
  }

The obvious implementation for the Baz decoder is


object Baz{
 implicit val decoder : Decoder[Baz]  (c : HCursor) =>
 for {
   e <- c.downField("e").as[List[String]]
   r <- c.downField("r").downField("foo").as[List[Data]]
}yield(Baz(e,r))

}

However, I would like to use the same Baz decoder for other JSON values which only differ in the key name "foo". That is, "foo" could be something else like "bar".

How do I tell/move the cursor so that it works irrespective of the value of the key for the List[Data]?


Solution

  • Using a Map encoding will allow you to re-use the decoder and slurp any JSON value of the same structure:

    
    object Baz{
     implicit val decoder : Decoder[Baz]  (c : HCursor) =>
     for {
       e <- c.downField("e").as[List[String]]
       r <- c.downField("r").as[Map[String, List[Data]]]
     }yield(Baz(e,r))
    }