Skip to content

Instantly share code, notes, and snippets.

@supermacro
Last active November 26, 2020 04:40
Show Gist options
  • Save supermacro/5b38c807a29a79e49795372960149ad8 to your computer and use it in GitHub Desktop.
Save supermacro/5b38c807a29a79e49795372960149ad8 to your computer and use it in GitHub Desktop.
Nested Comment Tree Decoder
module Main exposing (main)
import Browser
import Html exposing (Html, div, text)
import Json.Decode as D exposing (Decoder)
{-
This module demonstrates how to decode a nested tree of nodes that are NOT infinitely recursive.
-}
type alias CommentTree =
CommentWithReplies
(CommentWithReplies
LeafComment
)
type alias CommentWithReplies a =
{ id : String
, anonymousAuthorName : String
, replies : List a
, body : String
}
type alias LeafComment =
{ id : String
, anonymousAuthorName : String
, body : String
}
apiResponseDecoder : Decoder a -> Decoder a
apiResponseDecoder dataDecoder =
D.field "data" dataDecoder
-- intentionally ommiting type here
commonFields =
{ id = D.field "id" D.string
, anonymousAuthorName = D.field "anon_author_name" D.string
}
leafCommentDecoder : Decoder LeafComment
leafCommentDecoder =
D.map2 LeafComment
commonFields.id
commonFields.anonymousAuthorName
makeCommentTreeDecoder : Decoder a -> Decoder (CommentWithReplies a)
makeCommentTreeDecoder nextDecoder =
D.map3 CommentWithReplies
commonFields.id
commonFields.anonymousAuthorName
(D.field "replies" <| D.list nextDecoder)
commentListDecoder : Decoder (List CommentTree)
commentListDecoder =
let
commentTreeDecoder =
makeCommentTreeDecoder
(makeCommentTreeDecoder leafCommentDecoder
)
in
D.field "comments"
(D.list commentTreeDecoder)
json : String
json = """
{
"data": {
"comments": [
{
"id": "ckhxpcv2l0056b7t28lc2qnii",
"anon_author_name": "unbeatable-caped-terror",
"body": "A top-level comment",
"votes": 0,
"post_id": "ckhxpc7sh0032b7t24cmlli2j",
"created_at": 1606326555981,
"updated_at": 1606326555981,
"parent_comment_id": null,
"author_id": null,
"author": null,
"replies": []
},
{
"id": "ckhxpde9v0069b7t2tuddh7lm",
"anon_author_name": "infamous-sir-master",
"body": "Another top-level comment",
"votes": 0,
"post_id": "ckhxpc7sh0032b7t24cmlli2j",
"created_at": 1606326580868,
"updated_at": 1606326580868,
"parent_comment_id": null,
"author_id": null,
"author": null,
"replies": [
{
"id": "ckhxpdorx0077b7t2y28g02dj",
"anon_author_name": "criminal-tomorrow-storm",
"body": "Yo this is a reply",
"votes": 0,
"post_id": "ckhxpc7sh0032b7t24cmlli2j",
"created_at": 1606326594477,
"updated_at": 1606326594478,
"parent_comment_id": "ckhxpde9v0069b7t2tuddh7lm",
"author_id": null,
"author": null,
"replies": []
}
]
}
],
"siteVerified": false,
"postId": "ckhxpc7sh0032b7t24cmlli2j",
"leafIds": [
"ckhxpcv2l0056b7t28lc2qnii",
"ckhxpdorx0077b7t2y28g02dj"
]
}
}
"""
errorToHtml : D.Error -> Html.Html msg
errorToHtml error =
Html.pre [] [ Html.text (D.errorToString error) ]
decoded : Html msg
decoded =
let
decoder = apiResponseDecoder commentListDecoder
in
case D.decodeString decoder json of
Ok data ->
text "Yay! Successfully parsed a comment tree"
Err e ->
errorToHtml e
main : Program () () Never
main =
Browser.sandbox
{ init = ()
, view = \_ -> div [] [ decoded ]
, update = \_ _ -> ()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment