我想解码一个 API 响应,其中一个字段值 ( category) 将决定如何configuration使用不同的子解码器解码另一个字段 ( )。
我能够使用Json.Decode.mapn函数和andThen函数来完成这样的事情,但我想知道是否有任何方法可以使用elm-decode-pipeline它来做这样的事情,因为它有一个更好的 API,我mapn最终会用完函数。
一个最小的和有点微不足道的例子是这样的:
type alias Machine =
{ name : String
, specs : MachineSpecs
}
type MachineSpecs
= ElectricMachine ElectricSpecs
| MechanicalMachine MechanicalSpecs
| UnknownMachine
type alias ElectricSpecs =
{ voltage : Int
}
type alias MechanicalSpecs =
{ gears : Int
}
Run Code Online (Sandbox Code Playgroud)
一些有效的 JSON 响应将具有以下形状:
{
"name": "Foo electric machine",
"category": "electric",
"configuration": {
"voltage": 12
}
}
Run Code Online (Sandbox Code Playgroud)
{
"name": "Bar mechanical machine",
"category": "mechanical",
"configuration": {
"gears": 5
}
}
Run Code Online (Sandbox Code Playgroud)
{
"name": "Some machine of unknown category",
"category": "foo"
}
Run Code Online (Sandbox Code Playgroud)
我尝试了一种与我在mapn函数中使用的方法类似的方法,但它不起作用。
decoder : Decoder Machine
decoder =
decode Machine
|> required "name" string
|> required "category" (string |> andThen catDec)
catDec : String -> Decoder MachineSpecs
catDec cat =
case cat of
"electric" ->
map ElectricMachine electricDecoder
"mechanical" ->
map MechanicalMachine mechanicalDecoder
_ ->
succeed UnknownMachine
electricDecoder : Decoder ElectricSpecs
electricDecoder =
decode ElectricSpecs
|> requiredAt [ "configuration", "voltage" ] int
mechanicalDecoder : Decoder MechanicalSpecs
mechanicalDecoder =
decode MechanicalSpecs
|> requiredAt [ "configuration", "gears" ] int
Run Code Online (Sandbox Code Playgroud)
事实上,我还没有看到网上或同时使用的文档上的任何实例Json.Decode.Pipeline,并andThen在同一时间,所以我不知道,如果它甚至有可能。
我已经设置了这个问题的在线示例,显示它如何无法解码条件部分:https : //runelm.io/c/3ut
作为替代方案,您可以将andThen绑定放在管道之前(ellie 示例):
decoder : Decoder Machine
decoder =
field "category" string
|> andThen catDec
|> andThen
(\cat ->
decode Machine
|> required "name" string
|> hardcoded cat
)
Run Code Online (Sandbox Code Playgroud)
如果您的mapN号码用完,请考虑切换到包中的andMap(或中缀版本|:)elm-community/json-extra。
Chad Gilbert 的回答很有效(谢谢!)它引导我阅读Json.Decode.Pipeline源代码以更多地了解管道是如何实现的,并且我找到了一个更简洁的替代解决方案,所以我想分享它这里:
decoder : Decoder Machine
decoder =
decode Machine
|> required "name" string
|> custom (field "category" string |> andThen catDec)
Run Code Online (Sandbox Code Playgroud)