[Scala]Circeでリストの各要素をパースの成否ごとに蓄積する

Circeでリストの各要素を個別にパースして成否別に取り出すデコーダーを導出しました。
2024.02.17

はじめに

リスト内に複数の要素を含むJSONをパースする際に、いくつかの要素のパースに失敗してもそれ以外の要素のパースに成功する場合は成功したものだけを取り出したい場合があります。 Circeでパーサーを合成すると簡単にできるので試してみました。

やりたいこと

入力のJSONは下記のようなものです。この例では3番目の要素のnameの型が正しくありません。

[
 { "name": "nyan"},
 { "name": "miaou"},
 { "name": 1234},
 { "name": "miaou"}
]

このJSONをパースした結果以下のようなリストを得たいです。

final case class Cat(name: String)
List(
    Right(value = Cat(name = "nyan")),
    Right(value = Cat(name = "meow")),
    Left(value = DecodingFailure at .name: Got value '1234' with wrong type, expecting string),
    Right(value = Cat(name = "miaou"))
  ) // List[Either[ParsingFailure, Cat]]

またエラーとパース済み値を別々のリストで受け取りたいです。

(
  List(DecodingFailure at .name: Got value '1234' with wrong type, expecting string),
  List(Cat(name = "miaou"), Cat(name = "meow"), Cat(name = "nyan"))
) //(List[DecodingFailure], List[Cat])

コード

既存のデコーダーを使ってそれぞれのデコーダーを導出できます。

出力

Right(
  value = (
    List(DecodingFailure at .name: Got value '1234' with wrong type, expecting string),
    List(Cat(name = "miaou"), Cat(name = "meow"), Cat(name = "nyan"))
  )
)

まとめ

リストの要素をパースの成否ごとに分割できるデコーダーを導出しました。