Lessons: 16Length: 2.2 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

3.2 Serving HTML to the Browser

In the previous lesson, we learned how to create a basic web server that will receive web requests from the browser and return data. The problem was that this data was unstructured and just a string. In this lesson, I'll show you a couple of ways that you can return actual markup back to the browser, and I'll discuss the pros and cons of each.

3.2 Serving HTML to the Browser

Okay, so now it's time to build on where we got in the last lesson. And the way that we're gonna do that, is we're gonna start to actually introduce what you're supposed to introduce in most web applications, and that is HTML markup. And the reason that we wanna do that is obviously, that's kind of the point of building a web server. You want to serve HTML to the end user, so that they can see things, and they can do things, and they can interact with your application, because that's really the point. And the reason that I'm saying that is because all we were really doing in the last lesson was getting a server up and running and then showing something to the end user. And as you can see here, it's really just a string. And if I go back and review the page source you're gonna see, once again, we're just providing a string here and it's kind of a good step in moving forward and starting to get things moving. But we want to ultimately be doing the right things. And the right thing right now is we want to serve up actual HTML to the end user. So how can we do that? Well, here is the basic web server that we previously built and as you can see we're just writing a simple formatted string out to the response writer and then it's being presented in the browser. So let's take a step forward a little bit and start to make this a little bit better. So I have a new Go application here that I'm ultimately gonna start running as my web server in a moment but first I wanna make a little bit of a change. The only thing that I wanna change is the body of my handler. And I'm going to inject some code in here and don't get too freaked out. I know this is ugly, but let's just walk through it very slowly and then you'll see where I'm trying to get with this. So instead of just returning back or writing a string to my response writer, I actually want to write some HTML because that's what we wanna serve up. We wanna serve something that the browser can understand, that the user can interact with. So as you can see here, I have stopped using the fprintf function and just went for fprint. And the reason that I've done that is because I'm not really doing any string formatting here, I don't have any %s's or %d's or anything like that. I'm just presenting some raw string, which just so happens to be HTML. So if you take a look in here, I've created doc type, I have an HTML tag here. In my head I've got some meta tags and a title my amazing blog and then I in the body have created a header with an h1 that says Welcome to my amazing blog. So you can see here, the goal that I'm trying to ultimately get to is build a very basic blog or the skeleton of how you could create a very basic blog. Now the concepts and the ideas that we're learning here, in the in the last lesson and the next few, is just to get you to a point where you can do these types of things. And then you can add in as much styling and JavaScript and whatever you want to do but there's some really cool tools that Go provides for you that are really important to understand before you get to that point. So now instead of just serving up of a string, I'm gonna serve up this HTML. So I'm gonna make sure this is saved and then I'm gonna head back over to my terminal and going to kill that version of the server and I'm going to go and get a different one. This time I'm going to go to my Servinghtml and I'm gonna run that server. I'm gonna come back over to my browser and I'm gonna clear out this Derek stuff because I don't need it anymore. And then you see here I now have Welcome to my amazing blog. So that is obviously changed and where did that come from? Well, that came from our markup. So not only do I have this kind of header, this bold text here, I also have a title up in my tab here. And if we were to go into our page source, you're gonna see here that we have HTML. Now do pay attention, we do have everything lined up along the left and in the world of HTML it doesn't really matter. But in the moment you're gonna see that there's gonna be a change happening and it's to help prove a point of where this data is actually coming from. So now that we see we can actually put some HTML in front of the user, let's come back and take a look at our code and really see if this is good or bad. And I'm going to give you a little bit of a hint that this is not bad, this is actually horrible, but let's talk about why. So we are now able to present some markup to the end user and that's good, that's what we want to do. But we're going about it in the wrong way. So as you can see in my code here that I'm really intermingling front end code with back in code and that's never a good idea. And why is that never a good idea? Well, because it becomes very difficult to modify and change the way that the UI looks to the end user without maybe breaking something on the server. And you can run into a lot of bad scenarios. So, what I want to do is be able to pull those things apart. And another reason why that is a problem, especially with a programming language like Go, is because in a previous lesson, I mentioned to you that Go is a compiled language. You actually build these source files into an executable file that you can then run. I have been skipping that step and just doing the run command because it kind of hides all of that complexity, does all of those steps, and then runs my application. Well, in the real world, if I wanna go out there and I want to modify this code. If I want to change the way that the UI looks, I would have to modify this stringed version of my HTML. But in order for that to actually show up out in the real world, I would have to save this, I would have to recompile it, build it. I would have to send it out and deploy it and then the end user would ultimately see it, just so that I could change the way the UI looks. And that's a bad thing because now, like I said before, we've got all this front end back end stuff intermingled it just becomes a really really big mess. So how do we fix that? Well there's many different ways that we can fix that but one of the most straightforward things that we could do, using Go and some of the built-in standard library functions. Is take my markup that I have right here as a string, extract that into a separate file and then just have my server code worry about responding to messages, accepting requests that come in, do something to determine what needs to be displayed to the end user and then do that. So how can we facilitate that using Go? Well, so what I'm going to do is I'm going to take all of this markup and I'm going to extract it to a separate file and that is this blog.html file I have here. So as you can see, I have kind of reformatted this a little bit. There's a some tabs in the beginning here, just so that you could see that it's a little bit different than it was, when I was doing it row strings in the actual Go code itself. But I have this file I have this markup somewhere else, how do I actually get to it? Well, I have another version of server code here that's gonna change things once again just a little bit further, not too terribly and you're gonna be able to walk through this pretty simply I think. So the only modifications we've done here now is we've introduced a new package, this io/ioutil which you're gonna see in a few moments is going to allow me to read files from disk, you can also write files, but for our purposes reading will be just fine. Our main function is gonna be the same as it was before, and our handler function now looks a little bit smaller. And it's only calling off to another function. It's going to call off to loadFile, which we'll take a look at in a second and then it's gonna call our Fprintf function with a couple variables, our response writer and then ultimately the body of what we're reading from that file. So, if I take a look at loadFiles, you can see here it takes in a string which is going to be the file name that we want to read from disk and it's gonna have multiple return values of string and an error. And the error is kind of a specialized type of Go that's going to allow us to see what errors are going on and then we can handle those in an appropriate way. Okay, so now that we have our signature of our loadFile function, let's see what we're actually going to do. Within the ioutil package there is a ReadFile function that allows me to pass in the location of a file on disk. And it's gonna read it for me, and it's gonna read in the bytes of that file so that I can do things with it but this also has multiple return values. It returns back the bytes of the file as well as an error if it exists. So if you will typically get one or the other from the readFile, you're not typically gonna get both bytes and error because they're two different things. So now the first that thing I'm gonna do is I'm gonna check to see if an error came back. And if it did, then I want to make sure that I'm returning an empty string for my body of my HTML or for the body of my web page. And then the error that was returned back so that the consumer of this function could then do something with it if they so choosed. But if it worked fine, then I'm going to return it, and what I wanna return now is the actual string that was found within that file. But since I'm getting bytes back, what I need to do is I need to cast that or convert that into a string. And I mentioned in a previous lesson that there are a lot of different ways to do that based on the types that you wanna go back and forth between, by using special helper functions for each type. So because I want to return a string, I can actually use the string function in passing in my bytes and the result is going to be a string. And then I'm also going to return a nil here for the error because if it succeeded I'm not going to worry about the error itself. Now if we come back into the result of our loadFile function, you're going to see here that I have two variables or at least I have a variable here called body and this weird little under bar thing, so we'll talk about that in just a second. So if everything goes well I should get a body and then I'm simply going to write my body out using my Fprint function out to my response writer, and then everything should work just fine. But let's come back and take a look at this underbar for just a moment, so what exactly is that? Well, when you start talking about functions that we can return multiple values, what happens if you have some of those values that you really don't care about that you're never gonna use? So the example would be, I know a function in this case is going to return two things. It's gonna return a string and it's gonna return an error. What if I, for all intents and purposes don't care about the error I'm just going to go charging ahead regardless of what is happening and I will tell you that that's not a good idea. If you're given an error back, then odds are you're probably gonna want to do something with that. But for demonstrated purposes, I'm just showing you that in this case, all I care about is the body. The error I don't care about, so I can specify this underbar which really tells Go, it says, I know you're gonna return multiple values, I know you're gonna give me some extra piece of data. But don't bother with creating a variable, allocating memory space and doing all those types of things because I'm just not going to use it. There's no point doing that. Let's save those resources for when they're actually needed, so that's what the underbar is telling Go to do. So now we've gotten to a point where I've removed all of the markup from my server side code and I should be able to go and read my HTML file and then present it to the end user. So, let's come back into my terminal and once again let's quit this and let's run a new version here, which is going to be serving from a file. So head back to our web browser and let's go ahead and refresh our page. And it doesn't look like anything is actually changed. But if I come in to view my page source, you're now gonna see that this is a little bit well formatted. I have some indenting going on in here, so it's a little bit easier to read and that's because it actually came from my blog.html file because that was much better formatted. So there you have it, now we have multiple ways of being able to serve up HTML to the end user. Although one is really more accepted than the other and that's simply because you don't really ever want to intermingle server side and client side code especially in a compiled language, such as Go. Because it's going to ultimately run into a maintenance nightmare that's going to become very difficult for you to maintain at scale, as your web application continues to grow.

Back to the top