0

I'm looking for a most elegant way to traverse a list of objects with multiple fields in Json with circe optics.

Let's say we have this sort of JSON:

[
  {
    "key1": "one",
    "key2": "two"
  },
  {
    "key1": "three",
    "key2": "four"
  }
]

and we have a case class case class Entity(key1: String, key2: String)

So I want to find the most elegant and sleek way to traverse this JSON and create a list of case objects in the end.

I know that I can use each: root.each.key1.string.getAll(json), but how would I build a lens that will give me a traversable tuple (?) or something that I could put into for comprehension. I can probably combine lenses somehow.

There's already a question like that (how to parse un Array of object with Circe) but it has only one field in each object.

Konstantin Bodnia
  • 1,372
  • 3
  • 20
  • 43
  • 1
    Do you really need optics? Why not just `json.as[List[Entity]]`? – Luis Miguel Mejía Suárez Aug 07 '20 at 13:36
  • @LuisMiguelMejíaSuárez because my example is a very simple one. In fact I need to do a little bit more than just create case objects out of JSON response. – Konstantin Bodnia Aug 07 '20 at 14:02
  • and also compiler gives me an error: Error:could not find implicit value for parameter d: io.circe.Decoder[List[blah.blah.Entity]] json.as[List[Entity]] – Konstantin Bodnia Aug 07 '20 at 14:20
  • 1
    Well, you have to derive the decoder of `Entity` either manually, automatically, or semi-automatically. That is basic **circe** usage than since you asked for optics _(which is advanced usage)_ I assumed you already had. What else do you need to do apart from instantiating the classes from the json. – Luis Miguel Mejía Suárez Aug 07 '20 at 14:25

1 Answers1

0

Recently I was also trying to solve a very similar problem: I wanted to implement with circe-json what would be the equivalent of the following jq line:

cat json | jq '.[] | {key1: .key1, key2: .key2}'

The closest I got was this:

import io.circe.optics.JsonPath.root

root.each.json.getAll(json)
  .map(j => (root.key1.string.getOption(j).get, root.key2.string.getOption(j).get))
  .map(Entity.apply)
dvim
  • 2,223
  • 1
  • 17
  • 17