All right, let's continue with our server side form validation.
So right now we have this our reservation form, and that actually puts an empty form object in there
that we can use for validation.
And under our code, we under errors, we've defined a type of errors that will hold our errors, which
is a map of type string with every value associated with an index of string being a slice of strings,
because we might have more than one error for a given field in a form.
That's why it's a slice.
We have a function to add errors which will append an error and a message and associated with a particular
field.
And we have a function to check and see if there are errors and return the first error if there is one.
OK, so that's for that part and other forms.
We have our type that describes the form data that we're going to add errors to if any exist.
And we have new, which allows us to create a new form, a new empty form.
And we have this one check has which isn't finished yet.
And you may have noticed that if you were paying attention.
But let's go through the process of how we actually handle posted form data and perform server side
validation.
So I'm back in my handler's file and I'm looking at that empty function we created last time called
Post Reservation.
What's the very first thing I want to do?
It is good practice.
When you were parsing form data to do this, create a variable called error and assign it a method that's
built on the request called pass form, and that's it.
So you try to parse the form there and if there's an error, you take the user somewhere, you display
whatever it may be.
But all we're going to do right now is to say if error is not equal to nil.
In other words, if there's an error parsing that form form data, then we'll just log it the print
line, log the error and we'll return so they'll get a blank screen.
I'm not going to see anything will make this better later on when we handle errors in a more sophisticated
fashion.
So I pass that form data.
Now what do I do?
Well, think about what we want to do here on my reservation page.
I have four pieces of data, actually five one is the hidden form for the CSF token, but we're not
doing anything with that.
We're just letting our middleware make sure that this form is being posted from a page on our site.
And it's not some malicious user who's written a script to access our forums as many times as he or
she possibly can just because they're nasty.
So we only have four we care about.
We have first name.
We have last name, we have email and we have phone.
Now, I could if I wanted to back in my handler actually create four variables first name, last name,
email and phone and keep track of all of those.
But it's common practice.
When I have data that's, you know, all associated with one another, let's create a new model.
So I'm going to go to my models and I'm going to open.
Let's see what shall I do.
I just put it right here.
Actually, no.
Let's create a new file called Models New Go File, Model Start Go.
Because the name of that one, I will add this.
The name of that one is our template data.
Here's where we're going to store all of our models.
And eventually these models will be used to store things in a database to to get data from a database
and store them in these models.
But right now we're just going to create one and I'll create a model which I will call obviously reservation.
So let's create a type of reservation, which is a struct, and it has one field for each of the kinds
of information I need to store in that.
So first name and I'm going to export it because I want it to be available outside of the models package.
And it's a string and we'll have last name, email and phone, all of which are strings, last name,
email and phone, and I'll give that a nice comment.
Reservation holds the reservation data and I've created that type.
So back in my handlers, let's open this up and let's actually store that data right in a reservation
object, which we just created.
So I'll create a reservation object like this reservation, which is just a variable name, and that's
going to be a type models DOT reservation.
And I'm actually going to populate it with the information that the user posted from the form, even
though it might be bad data, I'm going to save it.
So first name is going to be equal to and how do we get something from a post request are not formed
yet.
And the name that I want, which happens to be first name and then the last name
which is assigned the value of our dot form dot get last name and one for email and for phone.
So I'll just do it this way.
Phone, email, phone
and email.
OK, so now I've populated this reservation.
Variable as a struct of type models reservation, and I've given it all of the appropriate values,
so I've grabbed first name from whatever they entered in the first name field of the form, last name,
phone, email, same thing.
That's all stored here.
And this might be bad data.
So how am I going to now check my form?
Well, we don't have a form object at the moment, but we're going to get one.
We're going to create a new one by creating forms our form, which is our variable.
And we're going to assign that the value of forms new.
And this time, we're not going to parse it until we're going to pass that post for our post four.
So this is what has all those euro values and the associated data.
So this is created by calling forms new right over here.
And all that does is say, OK, get the data.
You just passed me, which happened to be our post form, which is which is of type you are values and
create the foreign object and send back a pointer to it.
So we have that back at our handlers.
We have our form now.
We can actually check things.
So the first thing we have over on forms Dargo is this has is the only thing we have that's not new
or a typed definition we have this one function has and that returns bool.
So let's go back here and you'll see why we don't have enough.
Go back to our handlers and we want to make sure that it's valid.
So I can just say on this form of that created form DOT has, it should have first name and I need to
pass that my request.
So there I've done that.
I've now called form and said, hey, look, does this form have the value first name and is it something
more than an empty string?
We checked the form a post request for the value of first name.
Does it have an entry for first name if it has one and its empty return false otherwise return true.
So when I call this back over and handlers, I'm calling the function has, but I'm not doing anything
with its response, so I probably should make this a little more valid.
I need to check if my form is valid.
It would be great if I could put whatever checks I want here.
As many as I might have.
I might have ten, I might have three and then just say, if not formed valid, do something.
In other words, you failed form validation, but that function doesn't exist yet.
So let's go put it in there.
Let's go to our forms package and let's put in this func.
And it's going to be having the receiver of a verb form so we can look at our form data of type form
valid, and that's going to return a ball.
So I better put my ball in there.
All this, does it say if there are any errors at all associated with the form object F that I'm getting
from my receiver return that the value of of fault, if there are errors and truth, are sorry.
If it's valid, if there are no errors, return true or otherwise return false.
So all I have to do here really is say return the length of errors if that happens to be equal to zero.
It's going to return.
True.
Otherwise it's going to return false.
That's a nice shorthand way of doing it.
I could have written it over four lines and it would work just as well.
But this seems to me to be the simplest approach to do it.
So let's do this.
Valid returns.
True if there are no errors.
In other words, the form is valid, otherwise false.
OK, so that's great.
But the other thing I need to pay attention to is my house check doesn't actually add an error anywhere.
It just checks to see if the field exists.
So we could do this.
We can just go back to here before this return false part and say f dort errors, which is my receiver,
I'm calling the F object and that has a function associated with it called ADD.
And I can add my airstrip and the ad is for the field when I call it with first name that is populated
with the string value of first name.
And I don't need to specify the error message, which can be something as simple as this field cannot
be blank.
All right.
So now when I call this, that actually will add an error to it.
And that's exactly what I wanted to do.
So we have our has we have our new and and our handlers now where you need to keep going.
So if the form is not valid at this point, when I call form has now it's returning a false or true,
which I'm ignoring, but it's also adding an error if first name is empty or nonexistent.
So what I want to do, if the form is actually has a problem on it, well, pretty straightforward.
Let's first of all, create a variable to hold our reservation.
And when we're passing data to a template, remember, we had that value called data.
So if we go over to our template data here, we have this nice one called Where Is It?
Data, which is a map of string interface.
So let's go back to our handlers and create a map of string interface.
So I'll call it data is equal to make a map string interface.
And then I'll add my reservation to that data reservation, which is how I'll look it up on the template
when I need to, which I'm not going to do this lecture.
But we will eventually is equal to the reservation, that object I created up here.
So now I'm storing that in that value.
And now what do I want to do?
If they didn't pass validation, I can't just hand them back to the reservation handler because that's
creating an empty form.
But what I can do is the similar thing.
I can actually render the form right from here.
I can say render that form and I'm going to pass it, not forms new nil.
I'm going to pass it form object I created here, which now has an error associated with it because
I called the has function so I can just pass it forward, let me get rid of this and just put my variable
form there.
And I'm also going to pass it data which holds this reservation map or this map that has a value of
reservation in it.
So now I have the information that the user entered.
I have the errors, if any, generated by this and I render that page.
And at that point I want to stop processing this function.
I don't want to go any further, so I'll just return.
All right.
Let's see what this does.
So far, it's not going to do very much, but let's try it.
Let's make sure it compiles or stop my application and rerun it.
It comp. That's promising, let's go back over to our make reservation page, reload this and try submitting
it.
It took me back.
It didn't do anything.
Why not?
Because I have no logic of my template to display errors.
Well, we can do that if we can do it really easily.
So let's go back over to open up our template, which is the make preservation page.
Hide this window and let's think about how we can actually get access to the reservation object.
Probably not this lecture.
That'll be the next one, but get access to the errors object so we can do that pretty easily.
What I'm going to do is write at the top here.
I'm going to give myself a little bit of space to work.
I'm only working with first name right now.
And what I want to do is to say if there's an error, if there's an error associated with first name,
I want to display something and I'm going to stick it right next to the label.
So when there's an error, I want the error message to display right here.
How am I going to get access to that errors object?
Well, we know that we have a form object, so let's just use the new syntax you haven't seen it with.
And that is a directive for a goal line template in the language, for the structure, for it is very
simple with dot form dot errors, dot get and I'm going to look for the first name, the name of the
field, and that's exactly how I'm storing it in that form object.
I'm storing a string, a map of string, slice of strings and I'm saying with form errors get first
name and this has to have an end like everything else, pretty much everything else and go like templates.
I want to display something I don't want to display a label class equals text danger, which will make
it red.
That's a bootstrap class.
And all I want to display is whatever the value from form errors get first name is.
So I'll just display that.
And that's all I have to do at this point.
But I could do something else.
It would be great.
Let's just try it like this first.
So let me stop the application and go back here, go to the Make Reservation page to make sure I'm starting
with an empty form and click make reservation and it comes back to this form and gives me that error
message.
Be nice if I could make this be outlined in red as well.
Well, it turns out I can't pretty easily and I can do that simply by in the class for the input which
is right here.
I can put more logic in there as well with DOT form, which is in our template data, part of our default
default data and handed to us by the handler.
When the form fails, validation errors don't get first name.
So if that returns true, if there is more than one error, if there's a value stored informed, our
errors don't get first name that map, string, slice of strings.
What do I want to do?
Well, all I want to do is add a class and the class is a bootstrap class called is invalid.
And then of course I have to have my hand.
Now if I do that and I'll put this down on the next line so it's organized a little better, I should
be able to just run this because we're rebuilding our template cash in every request and it should make
this box outlined in red and it failed.
What did I get wrong?
Let's go back here with format errors.
Don't get first name is invalid and OK.
Oh, there it is.
Right.
There is a quotation mark has to be on the outside, otherwise it's invalid html.
So I have an opening class tag right here, but I never have a closing class tag or quote for that,
so it never ends and go fortunately is extremely picky about that.
So let's try this again now.
It'll work and it does.
It gives me the nice little thing right here, the little exclamation mark, it outlines this in red
and it has an error message.
All right.
So that's how we can do some basic validation.
But there are some problems associated with this.
For example, I have for required fields and with my current approach back over here under my handlers
right here, I would have to let me just hide this.
I would have to do form has first name, form has last name, form has email.
That seems really inefficient.
It would be better if I could have, say, a different function or maybe modify this function something
anyway where I could just pass it on any number of required fields.
And if any of those fields are not required, it generates an error for that specific field.
Well, there has to be a way to do that.
And it turns out there is and we'll do that.
And we'll also get around repopulating our form data with whatever they entered here.
Because right now, if I put Smith and John at Smith DOT, CAA or whatever and and submit the form,
I still lose that data, which seems kind of goofy because I've already got it stored in the reservation.
There must be a better way of doing this.
And in fact there is.
And we'll take care of that in the next lecture.