7

I want to load user profile before rendering something into the page but the whole user profile is composed of different parts that are loaded by multiple HTTP requests.

So far I'm loading user profile in sequence (one by one)

type alias CompanyInfo = 
  { name: String
  , address: ...
  , phone: String
  , ...
  }

type alias UserProfile = 
  { userName: String
  , companyInfo: CompanyInfo
  , ... 
  }

Cmd.batch
  [ loadUserName userId LoadUserNameFail LoadUserNameSuccess
  , loadCompanyInfo userId LoadCompanyInfoFail LoadCompanyInfoSuccess
  ...
  ]

But that's not very effective. Is there a simple way how to perform a bunch of Http requests and return just one complete value?

Something like this

init = 
    (initialModel, loadUserProfile userId LoadUserProfileFail LoadUserProfileSuccess)

....
ondrej
  • 967
  • 7
  • 26

1 Answers1

12

You can achieve this using Task.map2:

Edit: Updated to Elm 0.18

Task.attempt LoadUserProfile <|
    Task.map2 (\userName companyInfo -> { userName = userName, companyInfo = companyInfo })
        (Http.get userNameGetUrl userDecoder |> Http.toTask)
        (Http.get companyInfoGetUrl companyInfoDecoder |> Http.toTask)

You can then get rid of the individual LoadUserName... and LoadCompanyInfo... Msgs. In Elm 0.18, the need for separate Fail and Succeed Msgs is addressed by Task.attempt expecting a Result Error Msg type, so that LoadUserProfile is defined like this:

type Msg
    = ...
    | LoadUserProfile (Result Http.Error UserProfile)

map2 will only succeed once both tasks succeed. It will fail if any of the tasks fail.

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
  • 6
    Worth noting that these network requests will run sequentially; they _won't_ be concurrent. – Jezen Thomas Oct 12 '16 at 17:02
  • Is there a way to do this that _is_ concurrent? – mLuby Jul 30 '17 at 01:45
  • 1
    Use `Cmd.batch` to run Tasks concurrently. Note that they will have no relation to each other, so any dependencies between results will have to be handled by you in your `update` function. – Chad Gilbert Jul 30 '17 at 01:53
  • 1
    Thanks, @mLuby. I've updated the answer for Elm 0.18 – Chad Gilbert Jul 31 '17 at 11:18
  • @ChadGilbert Where is it documented that `Cmd.batch` will run the Tasks concurrently? – mljrg Nov 22 '17 at 18:31
  • I think you mean in *parallel*, as explained in the docs, things can be done sequentially but concurrently. –  Jul 27 '18 at 14:45
  • The method `Http.toTask` does not exist anymore it appears, it might be good to replace it by using `Http.task` instead of `Http.get` . – al.one Jun 10 '21 at 14:38