Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing nested JSON in Elm

Tags:

json

elm

I have this situation

-- this is in post.elm
type alias Model =
  { img : String
  , text : String
  , source : String
  , date : String
  , comments : Comments.Model
  }

-- this is in comments.elm
type alias Model =
  List Comment.Model

-- this is in comment.elm
type alias Model =
  { text : String
  , date : String
  }

I am trying to parse a JSON so formed

{
  "posts": [{
    "img": "img 1",
    "text": "text 1",
    "source": "source 1",
    "date": "date 1",
    "comments": [{
      "text": "comment text 1 1",
      "date": "comment date 1 1"
    }]
  }
}

This is my Decoder

decoder : Decoder Post.Model
decoder =
  Decode.object5
    Post.Model
    ("img" := Decode.string)
    ("text" := Decode.string)
    ("source" := Decode.string)
    ("date" := Decode.string)
    ("comments" := Decode.list Comments.Model)

decoderColl : Decoder Model
decoderColl =
  Decode.object1
    identity
    ("posts" := Decode.list decoder)

It does not work, I am getting

Comments does not expose Model.

How do you expose a type alias?

How do I set up Decoder for my example?

like image 761
Alberto Zaccagni Avatar asked Mar 04 '16 16:03

Alberto Zaccagni


1 Answers

Edit: Updated to Elm 0.18

To expose Comments.Model, make sure your Comments.elm file exposes all types and functions like this:

module Comments exposing (..)

Or, you can expose a subset of types and functions like this:

module Comments exposing (Model)

There are a few problems with your decoders. First off, to match your JSON, you're going to need a record type alias that exposes a single posts list Posts.

type alias PostListContainerModel =
  { posts : List Post.Model }

You are missing a decoder for comments. That will look like this:

commentDecoder : Decoder Comment.Model
commentDecoder =
  Decode.map2
    Comment.Model
    (Decode.field "text" Decode.string)
    (Decode.field "date" Decode.string)

I'm going to rename your decoder function to postDecoder to avoid ambiguity. Now you can fix the comments decoder line by using the new commentDecoder.

postDecoder : Decoder Post.Model
postDecoder =
  Decode.map5
    Post.Model
    (Decode.field "img" Decode.string)
    (Decode.field "text" Decode.string)
    (Decode.field "source" Decode.string)
    (Decode.field "date" Decode.string)
    (Decode.field "comments" (Decode.list commentDecoder))

Lastly, we can fix decoderColl by using that posts wrapper type (PostListContainerModel) we created earlier:

decoderColl : Decoder PostListContainerModel
decoderColl =
  Decode.map
    PostListContainerModel
    (Decode.field "posts" (Decode.list postDecoder))
like image 182
Chad Gilbert Avatar answered Sep 23 '22 02:09

Chad Gilbert