Ignore invalid item when decoding list
Generally the way you can deal with these is by decoding it to an Elm type that expresses the options, and then post processing with a map
.
So for instance in your example, I would go for something like this:
decodeMaybeType : Decoder (Maybe Type)
decodeMaybeType =
Decode.string
|> Decode.map getTypeFromString
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.map2 (\maybeType index -> Maybe.map (\t -> Section t index) maybeType)
(Decode.field "type" decodeMaybeType)
(Decode.field "index" Decode.int)
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)
NB: List.filterMap identity
is a List (Maybe a) -> List a
, it filters out the Nothing
and gets rid of the Maybe
s in one go.
Given the comment by Quan Vo about one of many fields could be invalid, using Decode.oneOf
might be a better fit.
You write the decoders for each field. If any field is illegal, the Section
decoder fails and in oneOf
, Nothing
is returned.
(Here I am also using Json.Decode.Pipeline
from NoRedInk).
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (required)
type Type
= A
| B
type alias Section =
{ sectionType : Type
, index : Int
}
getTypeFromString : String -> Maybe Type
getTypeFromString input =
case input |> String.toLower of
"a" ->
Just A
"b" ->
Just B
_ ->
Nothing
decodeType : Decoder Type
decodeType =
Decode.string
|> Decode.andThen
(\str ->
case getTypeFromString str of
Just sectionType ->
Decode.succeed sectionType
Nothing ->
Decode.fail <| ("Unknown type" ++ str)
)
decodeSection : Decoder Section
decodeSection =
Decode.succeed Section
|> required "type" decodeType
|> required "index" Decode.int
-- Either we succeed in decoding a Section or fail on some field.
decodeMaybeSection : Decoder (Maybe Section)
decodeMaybeSection =
Decode.oneOf
[ decodeSection |> Decode.map Just
, Decode.succeed Nothing
]
decodeSections : Decoder (List Section)
decodeSections =
Decode.list decodeMaybeSection
|> Decode.map (List.filterMap identity)