We now know how to retrieve a resource from an HTTP server using the
GET request. Most Elm apps also need to create, update, and delete resources on the server. In this section, we’ll learn how to update a post by using the
PATCH HTTP method.
Saving the Updated Post
Right now, if we modify a post from the Edit Post page we built in the previous section, the new information is lost because we aren’t saving it anywhere.
onInput Event Handler
The first order of business in making the Edit Post page functional is to add input handlers to text fields. Add
onInput to all three text fields in the
editForm function inside
We’ll be sending a message to the Elm Runtime whenever the contents of a text field is modified. The message will contain the post ID and the modified content as payload. Although it appears that we are only sending the post ID, Elm will automatically pass the modified content as the second argument to the message constructor.
onInput is defined in the
Html.Events module. Let’s import it in
Next we need to add those messages to the
Msg type in
The definitions above would read better if we’re explicit about what the
Int type represents. Let’s define a type alias called
PostId and use that instead of
Don’t hesitate to define as many type aliases as you need to improve the readability of your code. Let’s replace
PostId in the
findPostById function in
View.elm as well.
We’ll handle the messages above one at a time. The first one is
UpdateTitle. Add a new branch to the
update function in
Also add the following definition for a new function called
updateTitle to the bottom of
Our strategy here is to find a post with the given ID and then update its
title field. You maybe wondering why
updateTitle doesn’t reuse the
findPostById function (shown below) we created in the Routing to the Correct Page section to find a post. The reason for that is in addition to finding a post we also need to update and save it back to the
posts field in our model.
Let’s understand how the
RemoteData.map function — used inside
updateTitle — works.
It applies the given function to the
Success value stored in
model.posts. If the value is anything other than
Success, it ignores the function. Here is how its implementation looks:
a type variables represent the
Success values respectively as shown in
RemoteData’s definition below.
updatePosts also uses
map to apply yet another function to the posts, but the
map function we’re using here is defined in the
Transforming a value from one format to another is quite common in Elm. That’s why most modules provide their own implementation of the
map function. Although conceptually similar,
List.map operate on different types of data.
RemoteData.map expects its second argument to be a
Success value whereas
List.map expects its second argument to be a
The actual task of finding the right post and updating its
title happens inside
The figure below illustrates how
updatePost functions work together to find a post and update its
Logging in Browser Console
It would be nice if we could find out whether or not the code we’ve written so far works. But until we have handled the remaining messages —
UpdateAuthorRul— our app won’t compile. Let’s add two more branches to the
update function in
We’ll handle these messages properly in a moment. For now, we’ve a dummy implementation that simply returns the given model and an empty list of commands.
Our app will compile now, but how can we verify that the modified content from a text field is indeed saved in the
title field? One approach is to log the new title in browser console.
Debug module in Elm provides a function called
log. That’s exactly what we need here. In addition to printing the output of unfinished code, we can use the
Debug module to investigate bugs and performance problems. Let’s import it in
Debug.log to print the value of
Here is how
Debug.log’s type signature looks:
elm-live is running and go to
http://localhost:8000/posts/1. Open browser console and modify the title. You should see a new entry for each keystroke.
- Opening browser console
- Instructions for opening the browser console depends on which browser you’re using. Please read this nice tutorial from WickedlySmart that explains how to open the console on various browsers.
Now that we know our code is working, we can remove
updateTitle. Don’t forget to remove the line that imports
Debug module as well.
Saving New Author Name and URL
The code for properly handling
UpdateAuthorUrl messages looks very similar to how we handled
UpdateTitle. Modify the branches for those messages in the
update function inside
State.elm as shown below.
Also add the following definitions for
updateAuthorUrl to the bottom of
Unfortunately, Elm doesn’t provide an easy way to update a nested field in a record. We can’t use the dot syntax to modify a field like this:
This doesn’t work either:
A work around is to store the old author in a constant.
There is quite a bit of duplicate code in
updateAuthorUrl. The only difference between them is the part that modifies the post record. Let’s extract that part out. Replace those three functions with the following code.
The branches for handling text field messages in
update also contain duplicate code. We can remove the duplication by moving the code for modifying the
posts field to
Here’s how the branches for handling text field messages in
update look now.
That looks much cleaner. Check the output from
elm-live in terminal to make sure we didn’t break anything.
Submitting the Updated Post to Server
Right now, the Submit button in Edit Post page doesn’t do anything. Let’s make it functional by adding
onClick event handler to it in
SubmitUpdatedPost to the
Msg type in
To handle this message properly, we need to first find a post with the given ID. If the post exists, we’ll create a command for submitting the post to our local server. If not, we’ll do nothing. Add the following branch to the bottom of
We have already implemented the
findPostById function in
View.elm. It would be great if we could reuse it here. One way we can achieve that is by importing the
View module in
State.elm, but that creates unnecessary coupling between our state and view code. We should keep them separate as much as possible. A better alternative is to extract
findPostById out to a separate module. Create a new file called
PostApp directory and add the code below to it.
Misc module provides a home for all the miscellaneous helper functions used throughout our app. Right now it only has one function. We may add more to it in the future. Import the
Misc module in
Now that we’ve moved
Misc.elm, we can safely delete it from
View.elm. We also need to import the
Misc module in
Creating a Command for Submitting Post
If you look at the
elm-live window in terminal, you’ll see a compiler error:
Cannot find variable updatePostCommand. Let’s fix it by adding the following code to the bottom of
To keep things simple, we’re using
Http.send here instead of
RemoteData.sendRequest. We’ll define
updatePostRequest in a moment. First let’s add the
PostUpdated message to
Msg type in
We need to import
Since we’re using
Http.send to create a command, the payload inside
PostUpdated will be of
Result type instead of
WebData. Let’s handle the
PostUpdated message inside
Once again to keep things simple, we’re ignoring the response from server by returning the unmodified model and an empty list of commands. Properly handling the response is left as an exercise. If you don’t remember how to deal with errors, please see the Handling HTTP Errors section.
Now that we’ve taken care of the message, let’s add the code for creating an HTTP request to the bottom of
Http module doesn’t provide a function called
patch, so we’re forced to construct our request using a low-level function called
Http.get functions we saw earlier in this chapter also use
Http.request behind the scenes.
Http.request takes a record as an argument. Let’s go through each field in that record to understand what they represent.
method - To update a resource on the server, we need to use the
headers - The
headers field allows us to send additional information to the server. Since we don’t want to send any headers, we’re giving it an empty list.
url - The location of the resource we want to modify.
body - The contents of the text fields in Edit Post page is assigned to this field. But first we need to translate that info from Elm values to JSON. Elm provides a module called
Json.Encode for that. Let’s import it in
Rest.elm. While we’re at it, let’s expose
We can now create encoders for
author. Add the following code to the bottom of
Encoding JSON values is the exact opposite of decoding. For comparison, here is how the decoders for
author would look if we were to create them using the
We can’t assign the encoded value directly to the
body field though. We need to explicitly tell
Http.request that our encoded value is in JSON format by using the
This will add the
Content-Type: application/json header to our HTTP request behind the scenes. That is how the server knows that the body of a request is in JSON format.
expect - By using the
Http.expectJson function we’re letting Elm know that we expect the response body to be JSON as well. We’re using the same decoder we created in the Decoding Nested Objects section to decode the response.
timeout - Sometimes a server takes forever to return a response. If we don’t want our users to wait too long, we can specify a timeout like this:
timeout expects a
Maybe. That’s why we need to wrap the value in
Just. Since we don’t want to specify a timeout, we’re simply passing
withCredentials - This field takes a boolean. It indicates whether or not the credentials managed by a browser should be used to make cross-origin requests. Our server doesn’t require us to authenticate in order to access resources. That’s why we’ve assigned
The only thing remaining is to expose
elm-live window in terminal to make sure everything compiled successfully. Now go to
http://localhost:8000/posts/1 and modify the title. After that click the Submit button.
Click Back to return to the list view and you should see the modified title.
You can also check
server/db.json if you want to verify that the title was indeed modified by our request.
In this section, we learned how to modify a resource on our local server using the
PATCH HTTP method. Along the way we figured out how to save changes from a text field in our model. We leveraged the
Debug module to see the output of our unfinished code by printing a value in browser console. We saw what an HTTP request is really made up of by understanding each field present in the record given to
HTTP.request. Finally, we learned how to encode Elm values into JSON using the
In the next section, we’ll delete a resource by sending a
DELETE HTTP request.