Acabamos de ver un ejemplo que usa HTTP para obtener el contenido de un libro. Pero muchos servidores devuelven datos en un formato especial llamado Notación de Objetos JavaScript, o JSON.
Nuestro siguiente ejemplo muestra cómo obtener datos JSON, lo que nos permite pulsar un botón para mostrar citas aleatorias de una selección aleatoria de libros.
import Browser
import Html exposing (..)
import Html.Attributes exposing (style)
import Html.Events exposing (..)
import Http
import Json.Decode exposing (Decoder, map4, field, int, string)
-- MAIN
main =
Browser.element
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
}
-- MODEL
type Model
= Failure
| Loading
| Success Quote
type alias Quote =
{ quote : String
, source : String
, author : String
, year : Int
}
init : () -> (Model, Cmd Msg)
init _ =
(Loading, getRandomQuote)
-- UPDATE
type Msg
= MorePlease
| GotQuote (Result Http.Error Quote)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
MorePlease ->
(Loading, getRandomQuote)
GotQuote result ->
case result of
Ok quote ->
(Success quote, Cmd.none)
Err _ ->
(Failure, Cmd.none)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
div []
[ h2 [] [ text "Random Quotes" ]
, viewQuote model
]
viewQuote : Model -> Html Msg
viewQuote model =
case model of
Failure ->
div []
[ text "I could not load a random quote for some reason. "
, button [ onClick MorePlease ] [ text "Try Again!" ]
]
Loading ->
text "Loading..."
Success quote ->
div []
[ button [ onClick MorePlease, style "display" "block" ] [ text "More Please!" ]
, blockquote [] [ text quote.quote ]
, p [ style "text-align" "right" ]
[ text "— "
, cite [] [ text quote.source ]
, text (" by " ++ quote.author ++ " (" ++ String.fromInt quote.year ++ ")")
]
]
-- HTTP
getRandomQuote : Cmd Msg
getRandomQuote =
Http.get
{ url = "https://elm-lang.org/api/random-quotes"
, expect = Http.expectJson GotQuote quoteDecoder
}
quoteDecoder : Decoder Quote
quoteDecoder =
map4 Quote
(field "quote" string)
(field "source" string)
(field "author" string)
(field "year" int)
Este ejemplo es bastante similar al anterior:
- init inicia en el estado Cargando, con un comando para obtener una cita aleatoria.
- update gestiona el mensaje GotQuote cuando hay una nueva cita disponible. Pase lo que pase, no tenemos comandos adicionales. También gestiona el mensaje MorePlease cuando alguien presiona el botón, emitiendo un comando para obtener más citas aleatorias.
- view muestra las citas!
La principal diferencia está en la definición de getRandomCatGif. En lugar de usar Http.expectString, hemos cambiado a Http.expectJson. ¿Qué ocurre con esto?
Cuando se solicita a /api/random-quotes una cita aleatoria, el servidor produce una cadena JSON como esta:
{
"quote": "Diciembre solía ser un mes, pero ahora es un año",
"source": "Cartas de un estoico",
"author": "Séneca",
"year": 54
}
No ofrecemos garantías sobre la información aquí contenida. El servidor puede cambiar los nombres de los campos, y estos pueden tener diferentes tipos en distintas situaciones. ¡Es un mundo complejo!
En JavaScript, el enfoque consiste en convertir JSON en objetos JavaScript y esperar que todo salga bien. Pero si hay algún error tipográfico o datos inesperados, se produce una excepción de tiempo de ejecución en alguna parte del código. ¿Era incorrecto el código? ¿Eran incorrectos los datos? ¡Es hora de investigar para averiguarlo!
En Elm, validamos el JSON antes de que llegue a nuestro programa. Por lo tanto, si los datos tienen una estructura inesperada, lo detectamos de inmediato. Es imposible que datos incorrectos se filtren y provoquen una excepción de tiempo de ejecución tres archivos después. Esto se logra con decodificadores JSON.
