Hello everybody
As an elm beginner I have been busy listening to my favourite podcast: elm-radio.
As they keep talking about opaque types I thought I would like to try it out.
I am also very excited about the new elm spa framework elm-land by Ryan Haskell-Glatz. So I wanted to use an opaque type following the elm.land implementation of a simple pokemon website.
Here you find my version of the site: https://willowy-twilight-ed9bec.netlify.app/ and (here was the link to the official documentation but I am only allowed to post two links in my first post :()
The elm-land documentation suggest implementing a type “Data” for dealing with http requests:
type Data value
= Loading
| Success value
| Failure Http.Error
the init function of the page Home_.elm calls the function getFirst150 (where I get the first 150 pokemon). As this function is tied to the type “Pokemon”, I implemented this type in a separate Pokemon.elm file, like so:
type alias PokeRecord =
{ name : String
, order : Int
, picture : String
, types : List String
}
type Pokemon
= Pokemon PokeRecord
This way, the constructor of the type Pokemon is not exposed to other modules. So if you need to implement a new feature or if you have any bugs or problems you only need to check Pokemon.elm. Opaque types for me feel a little bit like classes in object oriented programming. But as I don’t really understand object oriented programming, I am not an expert on this topic!
All my Pokemon helper functions look something like this:
getPokemonName : Pokemon -> String
getPokemonName pokemon =
case pokemon of
Pokemon pokeRecord ->
pokeRecord.name
hopefully this is correct!
Ok, now my getFirst150 function in the Pokemon.elm file looks like this:
getFirst150 : { onResponse : Result Http.Error (List Pokemon) -> msg } -> Cmd msg
getFirst150 options =
Http.get
{ url = "https://pokeapi.co/api/v2/pokemon?limit=150"
, expect = Http.expectJson options.onResponse pokeApiDecoder
}
this function, along with some other helper functions and the Pokemon type, is exposed to my Home_.elm file.
my model in the Home_.elm file looks like this:
type alias Model =
{ pokemonData : Api.Data (List Pokemon)
, pokemon : List Pokemon
}
my goal is to handle the http side with pokemonData which is of type Data, that is either “Loading”, “Successful” with the List of Pokemon or “Failure” with the error. Only in the success case do I want to assign the listOfPokemon to my model, like so:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
PokeApiResponded (Ok listOfPokemon) ->
( { model | pokemonData = Api.Success [], pokemon = listOfPokemon }
, Cmd.none
)
PokeApiResponded (Err httpError) ->
( { model | pokemonData = Api.Failure httpError }, Cmd.none )
now I can implement more and more functionality for my pokemon type.
Elm-land is very cool to work with and thanks to the documentation it is very easy to publish the site.
The code of the implementation is available on: GitHub - alpakaxaxa/elm-pokemon-api: Interact with pokemon api using elm-land framework
Any feedback regarding the implementation of the opaque type would be much appreciated! It is the first time that I use elm-land and an opaque type.
Thanks so much to Dillon Kearns and Jeroen Engels for teaching me a lot about programming and thanks to Ryan Haskell-Glatz for building an amazing spa framework!