Skip to content

Instantly share code, notes, and snippets.

@ryan-haskell
Created July 12, 2020 05:23
Show Gist options
  • Save ryan-haskell/3ce83ec17ed473717e5604c7047e4d2c to your computer and use it in GitHub Desktop.
Save ryan-haskell/3ce83ec17ed473717e5604c7047e4d2c to your computer and use it in GitHub Desktop.
Used in the "Using APIs" section of in the elm-spa guide
-- src/Api.elm
module Api exposing (Data(..), expectJson)
import Http
import Json.Decode as Json
type Data value
= NotAsked
| Loading
| Failure Http.Error
| Success value
expectJson : (Data value -> msg) -> Json.Decoder value -> Http.Expect msg
expectJson toMsg =
Http.expectJson (fromResult >> toMsg)
fromResult : Result Http.Error value -> Data value
fromResult result =
case result of
Ok value ->
Success value
Err reason ->
Failure reason
-- src/Api/Reddit/Listing.elm
module Api.Reddit.Listing exposing
( Listing
, hot, top, new
)
{-|
@docs Listing
@docs hot, top, new
-}
import Api
import Http
import Json.Decode as Json
type alias Listing =
{ title : String
, author : String
, url : String
}
decoder : Json.Decoder Listing
decoder =
Json.map3 Listing
(Json.field "title" Json.string)
(Json.field "author_fullname" Json.string)
(Json.field "url" Json.string)
-- ENDPOINTS
hot : { onResponse : Api.Data (List Listing) -> msg } -> Cmd msg
hot =
listings "hot"
top : { onResponse : Api.Data (List Listing) -> msg } -> Cmd msg
top =
listings "top"
new : { onResponse : Api.Data (List Listing) -> msg } -> Cmd msg
new =
listings "new"
listings : String -> { onResponse : Api.Data (List Listing) -> msg } -> Cmd msg
listings endpoint options =
Http.get
{ url = "https://api.reddit.com/r/elm/" ++ endpoint
, expect =
Api.expectJson options.onResponse
(Json.at [ "data", "children" ] (Json.list decoder))
}
-- src/Pages/Posts.elm
module Pages.Posts exposing (Model, Msg, Params, page)
import Api
import Api.Reddit.Listing exposing (Listing)
import Html exposing (..)
import Html.Attributes exposing (class, href)
import Spa.Document exposing (Document)
import Spa.Page as Page exposing (Page)
import Spa.Url exposing (Url)
page : Page Params Model Msg
page =
Page.element
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- INIT
type alias Params =
()
type alias Model =
{ listings : Api.Data (List Listing)
}
init : Url Params -> ( Model, Cmd Msg )
init url =
( Model Api.Loading
, Api.Reddit.Listing.hot
{ onResponse = GotHotListings
}
)
-- UPDATE
type Msg
= GotHotListings (Api.Data (List Listing))
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotHotListings data ->
( { model | listings = data }
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Document Msg
view model =
{ title = "Posts"
, body =
[ div [ class "page" ]
[ viewListings model.listings
]
]
}
viewListings : Api.Data (List Listing) -> Html msg
viewListings data =
case data of
Api.NotAsked ->
text "Not asked"
Api.Loading ->
text "Loading..."
Api.Failure _ ->
text "Something went wrong..."
Api.Success listings ->
div [ class "listings" ]
(List.map viewListing listings)
viewListing : Listing -> Html msg
viewListing listing =
div [ class "listing" ]
[ a [ class "title", href listing.url ]
[ text listing.title ]
, p [ class "author" ]
[ text ("Author: " ++ listing.author) ]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment