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


    Handle Server Validation Errors in an Elm Form

    Enrico BuonannoEnrico Buonanno

    Some validation can only be done on the server, such as email validation. The client also needs to give the user clear feedback to what is going on.

    In this lesson we'll setup server-side validation, briefly go over decoding JSON in Elm, and setup proper client feedback.



    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:00 Now I've built a very simple backend for our registration form, and this is to post requests on the route API register. It performs some server-side validation, namely, it checks if a list of registered emails contains the email that has been sent in which case it sends some JSON with the success fields at the false, and an error email already registered.

    00:23 Otherwise, it adds the email to the list of registered emails, and sends some JSON with the field success set to true. Now, let's go to our Elm code and see how it could deal with this server-side validation. Firstly, I need to change my route. Secondly, I wanted to change the decoder that I'm using to parse the response body.

    00:46 Firstly, let's see how we could model the response body in Elm. Let me paste in a couple of sample values about the JSON will look like. We have a success field that's a Boolean, and in the case of failure, we have an additional field errors with the list of strings.

    01:03 We could say that these JSON API is representing an outcome, and to represent the same, we could use the result type in Elm. The first type parameter will be a list of strings. There will be the errors in the error case, and in the case of success, we have unit since there is no data.

    01:22 We could even define a type alias, response body, and this is how you could represent response body in Elm. We can still improve on this, because we're not expecting a list of arbitrary strings, but presumably a finite set of strings that the server can return as errors.

    01:43 Instead, let's create a dedicated type. This is a union type where you can represent older error values that could be returned by your server. You could add other error types here, but for simplicity, let's just deal with this one type of error. We can now use this type in our definition of response body, and we now have a nice Elm type to represent the data that is returned from our server.

    02:17 We now need to write a decoder that will translate the JSON to this response body type, and we can call this decode response body. The type will be JSON.decoder, parameterized with the response body type. Decoding JSON into Elm is a pretty vast topic in itself, so let me just paste some decoders that I've written.

    02:47 I'll only go through this very briefly. Notice how here, we're looking at the field called success and decoding it as a Boolean. Here, we have this function that says, if success, then we construct an OK. Otherwise, we construct a result in the error case, and the errors come from the errors field.

    03:08 This is wrapped in the maybe because the field is optional. We're also using this decoder to translate these strings into our type server validation error. Now, let me remove this sample values.

    03:23 Instead of this decoder here, let me use decode response body. List that here, we get an error, that's because of our submit response message was expecting a type of unit, and so here, rather than unit, we have a response body.

    03:49 Now, we have a compiler error in the code that handles the submit response message. This can no longer be unit since it's a response body. Let me just call it underscore to disregard the payload. Now it compiles and we can take it for a spin.

    04:07 Let me try to register myself with email and recall at, and a password. Here, you can see the status code of 200, so the request for successful. But if we look at the response data, it says success false. The form on the other hand is giving positive feedback to the user, so it says your request has been received.

    04:37 What we would like instead, is that the form should tell the user that he cannot register, because the email has already been registered. Let's go to our update function and change it to deal with the case of failure.

    04:52 We want to split this case, so this underscore here, remember this is our response body which is just the result type. This could in turn be on OK with unit, and he would want to succeed as before. Otherwise, he would be an error with a list of errors. This is where we want to do things differently. We don't want the initial model. We want just the model.

    05:22 The status should be the initial state which is not submitted. Furthermore, we want to show the user that his email is already registered. Let me pass this model to a function, and let me call this apply server validation errors. Pass in it the errors to apply. Let me define this just below. This takes a list of server validation errors and a model, and returns an updated version of the model.

    06:03 Because errors is a list, we want to traverse this list, and do something to the model to reflect each error that has occurred. We can do this with a fold, so we pass by list of errors to the list.fold Elm function. As a reducer function, I'd say, apply error, and I will need to define this function apply error that applies a single error.

    06:31 This will take a single error and the model. Then, we can switch on the error. If the error is email already registered, then let's return the model with the email field in an invalid state. We don't have a way to do this exactly. Let's assume I have a function that says set error with the string that says this email is already registered.

    07:04 Actually, this needs to be This is the only error we've defined, so that concludes our pattern matching. Now, we just need to write the in to conclude our let close. This of cause doesn't compile, because the set error function doesn't exist, so let's enrich our validation module to expose this.

    07:27 This takes a field with a value and a validity, which we're going to change. We can create the new field with same value as before, but the new validity will be invalid with the given error, which I need to have as an argument here.

    07:47 I have another little compilation error, because here, I forgot to pass in the model as the initial states to my folder. Now the code compiles, and let me try to do the same as before. Now you see that the form gives some feedback that this email is already registered and it hasn't cleared the data. This makes it pretty clear to the user that his data has not been submitted.

    08:19 Let me change this to a, let me try submitting it again, and you can see that now the form was cleared and the request was successful.