Introduction
I just pieced this together after reading and looking at examples from the official elm guides. It makes use of an HTTP request to the Spotify API, and an instance of the json decoder to extract the image url from the response and displays it. There’s a search bar that allows you to specify the artist’s picture that you want, and a searching
status bar that will indicate the status of your search.
module Nested exposing (..)
import Html exposing (..)
import Http exposing (get, send)
import Html.Events exposing (onClick, onInput)
import Html.Attributes exposing (src, style)
import Json.Decode exposing (at, int, string, list, decodeString, Decoder)
import Json.Decode.Pipeline exposing (decode, required, requiredAt, optional, hardcoded)
-- Spotify Artist Decoders
type alias Artist =
{ name : String
, uri : String
, images : List String
}
imageDecoder : Decoder String
imageDecoder =
at [ "url" ] string
artistDecoder : Decoder Artist
artistDecoder =
decode Artist
|> required "name" string
|> required "uri" string
|> required "images" (list imageDecoder)
type alias ArtistList =
{ artists : List Artist }
artistObjectDecoder : Decoder ArtistList
artistObjectDecoder =
decode ArtistList
|> requiredAt [ "artists", "items" ] (list artistDecoder)
-- Functions returning messages or impure actions
updateSearchCriteria : String -> Msg
updateSearchCriteria text =
UpdateSearchCriteria text
getSpotifyArtist : String -> Cmd Msg
getSpotifyArtist name =
let
url =
"https://api.spotify.com/v1/search?q=" ++ name ++ "&type=artist"
in
Http.send NewArtist (Http.get url artistObjectDecoder)
-- MODEL/VIEW/UPDATE
type alias Model =
{ results : String
, searchCriteria : String
, artistPic : String
, isSearching : Bool
}
model : Model
model =
Model "" "" "" False
init : ( Model, Cmd Msg )
init =
( model, Cmd.none )
view : Model -> Html Msg
view model =
let
( fontColor, searchText ) =
if (model.isSearching) then
( "red", "Searching" )
else
( "green", "Done" )
in
div []
[ div [ style [ ( "color", fontColor ) ] ] [ text searchText ]
, input [ onInput updateSearchCriteria ] []
, button [ onClick Search ] [ text "Search" ]
, div [] [ text model.results ]
, img
[ (src
(if String.length model.artistPic > 0 then
model.artistPic
else
"http://www.graphics99.com/wp-content/uploads/2012/07/simpsons-with-his-small-family.jpg"
)
)
]
[]
]
type Msg
= None
| UpdateSearchCriteria String
| NewArtist (Result Http.Error ArtistList)
| Search
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
None ->
( model, Cmd.none )
UpdateSearchCriteria text ->
( { model | searchCriteria = text }, Cmd.none )
NewArtist json ->
case json of
Ok x ->
let
( name, pic ) =
case (List.head x.artists) of
Just a ->
let
pic =
case List.head a.images of
Just pic_url ->
pic_url
Nothing ->
"Nothing"
in
( a.name, pic )
Nothing ->
( "Broken", "No Image" )
in
( { model | artistPic = pic, results = name, isSearching = False }, Cmd.none )
Err msg ->
( { model | results = toString msg, isSearching = False }, Cmd.none )
Search ->
( { model | isSearching = True }, getSpotifyArtist model.searchCriteria )
main : Program Never Model Msg
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
Conclusion
Check it out here
(Just a heads up, it probably needs some styling :p)