Task.andThen chaining with Elm 0.18

June 11, 2018

Imagine you want to do the following things in order in your update function.

  1. Make a HTTP request to move some Items from Warehouse A to Warehouse B
  2. Then reload the list of Warehouses and their totals (maybe somebody else changed something in another browser)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case Msg of
        MoveItemsToWarehouse warehouseId items ->
            let
                getWarehouses =
                    Request.Inventory.warehouseList maybeAuthToken
                        |> Http.toTask

                moveItems =
                    Request.Inventory.moveMany maybeAuthToken warehouseId items
                        |> Http.toTask

                chained =
                    moveItems
                        |> Task.andThen
                            (\moveResult ->
                                getWarehouses
                                    |> Task.andThen
                                        (\getWarehousesResult ->
                                            (Task.succeed ( moveResult, getWarehousesResult ))
                                        )
                            )
                        |> Task.attempt BothFetched
            in
                (model, chained)

        BothFetched (Ok ( movedItems, warehouses )) ->
            ({model | warehouses = warehouses, items = itemsMoved model.items movedItems})

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

In this case I wanted just one Msg to fire which can update the model once the Items have been moved and we've go the newly refreshed Warehouse list. Chaining the Http.toTask with Task.andThen seems a little messy but it's OK for a chain of 2.