So last time we got a good start on the Web application and it's time to set up some roots and display
a page, but first, you may have noticed something that I missed somehow last time around.
And that is right here in line forty seven on my code in the main Dargo file, I have this app info
log print line and I neglected to change this to format or print F, which will do the trick.
There are other ways, but this will do it and that will actually do the substitutions because as you
can see down here on the console, it's starting http server in %s mode uncaught percent D.
Now for this time, let's clear the screen.
That's what I wanted, starting in development mode on part four.
All right.
Just a little oversight on my part.
So let's set up some roots and in order to do that, we're going to have to have somewhere for those
roots to go.
So in my Web folder, I'm going to create a new file, which I'll call Handlers Dacko.
And this is where I'll put my handler's subjectivities package declaration package made.
And let's set up a really simple handler and we'll call it virtual terminal.
So I'll create a function with a receiver app pointer to application so it has access to our app config
and I'll call it virtual terminal and it's a handler.
So it takes two arguments, a response writer
and a pointer to a request.
And all I'm going to do right now is just say app dot info log dot print line, hit the handler.
That's all we'll do for right now.
You give me something to point a route to.
So now let's go over to our roots file and let's put it right in here.
And it's just as simple as mux dot get and I'll use the path slash virtual terminal and that points
to a virtual terminal.
OK, now with those little few lines of code, when I run this, go run slash C and slash web, I should
start my application and I should be able to go to a web browser and go to HTP Colon's localhost four
thousand virtual terminal and not see anything, which is what I expected.
But when I look at the output in my terminal, it should say hit the handler and it does.
Perfect.
So let's stop our application and let's actually display a page now inside of my Web folder.
And this is unusual.
It may seem unusual to you if you've taken my other course in building Web applications and go, but
I'm going to put my templates.
I'll use standard go templates in a folder inside my work folder, which I'll call templates.
OK, and I'll explain why when I create another file in my web folder, a new file which I'll call Render
Duko, and this will take care of rendering pages for us.
So let's give it its package declaration package and now let's set some information up.
So the first thing I'll do is I know I'm going to be passing some kinds of information to my template,
so I'm going to create a new type, which I'll call template data.
And it's a struct and it's going to hold a few things.
And I'll put in all the kinds of things I think I might at some point need to pass to a template.
So like, for example, a string map and that will be a map of string string so I can pass a map of
strings to my templates and I'll do the same thing for map map of string and and probably offload map
map of string for thirty two and then just any kind of data which I'll call data and that's a map of
string with the interface type so I can put whatever I need in there.
And I'm probably going to want to pass, say a CSF token and you won't get to this time around but we'll
get to it eventually see a sort of token which will be a string for cross site request, forgery, protection,
flash data, a message that's displayed once and then goes away, maybe warning data.
And I want to display a warning to the user.
It'll just be a string and error, which will also be a string.
And I might also want to say, is the user authenticate?
Again, we're not using most of that right now, indicated what we will at some point before this course
is over.
And I'll just make that an API, which we are going to use.
That's the route to our API.
That'll be a string and CSFs version, which we are going to use.
And we'll make that a capital C like this and a capital S.
S success version, which will also be a string.
And that's that constant defined back in May not go all right.
So there's that form of it.
There's our type now and probably at some point.
And I also want to pass functions to my templates so far functions.
I'll just make it a equal to a template funk map.
And I'll leave it empty for right now and now I'm going to take advantage of goes embed functionality,
something that appeared in the standard library as part of go one point one six.
So we're going to do it like this.
We're going to use a directive as a comment, go embed and we're going to embed the directory templates,
OK?
And now I just say ver and I'll call my variable template FS for template file system embed with us.
OK, and that should have important embed for me and I did.
OK, so this is empty right now.
So we're going to get an error until we put something in this folder.
So what I'll do for the moment is just create a new file in here, which I will call based on layout
dot temple.
It'll be where I put my base layout.
OK, and here I'll just define
my layout to be named face and I'll give it an end.
OK, so go back to rendered.
OK, go and we'll save this ok.
And that error goes away.
So now I have a place to put my templates and that's where we're going to put them.
And the reason I'm doing that is this nice embed functionality that's now part of the standard library
allows me to compile my application, including all of its associated templates into a single binary.
And I think that's really, really convenient.
OK, now let's create another function here.
I'm going to call this one func and it will have the receiver app pointed to application.
And I'm going to call that add default data and then we'll take two arguments.
It will take TD, which is a pointer to template data, and we'll also take the request HDB request.
And for right now, all that's going to do is return TD.
OK, so it's not going to do anything.
It's just going to take what we got as template data and it's going to return it, which of course means
I have to put slash template data there.
This is where we will add any information that's in this struct or a variable that's created with a
type of template.
Data will add that default data using this function, but I'm going to create steps to get things working
for right now.
Now I'll write a function that actually renders a template, OK, so I will say thank you to application.
So we have access to our config render template and it's going to take a few hours and it will seem
like a lot at the beginning, but it'll make sense very, very soon.
OK, so render template.
We'll take our response writer Hibito Response Writer.
So we have somewhere to write.
It will also take a request pointer to an HIV beat up request, and it will take the name of the template
we want to render, which I'm going to call page, which is a string, and it will take a default or
all the default data that will be passed to all templates.
So template data pointer to that.
And it will also take something called Parshall's and that's going to be very Atick.
It will be one zero or more string's past this to try and you OK, and this will potentially return
an error.
OK, that's a long function definition, but that's what we're going to have to work with.
Now, the first thing I'm going to do is create a variable, which I'm going to call T, and that will
be a pointer to template dot template.
OK, and I'll also create a variable called error for E R, which is of type error.
And normally you don't do that.
But you'll see why I'm doing that in a moment.
Now I want to figure out what template do I want to render.
So I'm going to have things like virtual dash terminal page template and that will be a file that exists
in the templates folder inside of the Web folder.
But when I passed the name, I just want to pass terminal.
I don't want terminal page dot temple.
I just want terminal.
So let's build up the names of that template.
Will have some room here.
So I will say template to render.
That's a variable and I'm declaring that will be assigned the value of format s print F and I'm going
to give it up the string like this templates which is the name of the folder percent estcourt page Temple
and I will substitute for the percent.
S page, which I got as parameter to this.
OK, so now I know what template I want to render, ok.
And the first thing I'm going to do here is to check, to see if I have that variable we put in our
application config, that template cache if that exists in the template cache.
And I'll do it the same way you always do when checking to see if something exists in a map.
I'll ignore the first return parameter.
All I care about is the second one, which I'll call template in math, and that will be true if it
exists in the map and false if it does not.
And all I have to do is looking at template cache with the key of the template to render.
So if that exists, this will be true and we can use it.
If it doesn't, it'll be false and we'll have to build it.
OK, but there's another situation where I never want to use the template cache and that's when I'm
in development.
I don't want to be always stopping and starting my application every time I make a change to the file
in of the base layer.
Instead, I want it to happen automatically.
So I'm going to do a simple instict.
I will say, if I've got config on, if that is equal to production and template in map, then I'll
use it.
OK, so t will be equal to the T is the variable we declared right here in line thirty five.
The template I want to work with is going to be equal to after template cache template to render and
then I have my template.
OK, otherwise if we're not in production or it doesn't exist in that map, then we need to build it.
So we have to actually have to pass that template and I can do it right in the side, this statement.
But that's kind of awkward.
I'll put it into its own function, which I'll call pers template, so I'll call it, then I'll write
the function.
T error is assigned.
The value over is equal to after pass template function.
That doesn't exist yet, but we'll write it in a minute and I'll pass it.
Parshall's, which I got as a very odd string at the very last item in the that was passed to this.
I'll pass it Parshall's I'll pass it page, which is the name of the template I want to remember, minus
the extension on the full name template to render.
OK, and I'll check for an error.
If error is not equal to nil then apta error log dot print line error and I'll just return so I don't
want to go any further.
OK, and what I'll return is, I don't know, I have a template data here.
This is an error so that again there I'll return my error.
We'll go any further.
OK, so before we go any further down here, I'll just say return nil.
So this will compile, let's create that first template function.
So func and it has the receiver of pointer to application.
That's called pers template and it takes us parameters partial.
Which is a slice of string page, which is a string and template to render, which is also a string,
and it returns pointer to template template, which is the result of what we're going to get when we
pass and potentially.
OK, first thing we do here is again declare two variables Verrity, which is a pointer to template
template and var error, which is an error like that.
And now we'll build the Parshall's now we haven't got any Parshall's yet, but we will write this code.
Many go templates, as you know, are comprised of the template itself, some parshall's that we want
included in that template.
And the entire template is governed by some base layer.
So we need to deal with the Parshall's if they exist.
So all we have to do here is say if the length of parshall's is greater than zero, then we have some
parshall's to deal with.
So we just range through that slice of strings.
For an X is a sign the value of range through partial.
And what we want to do here is to say Parshall's I.
That index in the string is equal to the format as print f templates.
Again, as print f templates, which is the directory inside the Web directory, which will be embedded
into the final binary slash percent?
S partial template.
That's how we'll need more files and we want to substitute for that text.
OK, and then a little bit further down outside of this if statement, again, I'll say if Lenn of Parshall's.
Is greater than zero, and I'll put it out here and scroll up to give yourself some room, if we do
have parshall's that we have to call our past template function like this t comma error equals template
new and we want to pass it formatted as part of percent Essig, page, temple and page.
And then we want to pass any functions we don't have any, but we're going to eventually, so we'll
put in functions, those will be available to our template.
And after we add the functions, we call Persse first because we're passing a file system.
And if you recall the name of the file system that we specified, the embedded file system was template.
And the next thing we want to pass and it has to come in this order is the layout we're going to use
for any template.
And I'm going to call mine base layout tempo and it's going to be inside the templates folder like that.
So template based layout template then, because we're in the IF statement here that says there are
some partials, we need to include all of the partial file names and that would be as simple as string's
join Parshall's.
Like that, and that will separate the list of partial files with a comma and the last argument we want
is a template to render right there and better spell Parshall's.
Right.
And apparently didn't import the strings package for me.
So let's put that in there.
OK, let's make sure we've got this all right, good, so we're preparing templates to the Parshall's,
a name that doesn't need it pretty PRST or prevented this looks right.
OK, so that's our first one.
And I'm going to copy this whole thing and paste it down here for where the situation occurs that we
don't have templates or parshall's associated with a template.
I only have to do there is take this part of.
OK, so now we have a means of getting our T variable populated with the necessary information, but
of course we have to check for an error.
If error is not equal to nil, then APTA error log print line the error and return nil and the error.
Otherwise, everything worked and we can hand back our template.
But first, since we've gone to the trouble of building it, let's put it in our template cache template
cache and the index will be template to render and that's going to be equal to.
Now it's in our cash and we'll return T and no, because there's no error.
So now we have our parse template function.
So back up here, we're getting our T variable.
We're checking to see if it's in the template cache, if we're in production and the template is in
the map.
If it is, we pull it out of that map.
Otherwise, if we're in development or we're in production and value does not exist in the template
map, then we go and build it by calling Persch template.
So that gives us our T variable at this point.
So now we'll check to see if we have a template that if TD is equal to nil, then we'll set TD equal
to a reference to template data, an empty one like that.
Then we add our default data.
TD equals up, add default data TD plus it takes the second parameter our our request.
Think I made a mistake up here, it returns a pointer to template data that makes more sense.
I think I have those two transposed at one point, but they're all right now.
So let's keep going.
So we get our template data so we check to see if data was passed with the call to add default data.
And if it wasn't, we create an empty template data object.
Then we add our default data and finally we can execute that template.
So error is equal to to execute.
And that requires two parameters.
Our response writer and our template data and we check for error.
Error is not equal to nil.
Then APTA error log print line error and return and we return our error.
Otherwise, things should be good.
So this is a means if we get everything right, of handling the situation where we're we have a very
simple template that has no parshall's and we have a template that has parshall's and we have a template
that is being passed, no data and we have a template that's being passed, some data.
So that should handle all of the situations.
And the great thing about this is when we build those templates, which will take care of in the next
lecture, they're actually embedded into our final binary, which I think is a pretty clean solution.
So let's get started on the templates themselves in the next election.