Skip to content

Instantly share code, notes, and snippets.

@focusaurus focusaurus/A.elm
Created Dec 5, 2016

Embed
What would you like to do?
Decode JSON string enum into elm union type
module A exposing (..)
import Json.Decode as JD
import Json.Encode as JE
type alias User =
{ id : Int
, theme : Theme
}
type Theme
= Light
| Dark
userDecoder =
(JD.map2 User
( JD.field "id" JD.int )
( JD.field "theme" decodeTheme )
)
-- Can't figure out how to make a custom Json.Decoder.Decoder a
decodeTheme toDecode =
let
valueDe =
JD.decodeString JD.string toDecode
in
case valueDe of
Ok name ->
if (String.toLower name) == "light" then
Light
else
Dark
Err msg ->
Dark
@1602

This comment has been minimized.

Copy link

commented Jul 18, 2017

Replace your decodeTheme function with the following themeDecoder

themeDecoder : Decoder Theme
themeDecoder =
    Decode.string
        |> Decode.andThen (\str ->
           case str of
                "Light" ->
                    Decode.succeed Light
                "Dark" ->
                    Decode.succeed Dark
                somethingElse ->
                    Decode.fail <| "Unknown theme: " ++ somethingElse
        )
@crypticmind

This comment has been minimized.

Copy link

commented Jun 2, 2018

@1602 that's a cool example about custom decoders that should be in the docs.

@raoul2000

This comment has been minimized.

Copy link

commented Jun 27, 2018

👍

@nahiyan

This comment has been minimized.

Copy link

commented Jan 19, 2019

When you want to address "something else" in your case expression, just use "_" but please refrain from using keywords like "somethingElse" in your example, it can be misleading to beginners.

@raphaelpereira

This comment has been minimized.

Copy link

commented Jan 23, 2019

@nahiyan @1602 used "somethingElse" to include it on error message.

@nqthqn

This comment has been minimized.

Copy link

commented Mar 3, 2019

Maybe call it unknownTheme

@LimmaPaulus

This comment has been minimized.

Copy link

commented May 24, 2019

How to do this if custom type contains values that should also be decoded from JSON? If, for example, Dark contains Int-value telling how dark it is.

@bbuckley

This comment has been minimized.

Copy link

commented Jun 29, 2019

Can anyone answer LimmaPaulus' question? How would themeDecoder look if Dark had a payload?

type Theme
= Light
| Dark Int

@asonix

This comment has been minimized.

Copy link

commented Jul 10, 2019

I haven't tried this myself, but this is what I imagine would work

So your JSON might look like

{
    "theme": "Light"
}

or

{
    "theme": ["Dark", 2]
}

So your decoder will need to look like this

type Theme
    = Light
    | Dark Int

type Intermediate =
    Intermediate String (Maybe Int)

decoder : Decoder Theme
decoder =
    Decode.map2 Intermediate (index 0 Decode.string) (index 1 Decode.maybe <| Decode.int)
        |> Decode.andThen fromIntermediate

fromIntermediate : Intermediate -> Decoder Theme
fromIntermediate (Intermediate string maybeInt) =
    case (string, maybeInt) of
        ("light", Nothing) ->
            Decode.succeed Light

        ("dark", Just int) ->
            Decode.succeed <| Dark int

        other ->
            Decode.fail "Invalid json"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.