Decoding JSON in Elm

By | 2016-06-14

I recently starting looking at Elm. If you’ve never used Elm, it is a great front-end functional language with fantastic tooling. I highly recommend looking into it. However, if you come from an object-oriented, imperative language such as C# (then your JavaScript is most likely written in a similar manner), working in a language like Elm may have a bit more of a learning curve. The biggest hiccup I experienced came from receiving and using JSON data, whether from an API or local JSON file.

The key to writing a decoder for JSON data is to think one step at a time. Elm does not have a JSON.parse() or JSON.stringify(). Let’s look at an example of how to decode an array of objects. The principles used here would apply to decoding most objects. Just think one level at a time.

First add the following imports to your elm file:

import Http
import Json.Decode exposing (..)
import Task

Then create your model. In this example we are reading a list of words and definitions:

type alias Location =
  {
    id: Int
  , city: String
  , state: String
  }

Our JSON looks like this:

{ "data" : [{"id":1,"city":"Atlanta","state":"GA"},{"id":2,"city":"New York","state":"NY"}]}

When writing decoders in Elm, I find it easier to think at the lowest level and work our way up. First, let’s write a decoder to decode each City/State pair into a Location object.

decodeLocation : Decoder Location
decodeLocation =
  object3 Location
    ("id" := int)
    ("city" := string)
    ("state" := string)

Now that we can decode a single Location object, we need to be able to decode the whole list that is encompassed by “data”.

decodeDataFile : Decoder (List Location)
decodeDataFile = "data" := Json.Decode.list decodeLocation

Now all we have to do is call the decodeDataFile when we make our http call:

Task.perform FetchFail FetchSucceed (Http.get decodeDataFile url)