我想解码一个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
}
一些有效的JSON响应会有这些形状:
{
"name": "Foo electric machine",
"category": "electric",
"configuration": {
"voltage": 12
}
}
{
"name": "Bar mechanical machine",
"category": "mechanical",
"configuration": {
"gears": 5
}
}
{
"name": "Some machine of unknown category",
"category": "foo"
}
我尝试了与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
事实上,我还没有在同时使用Json.Decode.Pipeline
和andThen
的网络或文档上看过任何示例,所以我不确定它是否会&#39甚至可能。
我已经设置了此问题的在线示例,说明了如何解码条件部分:https://runelm.io/c/3ut
答案 0 :(得分:4)
作为替代方案,您可以将andThen
绑定放在管道(ellie example)之前:
decoder : Decoder Machine
decoder =
field "category" string
|> andThen catDec
|> andThen
(\cat ->
decode Machine
|> required "name" string
|> hardcoded cat
)
如果您的mapN
号码用完,请考虑在andMap
包中切换到|:
(或中缀版本elm-community/json-extra
)。
答案 1 :(得分:4)
Chad Gilbert's answer正常工作(谢谢!)并引导我阅读Json.Decode.Pipeline
源代码,以了解更多有关管道如何实施的信息,并且我找到了另一种解决方案有点简洁,所以我想在这里分享它:
decoder : Decoder Machine
decoder =
decode Machine
|> required "name" string
|> custom (field "category" string |> andThen catDec)