Join egghead, unlock knowledge.

Want more egghead?

This lesson is for members. Join us? Get access to all 3,000+ tutorials + a community with expert developers around the world.

Unlock This Lesson

Already subscribed? Sign In


    Submit Form Data via HTTP in Elm

    Enrico BuonannoEnrico Buonanno

    Time to leave the comfort of the client application, and talk to a server. We use the Http api to send an HTTP request, and the Json.Encode api to convert between Elm types in our app and JSON data in the request. The code for the server used in this lesson is available here on github



    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson


    Instructor: 00:01 The first thing we need to do to make HTTP requests is to install the HTTP package. If you look at the files in your current working directory, notice the elm-package.json file. I hadn't actually created this file. This has been created for me by elm-reactor the first time it compiled my Elm code.

    00:22 You see that this file lists the dependencies for your project. We now want to add a dependency on the HTTP package. We do this by writing elm-package install elm-lang/http and just accept. If you view the contents of the elm-package file, you see this reference to elm-lang/http has been added. You can now import this package by typing import Http.

    00:52 Let's find the place in our code where we would like our request to be submitted. This would be in the update function, where the submit message is received. Notice that at the moment we returned Cmd.none. Instead, we would like to submit a request.

    01:07 I will put this logic in a separate function. Let me call this Submit, which I'll define down here. The type of Submit needs to be Cmd Msg because this is the return type expected by the update function. Also, the data I want to submit is stored in my model, so we also need to pass the model as a parameter.

    01:38 Let me temporarily return Cmd.none to make sure that everything compiles. It does. Let me now see how we can go about implementing this.

    01:49 This is the documentation for the HTTP package. Here we can see that there is a post function that we can use to create post requests. Let me copy this signature and paste it into my Elm file.

    02:03 I know that I need to call at some point providing these arguments. The first argument of type string is a URL, so let me put this into a variable. Typically, the URL for posting a contact request may look something like api/contact. For the purposes of this demo, I'm going to have a server listening on a different port. I will put the full URL on localhost:3000.

    02:36 The first argument to the post function will be URL. The next argument is the body. This requires a bit more work because we need to encode our Elm data into JSON before we send it. To do this, we also need to import a specific package for encoding JSON, which is called Json.Encode. I'm going to alias this as just Encode.

    03:02 Here, I'm going to create some JSON. I'm going to use a function in the Json.Encode package that's called object which creates a JSON value given a list of tuples where the first item in each tuple will be the property name, so email. This will take the email in our model, but notice that this is an Elm string. We need to also encode this as a JSON value. Here, we will use Encode.string.

    03:35 The second property will be, of course, the message. Similarly, we can use Encode.string to encode Model.Msg. This essentially will create a representation of the JSON that we want to send.

    03:57 However, the type of this JSON variable is JsonValue, so it's not exactly a body yet. We need one further step, and that will be to pass our JSON to a function called Http.jsonBody which will convert our JSON value into a body.

    04:15 You see that the next parameter is a decoder. This would be used to decode the body of the response. We need to import another package. This one is called Json.Decode. I'm going to alias this as Json. These aliases for these two packages are fairly standard.

    04:37 There is already made a decoder in the Json.Decode package that's called String. This takes a JSON string and decodes it as an Elm string. Now you see that we've provided all the parameters, but the type returned by is Request a. In this case, a will be String because we're providing a decoder that decodes to a string.

    04:58 Let's put this into a variable. We have a request of type Request String. That's our expression here. Notice, however, that what we need to return is a Cmd Msg. What we have is a request. There is one more step missing. That would be the final step, which is to pass our request into the Http.send function.

    05:22 If you look at the documentation for send, you will see that this indeed takes a request, but it takes also another parameter that is a function that will take a result and convert it to a message. What this is saying is, "OK. I will send a request. And then, based on the response, I will populate a result."

    05:43 You need to provide a way to convert this result into a message. What we need is a new type of message, which I can add here. I'll call it SubmitResponse. This will have as payload a result that in the case of an error will contain an Http.Error and in the case of success will contain a string because we already called in the body of a response as a string.

    06:15 I can now add this parameter to Send, which is SubmitResponse. Now we start to really see the nature of Elm's update function that returns, of course, an updated model but potentially a command of message. What does that mean? A command is basically an instruction that is telling Elm to do something.

    06:38 The second type message means that this instruction should result in a message of type Msg to be constructed. In this particular case, we are telling Elm, "Please, send this post request and then when you get a response, which might be an error or a success, wrap that in a message of type SubmitResponse."

    06:58 Let me now try saving this. I've just forgotten to assign this expression to the request variable. This type is Http.Request. Now we get an interesting error. What this error is saying that we're not handling all possible messages in our update function. Indeed, we've added this SubmitResponse message, but we haven't updated out function accordingly.

    07:26 You can see how the compiler, in a way, is guiding us in our development process. Let me add that SubmitResponse, which we have some kind of payload, which I'm going to ignore at the moment. To get this to compile, I'm going to add model and Cmd.none. I'm ignoring this message temporarily. Now our application compiles.

    07:52 To test this, I've written a really simple server in Node.js that listens for this single API route, api/contact. Let me start my server, and go back to my browser, and try submitting again.

    08:09 Now you can see two requests. The first one that's calling Request Method:OPTION only has to do with the fact that we're doing a cross-domain request, because our page is being served by elm-reactor on localhost:8000, whereas the API we're calling is on localhost:3000. Chrome does this preflight request, but other browsers don't.

    08:32 The second one that we can see is the post that we've actually called it for. You can see that we get a status code of 200. If we scroll down, here is the payload. Indeed, you see a JSON object with our email and message. Here, you can see that also on the server side, the payload has been received correctly.