vsoch / elm-app-catalog

testing development of an app catalog with elm (under development)
2 stars 1 forks source link

Learn json parsing in Elm #2

Open vsoch opened 4 years ago

vsoch commented 4 years ago

Per notes from @ julianpistorius in https://github.com/vsoch/elm-app-catalog/pull/1#issuecomment-617961359 this is the next set of items I should tackle:


I think it's time to get familiar with JSON decoding, as well 'effects' (particularly making HTTP requests). Play around with these two examples:

- https://guide.elm-lang.org/effects/http.html
- https://guide.elm-lang.org/effects/json.html

Try the following:

- Change the views to use Elm-UI functions instead of Html functions
- Modify the JSON example to load the list of SCIF apps from this URL: https://sci-f.github.io/apps/api/index.json

The following resources on JSON decoders will help:

- https://github.com/zwilias/elm-demystify-decoders
- https://thoughtbot.com/blog/5-common-json-decoders
- https://thoughtbot.com/blog/getting-unstuck-with-elm-json-decoders

Once you've written a few simple JSON decoders by hand you might want to look at some of the Elm code generators:

vsoch commented 4 years ago

@julianpistorius how would I combine the previous Model (that had a counter) with another Model subset that includes variables for the state of an app? E.g.,

type alias Model =
    { counter : Int }

type AppModel
  = Failure
  | Loading
  | Success String

and then what I'm trying to figure out is then how to combine the init functions (I'm guessing I can only have one)

init : Model
init =
    { counter = 0 }

init : () -> (AppModel, Cmd Msg)
init _ =
  ( Loading
  , Http.get
      { url = "https://elm-lang.org/assets/public-opinion.txt"
      , expect = Http.expectString GotText
      }
  )

Would I want some combined model like:

type alias Model =
    { counter : Int,
      status: Failure | Loading | Success String}

(what's the difference in having alias or not? I forget if I already asked that. And then for the init, something like:

init : () -> (Model, Cmd Msg)
init _ =
  ( Loading
  , Http.get
      { url = "https://elm-lang.org/assets/public-opinion.txt"
      , expect = Http.expectString GotText
      },
    { counter = 0 }
  )

Sorry these questions probably seem stupid, it will take a while for this functional stuffs to click.

julianpistorius commented 4 years ago

Good questions! Reading...

julianpistorius commented 4 years ago

I'll take this in batches.

Regarding the model, you are close. You probably want something like this:

type AppState
  = Failure
  | Loading
  | Success String

type alias Model =
    { 
        counter : Int 
        , status: AppState
    }
vsoch commented 4 years ago

Ahh I was close! I knew I wanted to add the status to the model, wasn't sure if I should do it inline or define something above. I like how you did it, it's very straight forward.

julianpistorius commented 4 years ago

As for type alias, that's a shorthand so you don't have to refer to a potentially long, complicated type everywhere. See the example here: https://guide.elm-lang.org/types/type_aliases.html

julianpistorius commented 4 years ago

With my hint about the model type, the compiler should guide you to a working version of the init function. Let me know if you get stuck.

vsoch commented 4 years ago

Can I do this then?

init : () -> ( Model, Cmd Msg )
init _ =
    { counter = 0
    , status =
        ( Loading
        , Http.get
            { url = "https://elm-lang.org/assets/public-opinion.txt"
            , expect = Http.expectString GotText
            }
        )
    }

I can keep messing around, I am actually taking a break and editing your podcast! I'm pooped after this week.

julianpistorius commented 4 years ago

No problem. And you're close! You want the init function to return a tuple of type (Model, Cmd Msg ). This means that the first value in the tuple has to be a value that conforms to the Model type, and the second part of the tuple has to something that evaluates to a type of Cmd Msg.

I don't have my Elm editor handy, but I think it's something like this:

init : () -> ( Model, Cmd Msg )
init _ =
    { 
        counter = 0
        , status = Loading
    }
    , ( 
        Http.get
            { url = "https://elm-lang.org/assets/public-opinion.txt"
            , expect = Http.expectString GotText
            }
    )

I'm not 100% sure about the Http.get bit, but try it and let me know.

vsoch commented 4 years ago

okay phase 1 of this is done, the branch step2-http that adds a basic http request to get raw text content. For the next round of work I'll likely remove the counter and then test out parsing json.