Circe의 수동 디코더를 사용하여 고정되지 않은 json 배열을 어떻게 역 직렬화 할 수 있습니까?

alt-f4

다음과 같은 JSON이 있습니다.

{
  "data": [
    {
      "id": "1",
      "email": "[email protected]",
      "name": "Mr foo",
      "roles": [
        "Chief Bar Officer"
      ],
      "avatar_url": null,
      "phone_number": null
    },
    {
      "id": "2",
      "email": "[email protected]",
      "name": "Mr baz",
      "roles": [
        "Chief Baz Officer"
      ],
      "avatar_url": null,
      "phone_number": null
    }
  ]
}

저는 주로 데이터 목록을 구문 분석 / 역 직렬화하는 데 관심이 있으며 수동으로 수행하고 싶습니다 (신비한 이유로 수동 방식을 선호합니다).

이것이 관련이있는 경우, 나는 .NET을 sttp.client.circe._사용하여 Json으로 직접 get 요청에서 들어오는 데이터를 구문 분석 할 목적으로 sttp의 circe 라이브러리 를 사용하고 asJson있습니다.

get sttp 요청은 다음과 같습니다.

val r1 = basicRequest
    .get(uri"https://woooo.woo.wo/v1/users")
    .header("accept", "application/json")
    .header("Authorization", "topsecret"
    .response(asJson[SomeClass])

이것이 내가 지금까지 시도한 것입니다.

// Define the case class
case class User(
    id: String,
    email: String,
    name: String,
    roles: List[String],
    avatar_url: Option[String],
    phone_number: Option[String]
)

// Define the manual deserializer

case object User {

  implicit val userDecoder: Decoder[User] = (hCursor: HCursor) => {
    val data = hCursor.downField("data").downArray
    for {
      id <- data.get[String]("id")
      email <- data.get[String]("email")
      name <- data.get[String]("name")
      roles <- data.get[List[String]]("roles")
      avatarUrl <- data.get[Option[String]]("avatarUrl")
      phoneNumber <- data.get[Option[String]]("phoneNumber")
    } yield User(id, email, name, roles, avatarUrl, phoneNumber)
  }
}

내 접근 방식의 문제는 (내 생각에) .downArray사용자 배열에서 첫 번째 사용자 만 직렬화 한다는 것 입니다.

내 목표는 일련의 사용자 ( List[User]아마도 비슷한 것) 를 가질 수 있도록하는 것이지만, 현재는 배열에서 한 사용자 만 역 직렬화합니다.

"데이터"배열은 고정 된 수의 사용자를 포함하지 않으며 모든 api 호출로 인해 사용자 수가 다를 수 있다는 점을 언급 할 가치가 있습니다.

alt-f4

이 문제를 해결하는 데 도움을 준 Travis Browncirce Gitter 커뮤니티 의 도움에 감사드립니다 .

여기서 Travis를 인용합니다.

최상위 JSON 객체를 구성 적으로 구문 분석하는 데 필요한 인스턴스를 구축하는 것이 좋습니다. 즉, 단일 사용자 JSON 객체 만 디코딩하는 Decoder [User]가 있고 Decoder [List [User]]. at (를 사용합니다. "data") 또는 JSON 배열로 데이터 필드를 포함하는 최상위 JSON 객체를 디코딩하는 것과 유사한 것입니다.

나는 다음과 같은 구현으로 끝났습니다.

case class Users(users: List[User])

case object User {

  implicit val usrDecoder: Decoder[User] = (hCursor: HCursor) => {

    for {
      id <- hCursor.get[String]("id")
      email <- hCursor.get[String]("email")
      name <- hCursor.get[String]("name")
      roles <- hCursor.get[List[String]]("roles")
      avatarUrl <- hCursor.get[Option[String]]("avatarUrl")
      phoneNumber <- hCursor.get[Option[String]]("phoneNumber")
    } yield User(id, email, name, roles, avatarUrl, phoneNumber)
  }

  implicit val decodeUsers: Decoder[Users] =
    Decoder[List[User]].at("data").map(Users)

}

아이디어는 사용자의 디코더와 사용자 모음에 대한 디코더를 별도로 구성하는 것입니다. 그런 다음 UsersDecoder 에 매핑 하여 Decoder의 결과를 Users 케이스 클래스로 래핑합니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관