Последовательность Http.get в вяз - PullRequest
0 голосов
/ 29 июня 2018

Ниже у меня есть button, который пытается загрузить удаленный контент ...

import Post exposing (Post)
import Html exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode


type alias Model =
    { posts : List Post }


type Msg
    = Search String
    | PostsReceived (Result Http.Error (List Post))


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Search s ->
            let
                cmd =
                    (Decode.list Post.decode)
                        |> Http.get ("/posts?author=" ++ s)
                        |> Http.send PostsReceived
            in
                ( model, cmd )

        PostsReceived (Ok posts) ->
            { model | posts = posts }
                ! []

        PostsReceived (Err error) ->
            ( model, Cmd.none )


view : Model -> Html Msg
view model =
    button
        [ onClick (Search "amelia") ]
        [ text "Read posts by Amelia" ]

Это действительная программа на Elm, только с одной маленькой проблемой: API не позволяет мне искать по строке. Это не разрешено

/posts?author=amelia  => Malformed Request Error

Однако, это является разрешенным

/posts?author=2       => [ {...}, {...}, ... ]

Так что я должен сначала получить автора, чтобы получить его / ее id, а затем Я могу получать сообщения, используя идентификатор автора ...

/author?name=amelia => { id: 2, name: "amelia", ... }
/posts?author=2

Как мне упорядочить один запрос после следующего? В идеале я хотел бы кэшировать авторов где-то в модели, чтобы мы запрашивали только тех, которых мы не видели раньше.

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Вы можете связать вместе задачи, используя Task.andThen. Сначала вам нужно преобразовать веб-запросы в задачи, используя Http.toTask:

postsByAuthorName : String -> Cmd Msg
postsByAuthorName name =
    Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int)
        |> Http.toTask
        |> Task.andThen (\id ->
            Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost)
                |> Http.toTask)
        |> Task.attempt PostsReceived
0 голосов
/ 29 июня 2018

Вы можете использовать Task.andThen для объединения двух задач. Предполагая, что ответ /posts включает идентификатор автора, вы можете добавить этот идентификатор автора в модель при обработке ответа.

    Search s ->
        let
            getAuthor =
                Author.decode
                    |> Http.get ("/author?name=" ++ s)
                    |> Http.toTask
            getPosts author =
                (Decode.list Post.decode)
                    |> Http.get ("/posts?author=" ++ author.id)
                    |> Http.toTask
            cmd =
                getAuthor
                    |> Task.andThen getPosts
                    |> Task.attempt PostsReceived
        in
            ( model, cmd )

У меня есть эта компиляция на https://ellie -app.com / DBJc6Kn3G6a1 , если это поможет

0 голосов
/ 29 июня 2018

A словарь и еще пара опций Msg. Вам придется написать декодер для ответа автора, но в остальном это должно работать

type alias Model =
    { posts : List Post
    , authors : Dict String Int }


type Msg
    = Search String
    | SearchAuthor String
    | AuthorReceived (Result Http.Error Int String)
    | PostsReceived (Result Http.Error (List Post))


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Search author ->
            case (Dict.get author model.authors) of
                Nothing ->
                    let 
                        cmd =
                            (Decode.list Post.decode)
                                |> Http.get ("/author?name=" ++ author)
                                |> Http.send AuthorReceived
                    in
                        (model,cmd)

                Just num -> 
                    let
                        cmd =
                            (Decode.list Author.decode)
                                |> Http.get ("/posts?author=" ++ num)
                                |> Http.send PostsReceived
                    in
                        ( model, cmd )

        AuthorReceived (Ok number name) ->
            let
                updatedAuthors = Dict.inster name number model.authors
                cmd =
                    (Decode.list Post.decode)
                        |> Http.get ("/posts?author=" ++ number)
                        |> Http.send PostsReceived 
            in
                {model | authors = updatedAuthors } ! [cmd]

        AuthorReceived (Err error) ->
            (mode, Cmd.none )

        PostsReceived (Ok posts) ->
            { model | posts = posts }
                ! []

        PostsReceived (Err error) ->
            ( model, Cmd.none )


view : Model -> Html Msg
view model =
    button
        [ onClick (Search "amelia") ]
        [ text "Read posts by Amelia" ]
...