Elm:如何从JSON API解码数据

18

我有一组数据,使用http://jsonapi.org/格式:

{
    "data": [
        {
            "type": "prospect",
            "id": "1",
            "attributes": {
                "provider_user_id": "1",
                "provider": "facebook",
                "name": "Julia",
                "invitation_id": 25
            }
        },
        {
            "type": "prospect",
            "id": "2",
            "attributes": {
                "provider_user_id": "2",
                "provider": "facebook",
                "name": "Sam",
                "invitation_id": 23
            }
        }
    ]
}

我有这样的模型:

type alias Model = {
  id: Int,
  invitation: Int,
  name: String,
  provider: String,
  provider_user_id: Int
 }

 type alias Collection = List Model

我想将JSON解码成Collection,但不知道该怎么做。

fetchAll: Effects Actions.Action
fetchAll =
  Http.get decoder (Http.url prospectsUrl [])
   |> Task.toResult
   |> Task.map Actions.FetchSuccess
   |> Effects.task

decoder: Json.Decode.Decoder Collection
decoder =
  ?

我该如何实现解码器?谢谢

1个回答

25

注:请参考Json.Decode文档

尝试这样做:

import Json.Decode as Decode exposing (Decoder)
import String

-- <SNIP>

stringToInt : Decoder String -> Decoder Int
stringToInt d =
  Decode.customDecoder d String.toInt

decoder : Decoder Model
decoder =
  Decode.map5 Model
    (Decode.field "id" Decode.string |> stringToInt )
    (Decode.at ["attributes", "invitation_id"] Decode.int)
    (Decode.at ["attributes", "name"] Decode.string)
    (Decode.at ["attributes", "provider"] Decode.string)
    (Decode.at ["attributes", "provider_user_id"] Decode.string |> stringToInt)

decoderColl : Decoder Collection
decoderColl =
  Decode.map identity
    (Decode.field "data" (Decode.list decoder))

关键在于使用stringToInt将字符串字段转换为整数。我按照API示例,确定了什么是int和什么是string。我们有一点运气,因为String.toInt返回了一个Result,这正是customDecoder所期望的,但也足够灵活,可以更加复杂地接受两者。通常你会使用map来完成这样的操作;customDecoder本质上是用于处理可能失败的函数的map

另一个技巧是使用Decode.at来进入attributes子对象内部。


如果您还解释如何将一个值映射到Result中,那么我可能会很有用。 - Guilhem Soulas
OP 只是询问如何实现解码器(Decoder)。若要获得结果,请调用 Json.Decode.decodeStringdecodeValue - mgold
1
而现在 := 变成了 Decode.field。我已经更新了示例。 - mgold
最后一步现在应该是decoderColl = Decode.map identity (Decode.field "data" (Decode.list decoder)) - Eric Walker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接