HTTP

Muy frecuentemente vamos a tener que recuperar información desde algún otro lugar de internet.

Por ejemplo, imaginemos que queremos cargar el texto completo de La opinión pública por Walter Lippmann. Este libro publicado en 1922 entrega una perspectiva histórica sobre la proliferación de los medios masivos y su incidencia en la democracia. Para lo que vamos a ver a continuación, usaremos el paquete elm/http para descargar este libro en nuestro programa.

Apreta el botón azul “Editar” para abrir este programa en el editor online. Seguramente vas a ver una pantalla que dice “Loading...” antes de que aparezca el libro completo. Apreta ahora el botón.

import Browser
import Html exposing (Html, pre, text)
import Http



-- MAIN


main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view
        }



-- MODEL


type Model
    = Failure
    | Loading
    | Success String


init : () -> ( Model, Cmd Msg )
init _ =
    ( Loading
    , Http.get
        { url = "https://elm-lang.org/assets/public-opinion.txt"
        , expect = Http.expectString GotText
        }
    )



-- UPDATE


type Msg
    = GotText (Result Http.Error String)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotText result ->
            case result of
                Ok fullText ->
                    ( Success fullText, Cmd.none )

                Err _ ->
                    ( Failure, Cmd.none )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none



-- VIEW


view : Model -> Html Msg
view model =
    case model of
        Failure ->
            text "I was unable to load your book."

        Loading ->
            text "Loading..."

        Success fullText ->
            pre [] [ text fullText ]

Partes de este código te pareceran similares a ejemplos anteriores de la Arquitectura Elm. Aún tenemos un Model como modelo de nuestra aplicación. Aún tenemos la función update que reacciona ante mensajes. Aún tenemos una función view que muestra todo en pantalla.

Las partes nuevas extienden el patrón básico que ya hemos visto, con algunos cambios en init y en update, y la adición de la función subscription.

init

La función init describe cómo inicializar nuestro programa:

init : () -> ( Model, Cmd Msg )
init _ =
    ( Loading
    , Http.get
        { url = "https://elm-lang.org/assets/public-opinion.txt"
        , expect = Http.expectString GotText
        }
    )

Como siempre, tenemos que producir el Model inicial, pero ahora también estamos produciendo un comando de lo que necesitamos que ocurra inmediatamente. Ese comando eventualmente producirá un valor Msg, que luego será suplido a la función update.

Nuestro sitio web del libro comienza con el estado Loading, y queremos hacer un GET del texto completo. Cuando hagamos la solicitud GET usando Http.get vamos a especificar la url de los datos que queremos recuperar, y también necesitamos especificar lo que anticipamos que sean esos datos en expect. En nuestro caso, la url apunta a ciertos datos en el sitio web de Elm, y anticipamos que el dato sea un gran String que podremos mostrar en pantalla.

Pero la línea Http.expectString GotText dice algo más que el hecho de que esperamos un String. También está diciendo que cuando obtengamos la respuesta, ésta debiera convertirse en un mensaje GotText.

type Msg
    = GotText (Result Http.Error String)



-- GotText (Ok "The Project Gutenberg EBook of ...")
-- GotText (Err Http.NetworkError)
-- GotText (Err (Http.BadStatus 404))

Fíjate en que estamos usando el tipo Result que vimos un par de secciones atrás. Esto nos permite considerar en nuestra función updatetodos los posibles errores. Y hablando de funciones update

Nota: Si te preguntas por qué init es una función (y por qué ignoramos su argumento), vamos a hablar de eso en el capítulo siguiente sobre interoperabilidad con JavaScript. (Un pequeño avance: el argumento nos permite recuperar información desde JS al inicializar).

update

Nuestra función update también retorna un poco más de información:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotText result ->
            case result of
                Ok fullText ->
                    ( Success fullText, Cmd.none )

                Err _ ->
                    ( Failure, Cmd.none )

Si te fijas en la firma, verás que no sólo retornamos un modelo actualizado, sino que además producimos un comando de lo que queremos que Elm haga por nosotros.

Después, en la implementación, estamos haciendo búsqueda de patrones como es normal. Cuando llega un mensaje GotText, inspeccionamos el Result proveniente de nuestra solicitud HTTP, y actualizamos el modelo según si fue exitoso o no. La parte nueva es que también suplimos un comando.

En el caso de que recuperáramos el texto exitosamente, decimos Cmd.none para indicar que no hay más que hacer. Ya tenemos el contenido del libro.

Y si por otro lado hubiera ocurrido un error, también decimos Cmd.none y simplemente nos rendimos. El texto del libro no se cargó. Si quisiéramos evolucionarlo un poco, podríamos hacer búsqueda de patrones sobre el Http.Error y reintentar la solicitud si ésta expiró por tiempo.

El punto es que sea como sea que actualicemos el modelo, también tenemos la libertad de emitir nuevos comandos. ¡Necesito más datos! ¡Necesito un número al azar! Etc.

subscription

Otro aspecto nuevo de este programa es la función subscription. Nos permite revisar el Model y decidir si queremos suscribirnos a cierta información. En nuestro ejemplo, decimos Sub.none para indicar que no necesitamos suscribirnos a nada, pero pronto veremos un ejemplo de un reloj donde nos interesa suscribirnos al tiempo actual.

Resumen

Cuando creamos programas con Browser.element, configuramos un sistema como este:

Tenemos la abilidad de emitir comandos desde init y update. Esto nos permite hacer cosas como mandar solicitudes HTTP cuando queramos. También podemos suscribirnos a información interesante. (Pronto veremos un ejemplo que usa suscripciones).

results matching ""

    No results matching ""