---
title: 'Iterative Development in Elm: HTTP'
teaser: Fake out your HTTP requests for a tighter iteration cycle.
tags: elm,web,process
author: Joël Quenneville
published_on: 2019-08-20
---

Elm's compiler is a great assistant. We can make **HUGE** changes to our code
and it will make sure we make all the necessary fixes to get it working again.
It gives us complete freedom to refactor.

Just because we _can_ doesn't mean we _should_. I've found it's often much nicer
to take a lot of small steps, each of which leave us in a compiling state.
Recently, I've been using [incremental approach] a lot for interactions
involving HTTP requests, especially complex [GraphQL] queries.

In particular, faking out HTTP requests with a sleep allows me to hand-wave the
request away while I deal with the various UI states (loading, success,
failure), all while remaining in a compiling state.

[incremental approach]: https://medium.com/@dillonkearns/moving-faster-with-tiny-steps-in-elm-2e6a269e4efc
[GraphQL]: https://package.elm-lang.org/packages/dillonkearns/elm-graphql/latest/

## Setup

We've introduced a button. When we click it we want to fetch a user from the API
via HTTP.

```elm
button [ onClick UserClickedGetUser ]
  [ text "Get the user" ]
```

Now we're getting a compilation error because there's a new message we aren't
handling. ❌

## Do nothing -- inline

We add a new case to our `update` function. The simplest thing we can do is not
to make the HTTP request. We set the model into the loading state and return
`Cmd.none`. Now we're compiling again! ✅

We should be able to click the button and see the UI go into a loading state.

```elm
-- In the `update` function

UserClickedGetUser ->
  ({ model | user = Loading }, Cmd.none)
```

## Do nothing -- extract method

The next simplest thing we can do is to [extract method]. We're still not doing
anything, but now it's happening elsewhere. We're still compiling. ✅

```elm
-- In the `update` function

UserClickedGetUser ->
  ({ model | User = Loading }, getUser)
```

```elm
getUser : Cmd Msg
getUser =
  Cmd.none
```

[extract method]: https://refactoring.guru/extract-method

## Sleep

Time to actually do some work in the command. In an attempt to tighten the
incremental steps we need to get to a compiling state, we'd like to skip making
an actual HTTP request for now. Let's do something simpler instead. We can use a
combination of `Process.sleep` and `Task.perform` to create a command that
returns the same kind of responses that an HTTP request would.

```elm
getUser : Cmd Msg
getUser =
  Process.sleep 2000
    |> Task.perform (\_ ->
      ReceivedUserFromServer (Ok fakeUser)
    )

fakeUser : User
fakeUser =
  { name = "Fake", age  = 42 }
```

Now the build is broken because we aren't handling the new message
`ReceivedUserFromServer`. ❌

## Handle Result

Back in our `update` function, we add branches for both success and failure
cases of our message. We probably also need to handle success and errors views
for those states. Now we're compiling again! ✅

We should now be able to click the button, see a loading state, then after a
couple of seconds see a success or error state. All without making any HTTP
requests!

```elm
-- In the `update` function

UserClickedGetUser ->
  ({ model | user = Loading }, getUser)

ReceivedUserFromServer (Ok user) ->
  -- HANDLE SUCCESS

ReceivedUserFromServer (Err error) ->
  -- HANDLE ERROR
```

## Real HTTP

Now that we've got all the UI interactions done, we can finally circle back to
the HTTP request. We don't need to worry about loading or error states. Those
are already handled. All we need to do here is make the API call. Once that
compiles, we're done! ✅

```elm
getUser : Cmd Msg
getUser =
  -- DO REAL HTTP HERE
```

## See it in action

I've packaged the example above into a [live Ellie demo].

![Fake HTTP request](https://images.thoughtbot.com/jq-incremental-elm-http/f28gsFSzRemGnaG3LDwU_fake-http-request.gif)

[live Ellie demo]: https://ellie-app.com/6pr6nWHpj2va1

## Conclusion

I've found a lot of benefits to the incremental approach. Not only does it help
focus my development process, but it also allows me to scope commits more
tightly. I can actually run the app and interact with the HTML at almost any
point in the development process.

As a bonus, this approach also allows me to develop against an API endpoint that
doesn't exist yet. This isn't uncommon when working with a separate backend team
that's building features in parallel.

So the next time you're integrating some API, throw a few sleeps into your
code. You may find it's a winning combo 🥇
