What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Building Web Applications with Node.js and Express 4.0 (UPDATE)
by Jonathan Mills
With Node.js, you can take your existing JavaScript knowledge and use that to build full-stack web applications. This course will teach you how to build out routing, databases, and third-party APIs in Node.js and Express.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Course Overview
Course Overview
Hi everyone. My name's Jonathan Mills and welcome to my course Building Web Applications with Node.js and Express. Now I've been a JavaScript developer for quite a long time and I love being able to leverage those JavaScript skills in building backend web applications. I can take JavaScript anywhere I need it to go. So in this course, we're going to build a web application from the ground up using Node.js and Express. Some of the major topics we're going to cover, we'll cover quite a bit. Templating engines, there's a couple of different ways to write html out. And we're going to talk about what those are. We're going to talk about databases. We're going to cover both Mongo and SqlServer so you'll get a look at both different kinds of databases. We'll do some security with passport so you can see how to create users and how to log in and log out. And we're going to do some 3rd party APIs so that you can understand how to call out to a different API and pull data in and use that in your application. Now by the end of this course, you should be able to build a full blown web application all on your own. I'm going to cover just about everything you need to know to make that happen. Now before the beginning of the course, you should be familiar basically with JavaScript. I'm not going to talk about what JavaScript is and how JavaScript works but I will cover Node from the ground up. So you don't need to have any Node experience but it's helpful if you know JavaScript. So hopefully you'll join me on this journey to learn all about Node.js and Express here at Pluralsight.
Getting Started
Introduction and Installation
Welcome to Building Applications with Node.js and Express and this is a course that's going to walk you through getting a whole website up and running with Node.js and Express and Node is kind of getting to the point where it's taken over the world just a little bit, where you've got Visual Studio Code that was built on Node and you've got Electron applications sprouting up all over the place and Twitter and Walmart use Node for their backend, it's just kind of everywhere and so this is a course that's going to get you started moving in the direction you want to move in. So what are you going to learn in this course as a whole? And, like I said, we're going to build a web application. Just from the ground up, we're not going to use a CLI or anything, we're actually just going to build the whole thing all the way through. We're going to use Node and NPM. NPM is the package manager for Node and we're going to use somewhat close to the latest version of Node. Node's going to change quickly, we'll talk about that in a minute, but Node and NPM are the core foundation of what this course is going to be. We're going to talk about templating engines. There's Pug, which used to be Jade, there's EJS, there's a few others. We're going to talk about those too and I'll show you what they are. We'll talk about NMP scripts, that's what we're going to use to build out all of our processes around our application. In a previous version of this course, we've used Gulp, in this version of the course we're going to simplify a little bit and just use NPM scripts because the vast majority of what you need to do is just going to work just with that. We'll talk about routing and setting up multiple pages and just building out the framework for a full web application and databases, we're going to do databases a little different, we're going to look at two different extremes. We're going to look at Mongo on one side that is a no SQL database, a document store kind of database and then we'll look at the other extreme with SQL Server. I want to show you SQL Server specifically because there's many enterprise shops, dot net type shops, that use SQL Server and I want to demonstrate to you that that's fine, you can use SQL Server and Node at the same time and then we're going to consume APIs. In our application we're building out a book list and we'll have Good Reads as a backend API that we can go to to pull images and descriptions for our books. So let's get started. We're going to talk just a little bit in this module about Node and how it works and all those types of things and then we'll get started building out our web application.
What Is Node?
So let's take just a minute and talk about what Node is. Just so we're all on the same page. So first of all Node.js is server side rendered JavaScript. Normally you think of JavaScript running in the browser, well in this case, Node.js runs on the server so we can write our server side code in the same language that we write our browser code, which may or may not be a feature. It's cross platform and what cross platform means is it can run on Windows, it can run on Mac, it can run on a lot of things actually and, so, it's actually becoming a very common tool to use for desktop applications because we can run Node anywhere so that makes it easier to deploy and, a matter of fact, I mentioned Electron just a little bit ago. If you go out and look at Electron, this is using Node to build cross platform desktop applications and I know that's not the point of this course but I just wanted to point this out. And when you scroll down, you look at apps built on Electron, you got Slack, and you got Visual Studio Code. So when Microsoft had to write a cross platform IDE, they went with Node so if it's good enough for them, it's probably good enough for us too. Now that's only Electron, so that's desktop, but it's an indicator of, hey, this stuff runs everywhere and that's really where we want to get to. In addition to being cross platform, it's also JavaScript, and let's be honest, JavaScript's pretty awesome. I love JavaScript, I use JavaScript all the time and I say JavaScript is awesome kind of tongue in cheek, right? All a lot of people struggle with JavaScript a little bit but there's definitely benefits to having your server side code written in the same language as the front end code and it's not a matter of reuse, we're not necessarily going to reuse a lot of code, people say that but it just doesn't happen as often as people might think but at least it's the same context, it's the same syntax, it's the same thought processes, so having one language that runs everywhere is definitely very advantageous and last it's open source. Node.js is a completely open source thing that you can use that's going to run your JavaScripts. As a matter of fact, you can come right out here to the GitHub repo and see what's going on with Node.js. It's just GitHub.com slash Node.js and this is where the code for Node.js is and you can see there's a ton of contributors, 1,300 as of this recording, 17,000 commits, it's very active, as a matter of fact, right here you've got stuff written a day ago, so that's huge and now you can go in and look at it. It's not written in JavaScript, it's actually written in C++, so you got your dot cc using your dot hs but it's right here, it's a massive community in charge of keeping track of and working on Node.js. So that's Node, right, that's what Node is. It's basically just server side JavaScript. Node is only part of the puzzle when we get into this building a web application thing. Remember this course is Node.js and Express so let's talk a little bit about that. So what is Express? Here we've got a layer, we've got Node.js, we've got NPM, which is our package manager, and we've got Express and, so, what does Express do for us in this case? Well it's our web development framework. Node.js runs JavaScript, Express is, think about it as your web server. It's the web development framework, it's the JavaScript package that's going to allow us to build a web application. We talked about Electron, I showed you the Electron website, that's the package that allows you to build desktop applications. Express is the package that allows you to build web applications. It's a fairly unopinionated thing. There's a lot of different ways to do it. I'll show you some ways to make things work and then you'll go out to Stack Overflow or somewhere else and they'll say, "Hey, we do it this way." And that's totally cool. It's very unopinionated, you can do things in a lot of different ways and it's fairly minimalist. The actual Express code we're going to write is not a lot, we'll write a lot of JavaScript, we'll do a lot of JavaScript things but Express is a very minimalist package that allows us to just get the stuff done that we need to get done.
Installing Node
So the first thing we need to do to get started is to install Node, that may seem fairly obvious and some of you may have already done that but I at least want to talk about it just a little bit. So head out to Nodejs.org and you'll see on the front page, maybe somewhere on the front page, a download for your specific operating system and here I've got 8.9.4 for LTS and 9.5.0 for Current. The only thing I can guarantee you is that's not the numbers you're going to see because Node versions change rapidly and we'll talk about that here in just a little bit. One thing I do want to say is make sure you're at least after Node 7.5 ish because we're going to use Async Await to do some things and that came about a little bit later so if you're on an older version of Node, stick around, I'll tell you how to deal with that here in just a couple of clips. So you can either click right here or you can go to the downloads tab and the downloads tab, you can download for Windows, Mac OS, or you can get source code. You can download Sun or for Docker images there's all kinds of options but what I'm going to do is I'm just going to click on the 64 bit installer, the Mac OS installer, I'm going to download that. I would suggest you download whichever one is appropriate for you, run through the installation process. I'm not going to walk you through it because you could run this literally on any platform and so I don't want to do one and then have three quarters of the audience not get it so at this point, you should just be able to walk through installation and go from there. Once that is done, you should be able to pull up a command line and type node minus v. Hit enter and you'll see right here 8.9.4, that's the version I just installed. As part of this, it'll also install NPM and NPM is the package manager for Node and its version will be very different. So type npm minus v and you'll get 5.6.0 or some completely different number. Node does a very good job of being backwards compatible so I wouldn't worry at all if you have a fundamentally different version. If it's up to Node 12 or whatever, it doesn't matter as long as it's post mid sevens and I'll show you a way to figure that out here in a little bit and I'll show you a website that helps you figure out what features are available here in just a little bit. So once you're here and to this point, you should be good now let's go talk about this Node version thing.
Dealing with Node Versions
So we can't really talk about Node without talking about Node versions because versions change pretty rapidly in the Node world and that's a good thing, we like change, we like the additions that they're making but we need to deal with this and if you look at this screen, you'll see that Node changes very rapidly. Node eight was current right up until about November of 2017, Node nine came along and will be current until about April but then Node 10's going to come along in May or so and be current until October and so you'll go through some changes fairly rapidly. It used to be current for three months and that was it, it's gotten a little bit longer than that but also notice how the actives work. Node eight is active and Node 10 is active, so that's the long term support version. The odd numbers, Node seven and Node nine, don't ever hit LTS or active and that's just the cadence that they've struck with their versioning. So with that being said, how do we deal with versions because you might be working on a project on Node six, this course is late Node eight, you may have Node 10 come along and there might be a breaking change and so you want to go back and use Node eight, luckily, there's a simple way to do this. There is a tool called NVM that's going to make this happen. Now let me walk through Node Version Manager just for a minute and you get to it, it's out on GitHub, if you search GitHub for NVM or can just go to creationixnvm, that's the right way to get there, this is a tool that allows you to manipulate and change the version of Node that you're using and if we scroll down, one thing that's very important, I'm going to scroll down to important notes right here. I am on a Mac, so I will be using NVM. NVM does not support Windows and that's very important and so immediately if you're running Windows, you may have just tuned me out and said, "Well, that's horrible." There are options, however, I have a Windows machine too, I use both and so NVM Windows is the tool that you will use if you're using a Mac. It's different but for the most part, in the important ways it's identical, so I'm going to kind of walk through NVM but if you're on Windows, use NVM Windows, it works pretty much the same way. So if you're on a Mac, click back over to NVM. If you're on Windows, stay over there but the first step is to install and so we'll come up and there's an install script and so if you're on a Mac, copy this right here and install it. On Windows, you can actually download if you scroll down, you can just download it right here. Once you have it installed, let's pop open a terminal window and let's look at what this looks like. So right now, I have 8.9.4 installed and that's the version that I'm using. If I type nvm install 9.5 and hit enter, it's going to install Node 9.5 and it's going to upgrade my version of NPM so now if I type Node minus v, I get 9.5. So that's great, I can switch back and forth. If I go back to nvm use 8.9.4, it switches back and forth and so that's the beauty of NVM is I can go back and forth between the two. There is one thing to pay attention to, though. If I go node use 9.5, now I'm using nine five. If I close this terminal window and open a new one, I go node minus v, I'm back to 8.9.4. So it's going to remember 8.9.4 as the default. When you do node use it's only for that one specific instance. One other thing I want to point out is there are some shortcuts. I can do nvm install minus minus lts and that will install for you the latest version and I've already got it installed but the latest lts version of Node that's available to you. Now the way to deal with the fact that things change is we can do nvm alias default, let's set it to 9.5, now when I close my terminal window and I open a new one again, and I do a node minus v, I'm using 9.5 and so that's how we deal with the fact that it's always switches back and forth to the one that's set to default. We just do this node alias default 9.5 and what I'm going to do is 8.9.4. I'm going to set that as my default and that's the version we're going to use for the rest of this course.
Command Line Node
Alright, so now that we've got Node installed and we've got the right version running and all that stuff, let's look at it from the command line for just a minute. Just a minute, just so you understand kind of where this comes from and simplify a little bit because here pretty soon we're going to be running massive applications, I want to simplify things for just a second so it's a little easier to follow. So if I'm here at the command line, I can type node and when I type node, I get this little caret and that's it and it just sits there and I can do cool things, look at this. I can do var x equals five. Var y equals three. Function sum a, b, equals return a, b. So I've got two variables and a sum function. I can just do this, sum x, y. And check that out, I get eight. Node at its core, is just a JavaScript interpreter. That's all it does, it's a JavaScript compiler and it compiles and runs it, it's a runtime and it does all that kind of stuff but that's all it does, right? Now you can imagine, though, however, this would be pretty tiresome, writing out your entire application at the command line, so obviously we don't do that, right? We create a file and so, here I've created, basically this same thing as a file. First dot js, I just typed all that stuff back out and now when I run this, so I exit out. I type node and first dot js and it runs my JavaScript file. And so that was a lengthy way of demonstrating my point of all Node's going to do is either pop out to the command line and allow you to enter some JavaScript or it's going to take a JavaScript file and it's going to execute it, that's it. I mean as complicated as Node is, that's really all it does. And, so, when we start getting into our Express applications, though, I just want you to think about that mindset. All Node does is run a file and what that file does from there is up to the file and so over the course of the course, you don't always have to run the one file, right? When we start creating services, we can actually like run just the service, or we can run just one thing or another and that's a cool thing you can do when you start to think about things a little bit more abstractly than we have up until now.
Picking an IDE
And one of the fun things about working in JavaScript or actually one of the frustrating things about working in JavaScript is there's lots of choices, right, so I mean, it's a lot of fun, you can try a lot of different things, no one's telling you this is the way you must do it but at the same time, you got to make a lot of choices and over the course of this course, I'll try and minimize the choices that you need to make. I'll make some for you but I want to walk through this idea that you're not tied into an IDE. There's more than one that you can pick from and I'm going to kind of let you pick the one you want to use for this course, it really doesn't matter which one you use but I'm going to show you a couple of them. There's three that I'm going to talk about just briefly. Sublime Text, WebStorm, and then VS Code and I've already told you we're going to use VS Code for this course but I want to at least show you a couple of points on the other two. Now before you write me hate mail, right, I'm not showing Atom, Atom is another one that's out there and you can try that but it's not one that I'm really going to talk about. VM is out there, I'm not going to talk about that. Brackets, and so, there's a lot out there but I'm going to try and narrow it down to here's a couple of choices you have and I'll talk about why each one's good or not good or why you might want to use them. So let's talk about Sublime first because Sublime's a really fantastic text editor but that's what it is, it's a text editor. You can get syntax highlighting and do all kind of of stuff like that but, ultimately, Sublime is a very, very stripped down IDE that's got some package options, you can get syntax highlighting and things like that if you really, really want to but if you want a very lightweight simple easy IDE to use, and it's not really even an IDE, it's just a text editor, Sublime's the way to go. Now most people don't know this but Sublime is commercial. To buy a license, it's like 70 dollars, it's what we can nagware, right? You don't have to buy it but they request that you buy it and if you really like it, pay for it, it's great. I use Sublime Text for a lot of things, I've moved away from it as an IDE but Sublime Text is a great, simple, stripped down option. The other end of the spectrum, like completely the opposite side, is WebStorm. Now WebStorm is by Jet Brains and so if you're a dot net dev, you may be familiar with Jet Brains for Resharper and they've got some great Java products and Ruby products and so they've got a great suite of products and WebStorm's kind of right in there. It's a true IDE, it's a full-blown integrated development environment. It's got everything you need, it's very hefty and very powerful, it's by Jet Brains. They're a trusted name for a lot of developers and that stands up. The other side of this, though, it is a commercial editor, it's like 99 dollars and it's expensive but it actually is worth the money if you want that true IDE feel. If you're very comfortable working in like a visual studio, WebStorm may feel very comfortable for you. The last one and the one I'm going to talk about and use over this course, is Visual Studio Code and what's interesting is, a lot of times I'll say Visual Studio Code and people will think Visual Studio and that's not it. So Visual Studio Code is very much a text editor, it's an open source IDE, it's very lightweight, very responsive but it's still an IDE, you still get some debugging capabilities and you get some other things that I'll show you over the course of the course. It's also written in Node, which I think is pretty awesome. When Microsoft needed a cross platform IDE, they went to Node and so I think that's a great tool to use when we're talking about a Node course, right? Let's use something that's written in Node to do what we're doing. It is free, so unlike the other two I've shown you, this is a truly free tool which makes it great for the JavaScript community. JavaScript community's all about open source and an open source free IDE, you can't get much better than that and it is powerful, like I said, you've got debugging capability, it's got integrated terminal windows, it's got git integration that's really good. There's a lot of really cool pieces to this that are going to do what we need to do. Alright, so, that's an IDE. I'm going to use Visual Studio Code, you can use whichever one you want but once you get your IDE picked out, installed, played around with it a little bit, ready to go, let's go get some work done.
Node Package Manager
Alright, before we get started, I know I keep telling you, "Before we get started." Well we got one more thing to talk about and then we'll start getting some code written. The first thing you always do when you are going to create a Node application, is get your directory set up and get your NPM going and so what we're going to do, is I'm going to make a directory called library. We're going to create an app that deals with books and books we've read and things like that. So I'm going to make a directory called library. I'm going to cd into that and then I'm going to run a command, which is the command that you should always, always start your project with, npm init and it's going to ask you for some defaults. You know, with a name, the version, a little description of your app, what you're going to start with. We're going to start with app dot js. No git repositories, no keywords, no author, no license and it's going to create this package dot json file for us and we're going to say yes. Now real quick I ran a command, npm init. Let me talk a little bit about what npm is so we can all kind of get on the same page. Just real quick, what is npm? Npm's just a package management for Node. So if you're dot net developer, think nuget, gems in Ruby, there's packages that you are going to use and Express is one of those packages we're going to use to build our web apps and we're going to use a ton of packages but that's what we're going to do and npm's a tool we do it and you may have heard of Yarn, which is the Facebook alternative, hopefully the idea is once npm improves, Yarn will kind of go away so I'm not going to show you Yarn but if you've heard of it, just know it's a thing that exists. It also is easy updates and version management and let me show you real quick what I mean by that. It handles the versioning of your packages very, very nicely. Alright, so if I open this directory up in Visual Studio Code, and I open my package dot json file, this is what we just had, right? So I've got name, version, all that stuff. One of the things I like about Visual Studio is if you hit control tilde, I get a little terminal window. This terminal window is the same as this terminal window, same thing. If I do an ls, or windows a dir, you can see I get a package dot json. So the very first thing, the second thing, write npm init, the second thing we're going to do is an npm install minus minus save express. We're going to hit enter and you will see now in my package dot json file, I now have express 4.15.2 as a dependency and it's just straight up this way. Now yours will have come with a caret in front of it. I've got it set up to not do that and I'll show you how to do that here in just a minute. But with this caret set up, that might be a little confusing or you might see this little tilde there, there's little symbols involved and so let's take a minute, let's talk about package management and see what's going on there. So I'm going to save that and then let's run through a couple slides, I'll come back and do a couple things.
Versioning Packages
Alright, so let's talk about NPM versioning for just a second because you get this little caret that says 4.13.3 and that's weird because you've got a symbol there but all this caret means is that it's going to automatically update for you as new package versions come out. So here I'm saying 4.13.3 but we know new versions of Express are out because we installed 4.15, right? So what the caret means is I'm going to keep the four and I don't care about anything else so that if I do an npm install, I'll get 4.14 or 4.15 or 4.16, whatever works and as long as it's the same major version, it's just going to take the latest. A tilde is a little more restrictive. So in this case, 4.13.3, if I have a tilde in front of it, then it's going to ignore just the minor version, right? So if I've got tilde 4.13, I don't care what's after that second dot, I'll take whatever as long as it's the latest. The last option and the option that my npm defaults to, is nothing, if I have nothing and I say 4.13.3, guess what? I'm getting 4.13.3 and it doesn't matter if new versions of packages come out or not, that's what I'm getting and a lot of times that's what we default to because there have been known to be, and there shouldn't be, but there has been known to be breaking changes in minor versions and so that kind of makes me squeamish and so I want to make sure I have a little bit more control. Some people are less concerned about that and that's totally cool. So you can do whichever one you want. That's kind of the way versioning works. Let me show you an example with Express so you see exactly what I'm talking about. Now here I've got 4.15.2 and if you go into node_modules, you can actually see this and remember all I did was nmp install express and look at all the stuff that came with it. These are all the dependencies for Express. Npm, the latest versions, have collapsed this. If you have watched this course in the past before the update, there was only one thing in there and now there's a whole bunch and that's just because npm has flattened out its dependency tree. So if I go to express and I go to the package dot json and scroll all the way to the bottom, you see I have version 4.15.2. If I come back to my package dot json and let's just say, hey, 4.13 and I put my caret there, save that. Control tilde to get my terminal and I'll do npm install. Actually let's delete the express directory here. Just so you'll believe me 'cause it's going to give me exactly the same thing, right? Npm install, I'm looking for caret 4.13 so it should've installed the latest version four so if I come to express, go to my package dot json, down at the bottom, 4.15.2. Come back to my package dot json, if I go to a tilde 4.13.2 and I run npm install again, now I should have four dot 13 dot something. It helps if I save it then I run it. There we go, now you see a whole bunch of stuff was installed and look express 4.13.4 was installed. If I take the tilde out, run it again, now you see 4.13.2 is installed. So in this case, we're going to do 4.15.2, that's what we're going to use for this course. Five is in alpha, there are not a lot of breaking changes, there's actually no breaking changes that we will use in this course so if it's express five that gets installed, you can go ahead and run this course with express five, that'll work. If anything comes up, I'll let you know in the comments and we can get that figured out. Now there's two things I want you to set with npm to get the same behavior that I've got going on in mine. We're going to talk about our npmrc file. So if you go into docs dot npmjs dot com, files npmrc, I'm showing you the webpage instead of putting this on a nice, pretty slide because I want you to reference the page and come out here and look because there's a bunch of stuff out here that potentially will impact what you're going to do. But what I'm going to do is I'm going to create a per-user config file, I've got one already created in my home directory that does a couple of things and come out here and look and get one set up for yourself and let me show you what that looks like. Okay, so from here I'm going to do vi tilde slash dot npmrc, just so you can see it. Okay, so I've got three settings set up here. Progress equals false, save equals true, and save exact equals true and the two that I want you to care about are save true and save exact equals true. If this is set to false, you're going to get a caret and remember I didn't get a caret and save equals true, let me show you what this does. So let me get out of that and come back over here. I'm going to do npm install chalk and chalk's the next one we'll install. Notice how I didn't do minus minus save and it shows up in dependencies automatically 'cause having dependencies is important and we always forget to do minus minus save. So now I just don't need to worry about it. I also got the exact version, 1.1.3. So that's what those two things are going to do for you if you set up your npmrc file. So get that set up for you. Follows the docs for depending on whatever OS you're on and we'll get that running. That's it for this. Now we've kind of danced around this for a little while. Let's go write a webpage. That's the next module, let's go get a webpage written.
Summary
Alright, oh my goodness, we came a long way. Just one module, we had to get a lot of stuff out of the way before we could go get something done and that's what we've done. So we talked about what Node is. It's an open source runtime environment for JavaScript on the server, that's pretty much it. We talked about how to install Node. We download it, we installed it. We talked about versioning. So we installed one version but Node versions rev pretty fast and so we talked about using NVM to be able to flip back and forth between maybe the latest version and then going back to a different version, either the lts version or something else that your workplace might be using. It's easy to flip back and forth. Oh my goodness, we have so many IDEs. I only showed you three, I only talked about three. There's a lot more than that. I don't care which one you use. That was kind of the point, I gave you a couple of options. I don't care which you use, I'm using Visual Studio Code because it's free, it's powerful, and it's written in Node. So do whatever you want, that's what I'm going to use and if you're having problems with an IDE that's not Visual Studio Code, still drop a comment, I'm sure if either I can't help you, someone else will be able to help you. We talked about NPM as a package manager. NPM is how we're going to get packages from the NPM registry and install them on our local machine. Now those packages rev quickly and so we talked about how to deal with package versions, and carets, and tildes, and all these different things. I set up some NPM settings for you so that you don't have to worry about package versions as much. You're going to get the right version and that's what we're going to get and that's what we're going to deal with and so that might be helpful to you. I think that's it, so let's go write a webpage.
First Page
Introduction
Alright, in this module we're going to set up our first page. While that may seem like a simple thing, index.html, there's actually quite a bit to it and this module sets the groundwork for building out the entire application that we're putting together. What you're going to learn in this module, is how to do index.html. Seems pretty simplistic but there's quite a few steps involved in this. First thing we got to do is get Express setup. Let's actually be serving a route in Express, just our slash route, just the beginning one, but let's get a route set up. Once we get that part, let's run Express, let's get express going and working the way we want it to. We're going to take a detour in the middle of this module, we'll talk about some logging options, we'll talk about debugging and we'll talk about chalk and Morgan and some other pieces that we'll use to help our logging experience look a little bit better. Then we'll serve up HTML, we're not going to get into the templating engines yet, we're just going to serve up straight HTML and work to get that. But as part of serving up HTML, if we want our HTML to look good, we also have to serve up some static files. So, our CSS and our JavaScript and things like that. We'll pull in bootstrap, we're not going to build our own CSS yet, we'll do that a little bit later on but for right now, just to show serving static files, we'll pull in bootstrap and because it's required, we'll pull in jQuery and I'll show you a couple of different ways to pull those pieces in and give you some options there to what would work best for you in your environment.
Setting up Express
Let's start by getting our first web app up and running. Let's just get Express set up and see what's involved in getting that done. Here I've got my package.JSON file and that's all we have so far in our library directory. We've started this in the last module, we've got Express and chalk as dependencies and that's it. And so, I'm going to right-click in here and I'm going to create a new file. And we're going to call it app.js and you can really call this anything but app.js or server.js seem to be the standard that we go by. App.js is what we're going to call it. And then, there's a couple of things we've got to do right off the bat. VAR Express equals require Express gets us started, that gets us Express. And in node, we use the common Js pattern, so var Express equals require Express. We don't do the modules, the ES modules that you might see in other things. Require instead of import, so var express equals require Express. Now, we need an instance of Express too. We'll do var app equals Express and we're going to execute it. You may be tempted to come up here and shortcut this and just do that, don't do that, we'll need Express later. It'll be a couple modules from now but we'll need Express to pull routing and some other things in. So, leave it like this and we'll go from there. I like to leave a space here because this is going to be our list of actual requires and this is going to be the stuff that I'm doing outside of the require, so it's just my own personal thing. Now, the way Express works, is everything works through app. I'm going to say app.get and we'll talk a lot about what this means in a later module but for right now, just go with it. But think about get as, you've got a browser and you send a get request, to slash, and when Express gets a get request, to slash it's going to execute for us a function. That's it, that's really all Express is. It's just a series of, "Hey, when you get a request "to this route in this verb, execute this function." That's not too hard and when it executes this function it's going to send us two parameters. It's going to send us a request and a response. We typically, in the node world, just abbreviate those to req and res. You don't have to, you can call them request and response but that seems like a lot of typing that you don't need. You however, can't shorten them any further than that, it can't be R and R or re and re, so we get req and res. Now, when those come in, we need to send a response. So, we get access to the request and we don't care about that right now, we'll care about that later but for right now, we just need to deal with the response, so we're going to do a res.send and then we're just going to put a message in here. Let's say, Hello from my library app. Whenever I send a get, to slash, express is going to send back a message, hello from my library app. It's just going to send text, that's all it's going to do. And then the last thing we have to do to get express, like running, is for it to listen on a port. We just say, app.listen, and we tell it to listen on a port. In this case, we'll just say 3,000, that's pretty standard or 3,000, 5,000, you can really do anything, but 3,000 is what you'll see most of the time. And then when it starts listening, it'll execute a callback and actually I like this from Visual Studio, 'cause it'll actually even say right here, see, listen, the port number and a host name with a string and then a callback. We don't care about the host name, almost ever, but we care about the callback and so, we can actually just skip that and just go right to the function. You'll see it adjusts the little helper I get to say, hey callback function. And in this case, we'll just do a console log. Let's just say, listening on port 3,000, that's it. That's a full-blown Express app. We're listening on a port, we're going to respond to a get request, and that's it. Now, don't stop yet, there's a whole lot more to this but that's the core of what an express app really is. Let's pop over and run this so we can see what's happening.
Running Express
Now that we've got express kind of set up, let's run it so we see what happens when we make our calls. Here, I've got my express app, if I'm in Visual Studio, I can actually just hit control+tilde, and I get my little window up, which is kind of cool. And it's running right from that location. If you're not using Visual Studio code, you can drop out to a console and run everything from here. And for the most part, I'm going to stay inside Visual Studio code just because it's easier and it lets you see everything that's going on. Every once in a while, I may pop out to a terminal but for the most part, I'm just going to leave it in here. Now, to run this, we're just going to type node and app.js. Now, remember from module one, when you call node and you pass it to Js file, it just executes the file. And so that's really all an Express application is, it's just a JavaScript file, that's got some commands for express to listen to some stuff. That's it, and so we're going to run node app.js to get this thing running. And you see, there's our, listening on port 3,000. If we drop out to a browser, and I'm just going to use Chrome, we come up here and we say, localhost 3,000, there we are, hello from my library app. It works, everything's up and running, done. There's a couple of things I want to talk about though as we get through this. So, listening on port 3,000, we're console logging out to the console and that might make some people feel icky, it's not really a good way to do it, so, we're going to introduce something different and we'll show a couple of different options here. Let's take a minute and let's talk about some debugging choices we can make to keep track of what's going on in our application and we'll do that now so we understand that part before our application blows up into this big monolithic thing.
Debugging Options
What we're going to do now, is look at debugging just a little bit. And I'm going to give you three packages that we're going to install and use to work through debugging our application and just paying attention to the types of things that go on inside our app. The first thing we're going to do, if we break back out to our application is, notice we've got a console.log here that says, listening on port 3,000. And I teased you a little bit in the last module because I had you go ahead and install chalk and if we look at our package on JSON, there's Chalk version 1.1.3. If we go back into our app, up here at the top, we're going to do, var chalk equals require chalk. And what chalk does for us, if we come back over here and we run our application. So, node app.js, and we run our application, see we've got this, listening on port 3,000, and that's totally cool and it's helpful but when we start spitting out a lot of messages, it's hard to see through the noise, and so Chalk kind of helps us by allowing us to set colors on our error messages or our console messages. So, let's take this 3,000. I'm just going to cut that like this. We're going to add a plus. Chalk.green. And actually what's cool here in Visual Studio code, I can hit chalk., and we can see all the color options that we have. But I'm going to use chalk.green and put 3,000 back in there, then we'll save that, we'll flip it over, close it and start it again and now you see, hey we've got some colors going on. Chalk has this nice way of just popping out a little bit of color so that you can, if you have an error, you can color it red, if you've got something working, you can color it green, it just kind of helps you see what's going on with your website. One thing I want to talk about real quick, and we'll drop these in, over the course of this course, since we are in node and we're in node seven, we have access to all of the cool ES6 features. And so what we're going to do, is instead of this plus stuff that we got going on, we're going to use template strings. We're going to take all this off and at the end here, we're going to put template strings. Template strings have the little back tick and that's above your tab key on the Mac. If you're on Windows, don't worry it's in the same place, it's right above the tab key. Here we can just do, listening on port and then around chalk we just do this dollar curly brace, and then we close the curly brace, right there. Or we can save that, come back over here, close this, start it up again, we have the same thing. This is just a cool little way of embedding things in our strings and we'll use this quite a bit, but for right now just say, "Hey, that's cool, "we did string templates," and then we move on. The next thing we're going to do is get rid of console.log altogether, which is super cool because, really we don't want console.log. And I'll give you a better way. We are going to use something called debug. Var debug equals require debug and one feature of debug, the first thing we're going to do with it, is we're going to tell it where we are. So, we're just going to say we're in app and we're going to save that. Now, real quick, we've got to pop back over and do an NPM install. And because we did our cool little NPM hacks, we just have to do NPM install debug, and we're going to get 2.6.6 if we drop down to package.json 2.6.6. Now one thing I haven't talked about, but we probably should talk about just real quick is, if things are broken and we're way out of whack, you can do NPM install debug at 2.6.6 and hit go, and it will make sure it installs that specific version. If you need to do that, I will drop a note in the comments but for the most part, just go with what you get. Now that we've got debug installed, let's look at what that look like. Let's come back over to app.js and instead of console.log, we're going to type debug, and we're going to save this. If we come over here and we run this again, node app.js, notice we get nothing. Our message went away, which may or may not be a good thing but here's why. The cool difference from debug to console.log is that debug only runs when you're running in debug mode. So, if you deploy something in production and you're using debug, it's not going to spit stuff out of the console. That's awesome and that's a huge plus. The way you make it work though, is you type debug equals star, node app.js, and you hit enter. Note that on Windows, you've got to do, set, debug equal star, ampersand, node app.js. Look at all this stuff, oh my goodness. None of this stuff was here before. That's because Express uses debug too, and you can see the cool part about this is, look at this last message. App listening on port 3,000. The first word in all of these things is, what we passed in to debug when we loaded it. So, here we said, require debug app. App is listening on port 3,000, Express application and Express router are also spitting things out, which is super cool but this can actually get a little bit wordy. So, let's talk about how to fix that. You can come in here and just do debug equals app and now you're just going to get messages for app. So, debug is kind of cool because it's going to give us a lot of extra options when we do things. Let's do one more. We're going to do an NPM install, Morgan. And what Morgan's going to do for us, is log some things to the console that have to do with our web traffic. So, I don't have to write these out to the console on my own, we can just use Morgan to do it. So, we come back up here. Var Morgan equals require Morgan. Now, right after we do app, we're going to make a space 'cause we're going to do quite a few of these over the course of this, actually, this module but we're going to do what's called middleware and we haven't talked about middleware yet, we don't talk about middleware actually for a couple of modules but just bear with me, just know this is what we're doing. We're going to do app.use(Morgan). And we're going to say, combined, and I'll talk to you about what that means here in just a second, but just go with this. Some people will actually do this. I am not a fan of this, when we get down here because I like having all of my packages that I'm using just listed up here at the top of my application. If I have requires kind of embedded all down through, it makes it a little bit harder for me to know what's being used. So, just know, you might see that done some and why I don't do it, is 'cause I like to have everything listed up above. Now with that there, let's come back over here and let's start our application. Now, if we come out here, we go localhost 3,000. You see, hello from my library app, and then if we come back over here, you see I have a get, spit out to our page. There's a lot of information in there, which you probably don't care about, so let's fix that. Morgan has a lot of settings and we use combined, that's kind of gives me everything. We can do tiny if you want less information. We'll close this and restart it. Pull our page back up, hit refresh. Now you see we've got our get, and then a fav icon, and we'll talk about fav icon later. Just know that this is the icon that gets stuck up here in the top, and so, every time you hit a page, you get this fav icon thing and I'll show you how to deal with that a little bit later on. Notice, I've got a little cloud that's because it's some other localhost stuff I had. I had that little cloud as my icon, and since its quorum, do we get a new one, it just stuck that one up there. You probably won't have a little cloud up there, you might have something else and I'll show you how to get something like the cloud in just a little while. So, that's debugging. We looked at chalk, we looked at debug, we looked at Morgan and I gave you those three things now because now when we go and do index.HTML, and we start loading all these other things, I want you to be able to see what's going on inside your application when things start to not work.
Serving Index
It's one thing to be able to send some text back to a browser but we're building a web app here, right so we've got to serve some HTML. The rest of this module, we're going to build out and display an index.html page with bootstrap and font awesome and all this cool stuff. But let's start by just getting an HTML page served up. If we come back here, let's right-click in our directory and create a new folder called, views. And views is typically, where we're going to store all of our HTML files, or we're going to use EJS and pug here in just a little while, in the next couple of modules, is where you'll learn about what those mean. If I right-click in views and I do index.HTML, now I've got this HTML file. Let's just do HTML, body, and then we'll just put a message in here serving up some HTML, so that we know, hey, we've got an HTML file coming and if it's done right, we just get that message. The way we're going to do this is, instead of res.send, we're going to do a, res.sendfile. And what send file needs, is a directory and a file. And the way in node, you have to send a fully qualified path name to that file which can become painful, so, the way we do this in node, is we say, under under dirname. And what under under dirname is, is the location of the current executable. So, app.js and we do node app.js, under under dirname is where this goes. And then you can append to that, slash views. The problem with this, so, slash views, slash index.HTML. And there's a couple of problems with this. If I do this, if I leave the slash off, I'll just give you the basic problem. Really, to serve HTML that's kind of it. If I control+C and then I run this, and I pull my browser back up and I hit enter, we get an error. You see, library views is all concatenated as one word and the reason for that is because, I didn't hit a slash here. And that can become just painful, especially when I'm trying to concatenate a whole bunch of stuff together. What we use in node to deal with this, but I also remembered, it's cross-platform, so we've got different stuff over on the Windows side, so if you're running this on Windows, you'd have your slashes like this, right, that's a pretty fundamental difference. And for the most part, it can figure some of that stuff out on its own, but we use a package, called path. And path is built-in, we don't have to NPM install that, which is nice, the one less thing to deal with. But what path gives us is this method, called join. And what path.join is going to do, is join these strings together to form a valid name. Now remember, I got in trouble when I did this. Path.join is going to fix that for us. Now, I've seen some code, where I get path.join and then this still, plus stuff going on, and that's kind of defeats the purpose of path.join. Instead of a plus, we just send in a series of params. So, dirname and then views index.HTML, and it'll join those together for us. Then we hit save, I kill this, I run it again, I refresh my page, and now I get my serving up HTML. So hey, that's progress. Just to kind of prove my point on why path.join is cool. If we do this, notice, there's no slashes anywhere. It still works. One other option is look, I'm going to do slash, and I'm going to do slash, and I'm going to do slash, and I'm going to do slash. So, now it's going to be double slashes there, guess what? It doesn't care, it just works. We'll talk more about path, here actually just in a little bit, when we start talking about static files, but for right now, we've got an index.HTML files being served up. It doesn't do much, but at least we've got one being served. Let's start talking about some style issues. I want to start building out our index but we're going to use bootstrap, and we're going to use font awesome and we're going to use a couple other things, and we need to get those installed before I can get too far into building out my HTML file. In this next clip, I'm going to show you a few different ways to make that happen.
Static Files - CDN
Now that we've got a basic HTML file being served up, we're not going to get too far before we want to add some JavaScript or some CSS files. Let's take a minute and talk about how to deal with this static content and there's a couple of different ways, and we're going to start by talking about CDNs. Now, I've got my index.html here and basically it just says, serving up HTML, but I want to add in bootstrap. And I'm going to talk about bootstrap, mostly because it seems to be fairly ubiquitous across most of the internet, so, we're going to go with that. We're just going to add bootstrap, getbootstrap.com to our HTML and through this, I'll show you how to deal with static content. Let's click on the getting started tab, and you'll see they have bootstrap CDN, right here. And so, what a CDN basically is, it's a hosted CSS elsewhere. And the idea being, if everybody serves their CSS from this place, then everybody has it cached already and you're not downloading it over and over again. Let's take this, we'll copy that and then up in our HTML, let's add a head tag. And we'll just add these in here. Now, the JavaScript should actually be down in the bottom of the body. Let's save that. Clean this up a little bit, and then we'll pull up this and we'll run our app, so, node app.js. Since I didn't run it with the debug stuff, I'm not getting any information, let's run it with the debug. Go to our localhost 3,000, there's our serving up HTML and if we inspect, we get to our console, will say, "Oh, hey bootstrap requires jQuery." We're getting bootstrap. You see in our network, if we refresh our page, there, we're getting all of our bootstrap but we are not getting jQuery, and so we need that. Now, jQuery is going to come from a different spot. So, let's go to code.jQuery.com, and that's going to give us, if we click minified here, the same little script tag that we can just copy. And we'll drop that down here and run that. Now, how do we know that this is working? Let's add like one thing. Let's come in here and add a class equals container. And put our serving up HTML, inside our div. That should actually clean this up a little bit and when I come back here and refresh my page, there, it slid over a little bit, that's what the container does. Actually, let's add another div, with the jumbotron. And now, there you go, now we're bootstrapping it up. That's a CDN. CDNs are just these places on the internet. jQuery's got one, MaxCDN does the bootstrap stuff and that's a great way just to drop stuff in. What it doesn't do, is your own custom CSS and JavaScript, so, we got to deal with that still. And what it also doesn't do, is let you work offline, 'cause if you're coding, and you're not connected to the internet, none of this CDN stuff works for you. There's an easy way to get up and running but it's not going to be our long-term solution for us. So, let's talk about how to set up static directories that Express will serve up for us.
Static Files - Public Directory
Now, as we said, a CDN only gets you so far. You can't work locally, so, let's do something else that will get us a little bit farther. And what we're going to do is, we're going to create a public directory and we're just going to put all of our CSS and JavaScript and all of that stuff in a public directory that we can then serve out of. Right here, we're going to create a new folder, called public. And in this directory, we're going to create two other folders, one called CSS, and one called js. And we can put our JavaScript files in js and our CSS files in the CSS directory, and that's where we can serve things from. Now, we have to let Express know that we're going to be sticking things in these folders. And the way we do that, is with a little line of code right here, right after our Morgan, we're going to just say, app.use, just like we did with Morgan. And in here we're going to say, Express.static. And what express.static does, is it just says, "Hey I'm setting up a static directory, "that we're going to use for static files," static files being CSS or JavaScript. And we're going to tell it where our static files are. And the way we're going to do that, is the same thing we did down here. We're going to do a path.join, and we're going to say, under under dirname, comma, slash public. Now, anything that we stick in public, is going to be accessible to the outside world. And it's just going to look in there and see if it's in there and go with it. And so, what that's going to look like, is now instead of index.HTML looking for bootstrap, bootstrap min CSS, we can actually delete this and we'll do this, hey, give me CSS bootstrap min CSS, CSS and then oh, we've got to put it in there. And the same thing would be here, the bootstrap theme. Bootstrap theme min CSS. We can actually get rid of all of this other stuff here too. And so, it just looks like that. Now for JavaScript, we come down here, and the same basic idea, we get rid of everything and we just say, slash js, slash jQuery, and we say, slash JS, slash bootstrap. That's where these files will go. Notice, they're not there yet, so we've got to put them in there, and the way we're going to do that, is a couple of ways. The first way we could do it, is to come back over to bootstrap and just download bootstrap. That's an easy way to do it, you click download, it's going to download it and all of that, and that's great. That's one way to do it. Another way to do it is to use NPM, and I like using NPM for something like this. We're going to close out of this and we're going to do NPM install bootstrap and jQuery. And minus, minus, save if you didn't do the little thing at the beginning, otherwise, just hit go and it's going to go. I noticed, we're 3.3.7 of bootstrap but 3.2.1 of jQuery and that's going to drop those into our node modules directory. What we're actually going to do is just come in here, go into node modules, bootstrap, dist, CSS, and just pull all this stuff out of here. Drop it into public CSS. Then we go to js, copy this. Public js, paste that there. And then we also need jQuery. So, node modules, jQuery, dist, jQuery, and really, I've been copying all of it, you really only need jQuery min, that's what we're actually doing, so, I'm just going to copy that one item. I'm going to come back into JavaScript and paste that. All of that's, there now. And you can see here in CSS and here in JavaScript, it's all there, we NPMed it, we copied it over. Now, let's NPM start again. I come back to our browser and refresh our page. Now, you'll notice, it didn't find jQuery, it did find bootstrap, but I installed a different version. It found bootstrap, it found bootstrap.theme.min.CSS, it found bootstrap.min.js, it just didn't find jQuery, so let's pop over, and this is Morgan, spits this cool stuff out, it just says hey, jQuery 3.2.1 it wasn't there. And the reason why it wasn't there, is because when we copied it, it is just jQuery min.js. Let's come back over here and just say, jQuery.min.js. Save that. Refresh our page, and there you go, everything works, it's all good. That was painful and I intentionally made it a little bit more painful, copying and pasting all of that stuff, but that's a little painful because I miss out on a couple of things. What I do get out of this, is now I have my public directory all set, where I can put my CSS and my JavaScript, I don't want to host my stuff on a CDN but I can put mine in there and what we'll do with it is a site CSS, we'll do that a little bit later on and our own personal JavaScript bundles that we'll put in there a little bit later on. But for right now, I don't want this stuff, necessarily my CSS, it was already over in NPM. And the next time I do an NPM update, and I get a new version of bootstrap, I have to copy it over again. I don't really like it, I kind of want to be able to pull that right from where it was. And so, let's take a look at how to do that.
Static Files - Node Modules
Now, let's take a minute and look at how to serve these files straight out of our node modules directory. That's ideal, that's where I kind of want everything to be because when I do a NPM update or things like that, then I'm pulling from right there. I don't have to worry about copying files all over the place and it's really not that hard to do it. Let's come in here and delete everything in our Js directory; and everything in our CSS directory. Now, we're going to leave the directories there and we're going to leave in our app.js, this express static because we will end up putting CSS into our CSS directory, so we don't want to mess with that. We're going to leave that, everything we've done up till now right where it is. But we're going to add to our app.use, another directory. We're going to come back here and right under this, I'm going to hide that for a minute. We're going to add an app.use slash CSS, Express.static, and then add just a, node_modules/bootstrap/dist/CSS. Just say, "Hey, if you go to slash CSS, "this is another spot that you can look at." You'll look in public, see if it's in public, if it's not in public, hey, look in here for CSS files. For JavaScript files, we're going to go to node_modules/bootstrap/dist/js. And say, "Hey, there's some JavaScript files in here "that you might look for too." And then we still need jQuery, so we're going to add that one too. I added these three lines of code that basically say, if you're going to slash CSS, if it's in public, great, serve that, if it's not in public, then look in bootstrap dist CSS. For JavaScript, you've got two places to go look. We can go look in jQuery, we can go look in bootstrap. Now, I'm going to save this, restart our server, go back to network so you can see it. We'll clear this. And look, everything still works. Bootstrap, jQuery, everything's still coming. But now it's being served out of our node modules directory instead of having to copy things into our CSS directory. So, we don't want that, we just want to pull out of node module. That's how that works. Now, we have static files being served out of our node modules directory, we've got bootstrap working, we're in our index.html, we've got all this stuff going and that's awesome. Before we go too much farther though, let's get some tooling built around what we're doing. Let's summarize real quick and then let's go get some tooling built.
Summary
We've got index.HTML up and running. We've set up express, Express is running, it's working, we're serving a slash HTML and we've also spent some time logging, we've got debug set up, we've got Morgan going, we've got chalk to make our messages pop out a little bit more. Serving our HTML file, our HTML file doesn't do much yet. It just says, we are bootstrapping, and that's it. We've got our static files served, bootstrap, jQuery, coming directly from node modules. We looked at CDNs, we looked at copying things over to our static files. And now we're serving them directly out of node module, so, we still have some NPM ability to update things as needed. That's what we've got and let's now, take a break for a second and let's go work on some tooling. There's a couple of things going on right now that I don't like. One is, every time we make a change to our Express files, we've got to restart our server, I'd like to do that automatically. We're hard coding some things, we don't have anything in our environment variables. I'd like to put some stuff in environment. I'd like to be linting our code, so, let's take a break from building out the website and go spend a module working on tooling so we can get our environment working the way we want it.
Setting up Tooling
Introduction
Alright, before we go any farther let's take a minute to wrap some tooling around our application. And the reason we're going to do this is it's make our lives a lot easier with some of the things we want to do. So the first thing we're going to do is talk about NPM start. Right now, in order to run our application with the debug stuff enabled, we type debug equals something, whatever we want to put there. And then you've got to type node app.js and if somebody goes and pulls our application down from GitHub or we share it with somebody else, they've got to know all this and from time to time, we'll forget, and we'll have to go look it up. What we do to get around that is we use NPM start and that's going to just be the entry point for our application. I'll show you how to set that up and get that going. We're going to talk a little bit about ESLint, static code analysis, and it's going to make sure we're doing the right things, we're following some best practices, we're getting things done the way we want to get them done. As part of that, ESLint's going to make sure we're using ES6. The beauty of Node versus a browser JavaScript is that we have full control over what we can use. We don't have to use Babel to transpile, we can just use ES6 and beyond, ES2017, ES2018, whatever Node supports and so we'll start looking at that and converting our application to use ES6. We're going to use Nodemon to run our application instead of just typing Node and the reason we're going to use Nodemon, is it support auto restarts, as you change code, it's automatically going to restart. No more stopping and starting and it supports environmental variables. Right now we're typing debug equals and that's one environmental variable but we're also going to support things like ports, and database configurations, and all that in the environment and Nodemon's going to help make that happen. So let's get started, let's talk about NPM start.
NPM Scripts
Alright, so let's take a look real quick on how to set up some NPM scripts and how to start our application in maybe an easier way. So if we come back into Visual Studio Code here, we've got our application open, we've got out app.js, and to run this we open up our terminal window and we can open up an external window but I want to do it here just so you can see what's going on. So the way you open this, if I do control tilde, no matter what platform you're on, it's control tilde, I get this window down here and I can slide it up so we can see what's going on. The benefit of using this window is when I hit control tilde, I get a terminal prompt at the exact directory location that I need it at. So that's a huge benefit for us. You don't have to cd into anything, it just kind of works and so when I do this, to run my application, I'm supposed to type node app.js and I run that and now my application's running. Now remember I don't get any output because, so control c to kill that, we were looking at debug. So I've got to do debug equals star node app.js. Now remember if you're running on Windows, we're going to do set debug star and then an ampersand there. That's the only difference, so just remember if you're on Windows, you need this ampersand and that set every time that I type this. Okay, so I run this, now I get everything. I get this huge output and realistically, like we said before, we don't want all of it, right? So I'll control c, I want app. Or I want, you know, whatever we want. I'm going to run that, so the problem with this scenario is that it's painful for a person who's got to come along behind you or even you, like two days later, to remember what it was you wanted run when you run. So what specifically you want to type and so what we want to do is set up a scenario where you don't have to worry about it and when somebody else goes and downloads your code, they don't have to worry about it. They just enter the same command every time and that brings us to scripts. So if we go to your package dot json file, I'm going to close this window. You see right here we have a scripts section and what the scripts section right now has in it is test. So I pop this back open, control tilde, and I do npm test and I run that, you see right here it says error colon no test specified and where that comes from, if you look up above, test is going to echo out error no test specified and then exit with a one, which is an error condition. So that's how that works and there's two built in. There's test, I can just run npm test, or I can even run npm t for those of us who are lazy, or I can come up here and we have start. Now notice Visual Studio Code is kind of awesome and this is why I like it. We're not going to talk about all of these but here's a whole bunch of other ones that people tend to use. We'll talk about the pre stuff here in just a minute but I'm going to do start and when we start, we want to run to debug equals app node app.js. Now if this isn't working for you on Windows, remember ampersand and set, don't forget about that. That's the last time I'm going to remind you, though, 'cause now you know. This is working, I save it, I come down here, I do npm start and it's going to start my application for me. Back over to app,js, you see listening on port 3,000, listening on port 3,000. That's the npm scripts, that's their purpose because now when you go pull this application down, you just type npm start, nine times out of 10, whenever you download something off of GitHub or you go pull a project somewhere, you type two things, npm install and then npm start and you're running, so that's start, that gets us going, we now have a running thing. Let's talk about adding some more things to this list of scripts so that we start having a more robust application. So we're going to start by the conversation of ESLint.
ESLint
Alright, so let's start with ESLint installation and this is going to be broken up into a couple of clips because it can get kind of complicated. We're going to talk about a lot of stuff so kind of let's work our way through piecemeal as we go. The first thing I want to talk about, though, is what ESLint even is. ESLint is static code analysis. So ESLint dot org is the location for this and there's a couple of different static code analysis tools, some linting tools, I'm not going to even talk about the other ones. ESLint has emerged as the de facto standard for JavaScript linting and mostly because it's incredibly powerful and it's very, very versatile. You can configure it in a lot of different ways and so if you want to read more about it, you can come over here to ESLint dot org and read all of the stuff around it. If you click on get started, there's a full course on Pluralsight about ESLint. Don't go watch it now but when you're done with this course, if you want to dig in more to ESLint, there is a course on Pluralsight about ESLint. Now I'm going to ignore their installation instructions for a minute, I'm going to install it a little differently 'cause I want to teach you a couple features about how NPM works. So ignore their instructions and we're going to pop back over to our code. So if we come down into our code and we come down here into our terminal window, in order to install ESLint, we're going to install it globally and so we're going to use a minus g tag and what this minus g tag does is allows us to execute it from the command line. So we'll do ESLint. We're going to talk about all the reasons why we don't want to install something globally here in just a minute but first and foremost, I want to keep this very focused. Alright, so now that ESLint is installed globally, I can type eslint minus minus init and ESLint is very powerful because it's very configurable. You've got a hundred different options. The problem with ESLint is it's very configurable and you have a hundred different options and so we've got to kind of strike a balance there and so when I type eslint init, it's going to start asking me some questions or I can answer questions about the type of stuff I want to do, I can use a style guide, I can inspect your JavaScript files and it'll figure it out for us. That's great but we're not to a point yet where we have potentially very strong opinions about how our code's to be, so what I want to do is I want to use a popular style guide and we're going to use Airbnb, so let's stop right here for just a second and let's talk about what that means and the types of things it's going to look for.
AirBNB Style Guide
So we're going to use Airbnb's style guide and Airbnb's style guide is pretty straightforward. It seems to be the right thing, it's very pragmatic and so let's take just a minute and go out and look at the types of things they're looking at so that you can understand what this ESLint thing's all about. So if you come out to Airbnb slash javascript dot github, it shows you their style guide and it's just a massive long list here, I just kind of, it's a massive long list of all of the things that they're looking for and I'm going to give you two examples that are going to apply directly to us. So if I click on types here, it's going to take us down to types and if you don't understand types in JavaScript quite yet, I've got another course out there that will walk you through some of those oddities about JavaScript but for right now, you can see that, hey, we want to use const for all of our references to avoid using var, that's an esx thing, I'll talk about that in a minute. You know, literal syntax and it's just a ton and it explains every single one of them. If I go to arrow functions, when you use anonymous functions, we want arrow functions, and I'll talk about that in just a minute but it explains why and this is why I like Airbnb's style guide. There is detailed explanations of everything that they're doing so it explains explicitly why we want to do the things we do and so that's why I prefer Airbnb's. So if you can read through this, don't read through it too much now, we'll kind of pick and choose some things but I'm going to close this and we're going to hit airbnb. We do not use react, we want it in JavaScript format, it's going to go and install everything for us. So we don't have to worry about installing other packages or anything like that. 'Cause now if I go to package dot json, I had edited it without saving it. We don't want to overwrite was just happened. Here eslint configure bnb, eslint plugin import. So those are there and it's working. Now let's play around with running it a little bit. So we see the types of things that we're going to get ahold of.
Running ESLint
Alright, now that we've got it installed and we've got it configured, basic configuration, let's run it and see how that works. So the easiest and simplest way to run this is just to type in our terminal window, and I'll make this bigger, you click on the caret, make it bigger, it's just to type eslint and the file, app.js in our case. Notice how it breaks with this error about not being able to find the package. So let's clear that out and let's talk about one issue that we have with ESLint, now that we have some of these local packages installed. Config airbnb and plugin import, is you can't use the global anymore. We can use the global to run basic ESLint but once we have packages installed, we have to install the packages globally or it can't find them and so that doesn't work for us So what we're going to need to do is run the local version that we just installed a second ago and the way we do that is dot slash, if you're Windows, you know, node_modules and inside a dot bin directory, inside node_modules, is going to be a, so if we come over to node_modules, inside a bin directory, we're going to have this eslint right here and that's what we're going to run, eslint app dot js. Now I'm going to maximize this so you can see it run and when we run it, look, I got a whole ton of stuff. So I got unexpected var, use let or const, we'll talk about that, spacing issues, all of these other things. But before we dig into start fixing these, let's talk about this whole global versus local thing.
Global vs. Local
So what ESLint has done is exposed an issue that we have just in general with global installations of NPM so let's take just a second and talk about what that means. So if we come back over here, I opened back up our little window. In order to run ESLint, when I type eslint, if I look at the version of this, I have version 4.10. Now if I start a new project and I want to use a newer version of ESLint, or maybe a project that's out there that I'm working on has an older version of ESLint, I'm stuck with 4.10, I can't change that because it's globally installed and so that's one of the downsides of globally installing it. It is possible to run it locally, right? We did dot slash node_modules dot bin eslint minus v, we can run it that way but that's painful, right? I mean, that kind of stinks. So we don't really like that idea either. So that's where scripts can come in handy and to prove my point, I'm actually just going to uninstall because we don't want to do this ever. So I'm just going to run an npm uninstall minus g eslint. Now it's gone, so if I run my eslint minus v, I get no such file in directory, alright. So let's kill this, if I come back over to my package dot json, I come up to my scripts, I can actually, right here, create a new script and I showed you the list and this isn't going to be in the list of standard stuff. We're going to create our own thing, called lint and what lint's going to do is it's going to run eslint app dot js and when you think about it, this makes sense that if I installed this on a production server somewhere or a CI server somewhere, I don't want my CI server to have to install things globally like that just doesn't even make sense. Hey, you know, Heroku, in order to run my app, you've got to globally install stuff. So what npm does with scripts, is it assumes a local version. So when I run npm run, now anything's that not test or start, test and start are unique, if it's something other than test or start you actually have to type run, npm run, hey npm run, this script called lint and it's going to look at my local node_modules and it's going to see what's installed locally and then use that version to run. Okay, now you see everything has run and we're working, npm run lint, that gets it going and now we need to start fixing stuff and you look at, though, the first section, expected var let's use let or const, Let's talk about ES6 for just a second because several of these are ES6 and so I want to give you just a brief little ES6 thing and then we'll talk about moving everything to ES6.
ES6
Now with Node comes the availability of the latest JavaScript features. So right now I'm talking about ES6 but even at the time of recording this, we've got 2017, 2018, we've got all kinds of new, cool features available to us in JavaScript. So if you run out to nodes dot green, this website is built so that you know which version of Node things are available in and so if you go all the way back to 6.4, if you're using six four, then most of the, at least the ES2015 or ES6 features are available, which would be things like for of loops and template literals and the let. Those types of things. Here's const and let and the cool thing about this is that if you, first of all, basic const is supported all the way back to 10.4, right? But if you hover over it, over this little question mark, you get a little popup that shows you what that means and if we come down to so is block scoped, you can get an idea of what it means for const to be block scoped and as you scroll down there's arrow functions. Const, let, and arrow functions are the three we're really going to focus on right now. I'm not going to dig into what they mean, just know that they are available to you. If you need to understand more about ES6 in general, there's a lot of courses, there's actually quite a few courses on Pluralsight out in the wild already, I have one that's more specific to Node so you can go watch that at some point if you need to understand a lot of the features. I'm just going to start using them because that's the right thing for us to do at this point. If you scroll all the way to the bottom, I'm just going to scroll all the way to the bottom, you start to see things that are coming, and you see there's a whole lot of errors they're not available yet. But here's 2018, template literal revisions or you come up here to the next section. Node ES2017, notice it started becoming available async functions in 7.10. If you scroll kind of up to the top, you can see 7.10 is where async functions and well I'll show you async functions here in just a little while, after a couple of modules, we'll start to do some things with async await because that makes your code a lot easier to read. You'll notice this has Node 9.0. At the time of recording it was on nightly builds and by the time you're watching this, it's probably out and released so you can, you might be using nine. So you may have some options that we don't have other places. There's nothing really there so shared memory and atomics, that's not really going to matter for you right now but for this course anything 6.4 and above, with the exception of the async awaits stuff, you'll be fine, alright, let's close that and go back to our code. So if we go to app.js, you'll see we've got all these vars here and you'll see down here, hey, we want let or const, we don't use var anymore and I'll tell you what that means, we just want the let or const to be our new default normal. If you use var, that's fine, they don't care, whatever you want to do but ESLint's going to say, "Hey, use let or const." And then down here we have our arrow functions. One thing I want to point out. Notice I have red squiggly underlines for errors and I have green squiggly underlines for warnings and the reason I have those, is I have a plugin and you might consider getting this plugin, called ESLint. I just, you know, click on this icon right there, type eslint, click install, so you get a little green install, just click install and it just works, it works with whatever your eslintrc.js file is, so it just works magically. I would spend just a second, get that installed, so it's a little bit easier for you to read. There's a lot of stuff to change here and I'm going to show you a couple ways to change these things because Visual Studio Code has some cool little built-ins. So let me walk you through a couple of ways to change blocks of code or get a whole bunch of things changed at one time.
Refactoring Tips in VS Code
While we have the opportunity to do so, I want to talk you through just a couple of tips on VS Code and some things that you can do to make your refactoring experience a little bit easier and better. Just a couple real quick and so I'll show them to you as we're cleaning up everything that we're doing. Alright, so, you'll notice first, the first thing we want to fix is all these vars. So here I've got a whole bunch of vars, you may want to change your, so this name app, see there's a whole bunch of them, we may want to change var and when I double click on it, notice when I did app, see all the apps lit up. When I double click on var, all the vars light up. If you've got variable names, you might want to change all of the instances of that variable name and that becomes very easy 'cause I can just double click and instead of, you know, normally what you do is control F, you know, search replace, control shift F, to search everywhere, you know, all of that, we don't care about any of that, right? I want to double click and I can do command function F2 and what command function F2, or on Windows control function F2, what that does for you is notice now all of my vars have a cursor in front of them and what I can do now is I can just hit the backspace key and I'm changing them all, all at one time. So anytime I want to change something, all I have to do is double click on it. So if I wanted to change what express was, I can hit command function F2 and I can start changing. So that's an easy one and if I run this again, those are now gone, I don't have those anymore but I do have a lot of formatting kind of stuff. A space is required after kind of things. So let's fix that. If I right click, I can do format document. Just boom, just like that and I'll undo it, so you notice I've got no spaces, things just aren't quite right, I can right click format document and it's going to format and give me extra spacing right here, these spaces here, save that. If I run this again, now you'll see those are kind of cleaned up so once you've typed a whole bunch of stuff, just, you know, right click format document, you're done. You may notice, this down here could potentially change a whole bunch of stuff. So if I've got something like this. I've got a tab here, if I run this, I'm going to get an error that says expecting indentation of two spaces but found one tab. Well if you're a tab or a spaces person, it doesn't really matter, I prefer tab, this is where I tab, I don't want to space twice but some people are all offended about spaces and this particular ESLint package wants two spaces so that's cool, what you can do is you can click on this down here. Indent using spaces and, hey, I'm going to do two. It automatically changes this to be a size of two but it's still a tab, like if I just push back and forth. If I hit the backspace and hit tab now, since I'm tabbing with spaces, it's going to input two spaces for me. So it's going to make all my tabs spaces just by default. So I don't have to worry about it. So I'm going to, now notice, we're down to just a couple left and what this is, is all about arrow functions. So notice right here, unexpected function expression prefer arrow callback. And what prefer arrow callback means is whenever you're doing a callback, if you're doing a function, that's fine, make it a function but whenever you're doing a callback, it would prefer that it be an arrow function and it prefers that for a couple of reasons. One that this keyword binding in arrow works kind of the way you'd expect. Instead of the broken way, broken in air quotes, way that functions do and we'll talk about that later when we have a need for it but for right now we don't but it's just, that's the gotcha and so it just prevents you from ever having to deal with that 'cause there's no negative to using an arrow function. If I have this here, there's no downside to that and also I can just do this. I can get rid of everything, get rid of my curlies because I don't have to return anything. Now it just works but I'm going to pull this all back to like this because I want to show you one other thing. 'Cause I've got two of 'em here, I missing a semicolon here, there's all kinds of weird stuff broken. I can come down into this window and I can type dot slash node_modules dot bin eslint and the reason why I'm doing this is because I don't want to change my npm scripts to do this. I'm just going to run it and you'll notice right here it says four errors, zero warnings, potentially fixable with the dash dash fix option. ESLint, once you become comfortable with it and you know what it's looking for and you know what it's going to do, you can run it, so app.js with the dash dash fix and when I run this, notice, look at lines 15 and 19, when I run this, it changes them, it converted them to arrow functions, it also added a semicolon right there. That is essentially magic, really. Just, hey, here's some problems but guess what, I'm going to fix them for ya and now everything's going to work. So now, now that that's done, I'll run my npm run lint. Boom, everything works. Now that may all seem fairly routine, right? So it complained about spaces and it didn't complain about const versus var and all those things and that seems fairly mundane, right? It's not really doing us a whole lot of good yet. Although, that's important things. The type of stuff that it is going to do for you, though, that I want to make sure we talk about is notice where const chalk equals require chalk. If I come into package dot json and remove the reference to chalk, basically what that means is moving forward, if somebody pulls down this code and does an npm install, it's not going to install chalk. It's going to work for you, but it's not working anywhere else. Well, now you'll notice, I've got a red squiggly underneath require chalk and ESLint is saying, "Hey, you're using something that doesn't exist." And that's important and that's going to protect you from potential problems. It's going to work on my machine because I have chalk installed already before I removed that package. So that's one thing that it's going to do for you. Another thing it does for you, there's a bunch, but right here, notice I do path dot join dirname and public, what a lot of people do, and I'll see this every once in awhile, is they'll do that, that should work but sometimes, right? And not on all platforms and so now I get an underscore, squiggly, that says, "Hey, no path concat. "You can't do that or you shouldn't do that here." It's just going to prevent you from making some mistakes that you might make otherwise. Alright, let's round this module out with some examples on how to restart your application automatically and then maybe pull in some environmental variables as well.
Setting up Nodemon
So the last tool we're going to set up before we really start going on our application is Nodemon and the reason we need Nodemon, if we look at the website real quick, is Nodemon reloads your application automatically. It's a simple utility that's going to monitor your application and when you make code changes, it's going to automatically restart your server for you and it's just an easy way to not have to remember to stop and restart every time you change something. So what we're going to do, notice it says the first thing npm install minus g nodemon and I have a fundamental dislike, as we've said already, of doing a minus g install so we're going to just do an npm install. So we're going to pull up our terminal window here and just a reminder I did that with control tilde or you can go to view, integrated terminal right here and that'll open it or close it. Okay, so what we're going to do is an npm install nodemon and that's going to get Nodemon installed and set up for us and I'll pull this back down while that goes and we're going to change our start script to be nodemon. The next thing we need to do is set it up and we can do to the documentation. I'm not going to walk you through all the documentation but I'm just going to give you a basic idea. Notice it's nodemon your app and we can config by using some basic configuration in our package dot json, so check this out right here. We like that. Okay, so what we're going to do is come into our package dot json. Notice we now have nodemon down here. Add a comma and we are going to type our nodemonConfig right here and what that's going to do for us is just tell Nodemon how things are going to work and we're going to keep this simple. We can make this a lot more complicated later if we wanted to but right now I just want to keep it simple. So there's a couple things we need to put in here. The first one is restartable and here we just say, hey, if I to hit rs, it's going to restart automatically. I'm also going to say, hey, we need some ignore options. Now if we come up here, if I change app.js or anything in our source directories, I want it to restart but, you know, if we do an npm update or we do an npmsr or anything changes in node_modules or things like that, I don't really care about that. So ignore is going to take an array of things we don't care about and so we're going to add node_modules to that. If I make a lot of changes really fast, I don't want it to restart every time a file changes. So we're going to set up a delay of 2,500 milliseconds or about two and a half seconds and we're going to save that. Now we changed right up here, our start to be nodemon app.js. Now if you're kind of just jumping in here, remember if you're on Windows, you'll need a set right there and an ampersand, I'll probably remind ya again even though I'm going to say I'm not going to remind you again, but get that debug app nodemon app.js right there. So let's come down here and do an npm start. We'll hit enter, now notice, we now have nodemon running. To watch, to restart anytime, type rs. Guess what, I'm going to type rs. There we go, we restart. I also can come into here into app.js and if I just change my on to at, just something simple, I can save that and see after a little pause, it restarts. Two and a half seconds, there we go. Alright, so there's nodemon set up. That's just going to keep us going so we don't have to stop and start all the time. Nodemon also provides one other excellent thing for us. Notice I have app dot listen 3,000. I have hardcoded my port, which is not something we want to do and I want to be able to pass in to the application from my process, from my environment, what ports I want to use. Nodemon lets me do that and all I have to do is come back over to my package dot json file, we'll minimize this, come back over here and add an environment. So notice I have port 4,000 now. NODE_ENV development, so I can set my node environment, I can set my port, I can set whatever I want in here and we'll add some things into this later, like database locations and things like that. So we're going to save that, come into my app.js. Now up here at the top, let's do this. Let's just pull our port in, so I'm going to say const port equals and I'm want to pull in my process environmental variables and we're going to actually call that process dot env and this where, basically process dot env is just going to be an object, it's a big object of all the things that I've passed in. So what did we pass in? Port 4,000, so I'm going to do dot port, so port is now going to be either process dot env dot port or what if that's not set? What if something's broken? Or 3,000, now I get my red underline because port's assigned a value but it's never used so this eslint telling us that we're doing something. So now it's used that so I'm going to come down here and I'm going to say port and port. I'm going to save it, now notice it's still listening on port 3,000. Well the reason for that is I added this stuff in here but Nodemon doesn't know that 'cause it hasn't read its config. So in this case, even though I just teased you with all that, in this case, I still have to restart it. Notice now, I'm listening on port 4,000.
Summary
Alright, we've covered all of our tooling that we needed to get set up and get going in this module. We started with NPM start, just I can write an npm start, our application starts, I don't need to worry about anything else. We talked about ESLint and static code analysis and getting all of that set up and running. ES6, we started using arrow functions and we used string templates and all those types of things to kind of add a modern feel to our application and we'll continue to add more and more of these ES6 and ES2017 and so on syntaxes as we go throughout this course. We set up Nodemon, it's going to monitor our files for us and do restarts and get all that going. We also closed with some environmental variables. All that's set up now, we've got our application running, let's go write some code, let's go get this application going so that we can start making something that's useful to us.
Templating Engines
Introduction
Welcome to our Templating Engines module for building web apps with Node.js in Express and templating engines are the thing we're going to use to build out our HTML, kind of the most important part of a web application is the part you get to see. Now we're working through this course, that's building out a full blown web application, we've got our Express server up, we've got our tooling set up, now let's start actually building out our web application. We're going to start with this conversation with templating engines and templating engines are basically the thing that Express uses to generate our HTML pages, we're not going to write a bunch of HTML and just serve it up statically, like we've been doing up till now, we're actually going to generate our HTML dynamically, so that we can include our, you know, variables and things from the database and all that. Now there's two almost extremes, when it comes to templating engines and I'm going to talk about the two extremes, I'm going to give you an example from each and then you can decide for yourself which one fits better with your style. The first one is Pug, now Pug used to be called Jade and they've changed its name to Pug and Pug is very much a white space driven, minimalist HTML type engine, that allows you to greatly simplify what you're typing and what you're putting in, it just generates a lot of it for you, so that's one extreme and we're going to use that for a couple of clips and I'll show you how that works. The other extreme's going to be EJS and EJS basically just takes HTML and drops tags in it for variables to be plugged in, very similar to how you would do in Angular or React, you know, we're just going to create HTML and drop some tags in there. By the end of this module, we're going to have a real page up and running and so that'll get us pretty far, we're going to use EJS for the full course, but I want to show you Pug, just so you can experience it, but then by the end of this module, we're going to have a full blown, real page up and running, that's going to look the way we want it to look, we'll get some CSS going and all of that and then we'll go from there. So let's take a look at Pug first.
Pug
Alright, we're going to start this journey with Pug and just to give you an example of what this looks like, if we've got a simple HTML site, we've got HTML, we've got our head, we've got our body tags, we've got all of these things and there's a lot of wasted space here with our closing tags and things like that. So what Pug tries to do is simplify all that, it's very white space intensive, so this would be the Pug representation of HTML, so notice I don't have a closing html, so everything that's indented one spot over from the html is inside my html tag and notice my title, MyApp, well, that's indented under head, so it goes inside my head tag and it eliminates the need to have all those closing tags and fix things up that way. Let's take a look at how this looks in practice. So first things first, we come into our app.js and we have to tell Express that we are going to use a templating engine and so here we've got all of our app.uses from before, well let's just come in here and say app.set and what app.set does is allow us to set something on our application instance and in this case, we're going to set our views directory and notice, love the little help, right, it says, "Hey, I've got set and you've got some options," our views directory is going to be source slash views, now we haven't created that yet, but that's where we're going to put all of our views, so let's create that real quick, so I'll come over here, we'll create a new folder called src and inside src, we'll create a new folder called views. Now we have to tell Express what view engine we want to use, so one more app.set, remember there's a couple of different versions and so we're going to use Pug, so we're going to say view engine, we're going to say pug, now all that means is when Express starts to look at what to use, it's going to look for a package called pug and that's not there yet, so let's Control+Tilde to pull up our Terminal window and we're just going to do npm install pug and if we go to our package.json file, once this is done, you'll see Pug. Alright, so let's save that and we're going to right-click under views and create a new file and what it's going to look for is a Pug file, so let's say index.pug, notice Visual Studio puts a little Pug icon next to my file, so that says, "Hey, I know what Pug is," and down here, you see it says Pug, because you are now working in a Pug file, so it'll give you assistance around Pug files. So what we're going to do is just create a very basic, simple HTML Pug application, so we say html, we tab it in, we say head, tab that in, title MyApp, alright, now we're done with our head, so we've got to back up and we say body, inside our body, we're going to have an h1, that just says MyApp and under our h1, we're going to have a p tag and here we're going to have an h3 and there we go, a very, very simple Pug file. Now if I come back to my app.js, if we scroll down, now when we get slash, right now, we're doing a send file on index.html, so instead of doing a send file, let's close this, res., we're going to do a res.render and we're going to render index, now when we do a slash, what res.render's going to do is it's going to say, "Hey, I'm going to render a view called index," it's going to look for where my views are, they're in src/views, it's going to come src/views, it's going to see index.pug and it's going to use that, so let's save that and down here, we'll do our npm start. Alright, now we're up and running, if we flip over, we'll see we have My App and our sub header exactly the way we have it laid out in our Pug and if I change my app here to Library, save that and flip over and refresh, now you see we've got Library. Alright, that gives us the basic Pug usage, but real life doesn't mirror basic ever, so let's take a few minutes and let's dig into how to use Javascript and loop over things and pass variables in, into our Pug template, so that we know how to use more of a real world scenario.
Pug and Javascript
One of the advantages of using a templating engine is we can pull some of our looping logic and some other things out into the template itself, instead of having to render all of that dynamically inside our page, so let's kind of talk about what this looks like in embedding Javascript into our Pug template. So here we've got our HTML page, just like we've always had, now notice now I've got a class, class="MyClass" and the way we would do that in Pug is we start to think about things a little differently, in Pug everything kind of resembles a function and if I want to add things to some of my header items, I just execute it like it's a function, so in this case, notice I have body and I set class equal to MyClass and notice it takes an array, so that allows me to pass multiple things in, if I want to and this idea kind of carries throughout, so let's talk for just a little bit about what it means to have everything be a function and how we work with this and then we'll loop over some things as well, just so you can kind of get an idea of what's going on. Alright, so we're back over here in our index.pug file and I'm going to minimize this just to keep things simple, we're going to go back and forth between index and app and I want you to notice this, so like we said, if body has a class that equals just MyApp, let's just say that and then down here, I have my h1 and sometimes you want to pass in like an id, so in this case, you'd say id, instead of class, now typically something only has one id, not multiple, so this just takes a string, we say MyId and actually let's just call this MyClass, so if I save this, notice my Node doesn't restart, because it doesn't need to restart for the template files. When I refresh and I inspect, now you can see my body has a class of MyClass and my h1 has an id of MyId, it's just that straightforward and that's kind of how that works, but now I want to start passing in some things and so let's talk about how to do that, because maybe I want my title to come in or maybe I want my header to have some line items, now let's talk about how that works and we need to pass things on render, so if we scroll down, here we do res.render index, we can pass things in and the way that works is we're just going to pass in an object and notice right here in Visual Studio, it says render, view:string and then options is an object, so you just pass in an object full of options and so what we're going to pass in is, let's just call it title: MyLibrary, we'll wrap that in tick marks, we'll format our document, because that way I'll get rid of my red underscores, we'll save and now that will refresh, there we go. Now in order to use this, I come over to index.pug and right here, I'm going to say equals and then the variable name that we passed in, so in this case, title and what equals means is, "Hey, just spit out whatever that is," and we'll save that and we'll refresh, now you see we have MyLibrary, so this equal sign allows me to spit out a variable, so whatever's on the right side of equals is a variable, so let's undo that, we'll come back over here and let's make this a little bit more complicated. Realistically I might want to pass in something more, like I might want to pass in a list of items, so I'm going to say list and that's going to be an array of a and b, now I can come back over to my index, now think about this, this is like, say we pull something out of a database, you know, just a list of items and most of what we do as web developers is we get an array of stuff from a database and we just loop over it and spit it out to the screen and so that's what we're going to do here, I'm going to, under my p, let's add a list and we're going to say each, now each is a keyword, it's not like a body or a head or something, each is a keyword in Pug, that's now a loop, I'm going to say each val, so each value or each item, each thing in list and what that's going to do now is just basically, it's a for loop and loop's over list and gives me each item and we're going to make that a list item and we want to spit out something here, so we use the equal and we say val, so I'm going to save that, come over here and there you go, now we've got a and b and notice h1 has an id, the body has a class and then here's my list of a and b, so that's the basic answer of how to loop over items in Pug and just kind of injecting this Javascript mentality, so there's for loops and things like that into our Pug template and so that's the basic idea for Pug, that gives you enough to know now whether or not this is something you want to pursue and if it is, that's great, I use it on some projects, that I know a lot of that people do, it's just kind of a do whatever feels right for you in this case. I'm going to stop here with Pug and I'm going to move over to show you the other extreme with EJS.
EJS
Alright, so let's look at the other extreme here with EJS, so let's come over to our app.js file and here we have view engine of pug, let's just change that to view engine ejs, that's really the only change, we'll close our terminal, our running process and let's do an npm install ejs, just like that and that's going to install and now we've switched over to EJS, now, we're not doing EJS yet, because we still have our Pug file in our view as well, instead of pug, we're just going to rename this to index.ejs, now notice everything is broken, so we've got an html, you'll notice this looks just like HTML and that's kind of the point. Inside our head, we're going to leave empty for now, inside our body, we're going to add an h1 tag and I want a title to be displayed here, how about something like Welcome to and then I want my title and so the way we do that in EJS is we use this syntax and this is how we break out of our HTML into our Javascript ability and I just want to display a title, so I'll say %=title and that's how that works, now I don't have a title yet, right and so if you remember in app.js, here I'm rendering index and list, I'm also going to send a title, let's just say, we'll call that Library, we'll save that, now I stopped this, so that I could install EJS and if you look in our package.json file, now you'll see ejs 2.5.7, let's restart, npm start, refresh our page, now you just see Welcome to Library, we also have this extra little thing sticking out there, so we'll fix that, that's 'cause I left one here. Alright, so I have that, but I still have to loop over everything, if you recall, I was looping over the list on my other side, so the way we do that is very similar, I'm going to do my ul, but now I'm going to break out to my Javascript again, now, when I put equals, it's just going to display a value, if I don't put an equals, it's going to do whatever I want to do, whatever Javascript I put in here, so here I can just do my old school for loop and we just open it and then I hit Enter, now I'm out of my Javascript, I can just put whatever I want to right here and so I'll put my li tag in, but then we have to remember to close our for loop down here at the bottom. So everywhere I put this less than percent, it breaks me out of Javascript and it just kind of builds it as we go and so I can do that over multiple lines with no issue. In here, I want to spit out whatever list, list.sub i is, so we're back to our equal syntax and we'll save that. If I refresh, now you see I've got my a and b and my Welcome to Library, it all just kind of works. So this is the basics of EJS, this is just how it works, now notice down here at the bottom, I don't have an EJS option, so I can install EJS support, I'm going to install that, I'm going to reload and now I have EJS support. So Pug came installed, EJS we had to install an extra extension for, but now that it's there, notice my highlighting's a little bit better. Alright, I've got my EJS, we talked about Pug, I'm going to use EJS here on out and part of the reason for that is it's a little bit easier, since we're not learning templating engines, we're learning Node and Express, I want to keep the learning path as simple as possible, so EJS is just HTML, it's a little bit easier to follow and get along with, so I'm going to stick with EJS for now, if you want to look at Pug for your application, that's great, but for right now, let's just move forward with EJS. Now let's get an application going, we've got all the pieces, now we need to get things going, so let's talk about pulling in a template to get everything going and then build out this application.
Templates
Now usually when I start a new project, I don't like to start from scratch, right, I don't like to just pull up a blank, empty page, 'cause I don't have the patience or the inclination to build out my own stuff, so I like to usually start with a template and I'll go out to Bootstrap Zero or something similar and pull down a free template, so we're going to come to our search here and search for storystrap, this is the one I prefer to use for this particular project and if you get a preview, they may ask you to follow 'em on Twitter or something, depending, they change their rules every once in a while, but if I click Preview, this is what our page is going to look like, it looks kind of cool, we can have our list of books right down here with a cover photo and it just kind of works, so I'm going to download this template and there it is right there, now let's go about the work of getting this thing installed in our application. Alright, so here what we've got is on the left, we have our template that we've just downloaded, you'll see we've got some CSS and index.html and some Javascript, over on the right side, we've got our project directory, app.js, node modules, all of those things, so what we're going to do is we're just going to take what's on the left, copy it over to the right, so in public, we have a css directory, that's empty right now, we're going to take styles, we're just going to copy it in there, now notice we also have bootstrap, but we don't need bootstrap, because we installed that with npm, so we're going to ignore that one, in our source views, we have our index.ejs, we're just going to copy over our index.html and we're actually going to delete index.ejs and we're going to rename index.html, index.ejs, that's it, that's all there was to it, let's take a look at what that looks like. So if I go to our, fix that, index.ejs file and look, minimize this so you can see everything, there's a whole bunch of stuff in here, notice a couple of things, so bootstrap.min.css from css/, well remember in our app.js file, if we go to /css, which is what we're doing right here, we're going to look not only in public, but we're also going to look in node_modules/bootstrap, so it'll find this font-awesome coming from a cdn, so that's cool, we can just leave that where it is and css/styles.css, so it'll find that, we've got a whole bunch of other stuff here, that I'm going to ignore for right now and then down at the bottom, we go all the way to the bottom, it's actually pulling jquery from a cdn and that's fine, we're going to leave that and then it's pulling Javascript from our js directory, which /js is actually looking in bootstrap. Alright, so if we save all that, we come over to our browser and we refresh, notice our Storystrap's up and running. Now, I don't want it to be called Storystrap, I want it to be called Library, because that's what it is, so let's go back to our index.ejs and we're going to come up here to the top, where it says Storystrap Template, we're going to do our %= thing and we're going to pull title and then down, we'll close, there's our navigation, our categories, we're going to come all the way down here to line 61, which says Storystrap, same thing, refresh, Library, there we go. Alright, we've got a good starting point, we've got something that looks kind of nice, we've got a full blown HTML page here, let's now build some functionality, let's actually start making our Express application work.
Summary
We are slowly but surely making progress in building a web application with Node and Express, we finally have something that looks like a real web page and it's only taken us four modules to get there, but in this module, we talked templating engines and this is the thing that Express uses to throw some HTML out to the browser. We started by using Pug and Pug, or Jade is the other name it used to be known by is a minimalist kind of looking template, that pulls put all of the extras and it builds HTML for you. Now we talked about EJS, which is the other extreme, which is just HTML with some tags thrown in, we're going to use EJS for the rest of this course, just because I think it's slightly easier for everybody to wrap their heads around, while we're talking about all the complications on the backend and building up our Express web server as we go. We built our first real page, we pulled a template down from Bootstrap Zero, we plugged it in, we added some EJS tags and now we've got a real page up and running, now let's actually start building out our whole application using some routing, we'll pull some databases in, we'll do all of that stuff and we'll get a real application going.
Routing
Introduction
So we're working our way through building out a web application and in this module we're going to start talking about routing and we're going to build out some routes for our application. Now we've come pretty far in our journey to build out a web application. We've got some tooling set up, we've got basics of a webpage showing, we imported a template that gave us a nice looking webpage to get started with and in this module we're going to start building out routes, we're going to have a book route, we'll have a single book route. We'll kind of work through all that. Now we're going to be generating some code as we do that and so we're going to start talking about how to separate out our files. Right now everything's in one file, in app.js, and we're going to talk about how to pull that apart so we have multiple files. We're going to add some parameter variables to our search, like when we build out a single book, I want to pass a book ID, so how do we do that in our routes? And we're also going to talk about router functions. We're going to create our router but we're going to do it as a function so we can pass things in on the creation so we can create different things, or pass config variables in and things like that. So let's get started in building out our routes.
Navigation
Alright, the first thing we're going to do as we build out our web application, is build navigation and this serves a couple purposes. One is it sets the framework for the pages we're going to build but two, it gives me an easy way to show you how to loop over things in a real scenario. So we're going to create a navigation object, we're going to pass it to an ejs page, and then we're going to loop over it to build our navigation. So let's look at what this will look like in practice. Let's look at index dot ejs. Here we've got four categories and here you'll see across the top of our page, we have the four categories. So let's build this out to where we're looping over something to build out this navigation. So if we come into app.js, here we've got our res dot render and I'm going to, first of all, let's format this a little bit because we're going to blow this out. Alright, as I format this up, now I can say, hey, instead of list, where we have list a and b, we set that up in the last module just to loop over something basic, let's call that nav and here we're going to have books and authors. Let's save that, now you'll notice I've got a little red underscore here, it says I'm missing a trailing comma, comma dash dangle. Let's fix that just really quick. That's something we did not do earlier. If we come into our eslintrc.js, we're going to come right here, got a comma, and we're going to add a rules, that's just an array of rules that we want to ignore or not ignore or whatever and in our index, in our app.js, it's called comma dash dangle. It basically, eslint's just one missed, add a little comma there and that's kind of silly and I don't like that, so. Comma dash dangle, we'll make it a zero. We'll save that, zero means it's ignored. Now notice how it went away. If I change it two, that means error and it freaks out about it. If I change it to one, that means it's a warning and so it gives me a little green underline. I understand kind of why they want it but I don't like so we're getting rid of it. Okay, so I've got books and authors in my nav. We're going to save that, we've cleaned up our ESLint, all that stuff's good. When I come back to my index.ejs, we're going to delete our other categories 'cause I don't need 'em, we're going to loop over them and right here, line 30, we're going to set up our for loop and then down here, you have to remember to close it. And instead of category, remember we put equals to say, hey, I'm just printing out a value here, I'm not writing any JavaScript, I'm just printing a value. So we're going to do navs sub i. We're going to save that, flip back over, refresh our page, and now you'll see we've got books and authors. But, really, I want the text here but here I need a navigation link as well so let's come back over to app.js. I'm just passing an array of strings into nav. What if instead, I pass an object? And I said link and title and here we're going to say link and title. Close our object and open a new object. Format it to give our spacing appropriately. There we go, now every time I loop over, I pull the first thing out of nav, I'm going to get an object that's a link and a title so here we need to say nav sub i dot title and right here in our href, nav sub i dot link and we'll save that. Now if we refresh our page, I hover over books, see down at the bottom it says slash books? Authors says slash authors. I don't have any linked to those yet but we'll build that next.
Routing
Alright, so we have in place some anchor text and some links that we want to go to. So if you're following along, you see we've got our books and our authors and those both go to local host 4,000 books, local host 4,000 authors and we now need to implement this, book route, and the way we're going to do that, there's a couple ways. So the first thing we can do is we can come down here to our app dot get and we can actually do app dot get slash books and just implement that right there and that works, that totally works, you can totally do that but that gets clogged very quickly and you end up with all this stuff in there so we're going to use this thing called a router. Basically what a router is is it allows you to encapsulate all of your routes in one spot. Let's go down below app and port and we'll just say const bookRouter equals express dot router and we're going to execute that and what that's going to give us is a thing that we can use to encapsulate all of our routes and obviously we need to spell express correctly and this is where ESLint comes in handy, right? I mean, there it goes, it tells me, "Hey, that thing doesn't exist." So express bookRouter has a problem because it is not used yet and we know it's not used yet so we're going to come down here right after this app dot get. We're going to come down here, actually let's do it up above because we're going to pull this out a little bit later. We're going to say bookRouter dot route and what this does is it allows us to set up a series of routes to associate with bookRouter and in this case, we're going to say slash books because that's the route we want and so everything that goes to slash books is going to use this bookRouter and then here we can do dot get, we do dot post, we can do all of those same things that we've got down here off of app. Okay, so let's implement our dot get and for the most part, most of our pages are going to be gets, we're going to have a few posts but most of the time, we're going to do gets and we're going to do this the same way we did our get down below, we're going to send in an arrow function and we're going to send in req and res. We'll format real quick, clear it up. Okay, inside here we're going to say, what do we do, let's do a res dot send, we'll just send back hello books and we'll be done. Now what this does for us is now it encapsulates this book route so when you go to slash books get, you're going to get a send of hello books. Now the next piece in this is to let the app know that we're using this router and so, see up here where we've got all these app dot use statements? It's the same thing so we're going to do app dot use, we're going to say, hey, for slash we're going to use bookRouter. Let's save that and then down at the bottom, we see it flip over, so we'll alt tab, refresh. Hey, we got our hello books. So that works and that's great but there's a couple different things we can do here and do to help fix this up. This is a little confusing because looking at this app dot use slash bookRouter, we don't know what routes are being maintained in bookRouter so what you can do is actually you can say, hey, anything that's slash books is going to be bookRouter and if you go to the root of bookRouter, then you're going to get hello books. If you go bookRouter dot route slash single, we just copy this dot get and stick it back here and say hello single book and we'll use this maybe when we do, when we look for just one book, so we'll change this to by ID a little bit later on. We'll save that and now when I go to slash books, that works, if I go to slash books slash single, I get my single book. This is encapsulating everything into a single router in a single place so that's great and then we've got our route set up but what that doesn't give us is something meaningful so let's add some pages that we can render so that if you're, if you go to slash books, you actually get a list of books or let's start rendering different pages in different places.
Rendering
We've got our book router routing things appropriately but we don't have yet are additional pages and realistically when we go to books, we want it to look very similar to this 'cause really this is going to be our list of books. Eventually this page will become something different and we want books to look like this page. So let's make that happen. The first thing we're going to do is we'll slide this back over, is we're going to go into our views directory and we know it's views because up here on line 17, we did app dot set views dot source views. So that's where we're going. So index dot ejs is what we have. So we're going to create a new file called books dot ejs and realistically because we want the same thing, we're just going to copy this entire file, just copy it into books dot ejs and we'll save that and then in our app.js, minimize this again so we have more space, right here where we go bookRouter slash route, right now we're doing a res dot send, instead we're going to do a res dot render and we're going to render books and we're going to save that. Now when we save it, you'll see we restarted down here at the bottom. So we'll come back over here, we'll refresh this page and now we have an error, and we have an error, if you'll look at line number six, title is not defined, if you recall, we were sending in all this stuff on our res dot render. We were sending in our nav and our title down here. So let's copy that, come back up here to where we render books, paste that in. Do a format so it doesn't yell at us, there we go. Make it look pretty so it doesn't yell at us and then refresh our page and it's there, okay. So now on books, we have a list of books, except we don't have a list of books, right? We've got a list of fake articles that were included as a part of this template. So let's actually add some books and we'll stick those in and let's see how that works. So what we're going to do, is come back over to our code, is let's just create right up here a thing called books and it's going to be just an array of books. Now eventually we'll pull this out of a database but databases are the next module so we're not there yet, let's just hardcode some books and what I'm going to do is I'm just going to paste a whole bunch of stuff and then I'll format it so all my red lines go away and set it to const and there you go, now we've got our book. Const because it's not changing, not var, and so you can type this in or you can type in whatever books you want, it really doesn't matter. For right now we're just going to use title and author. Genre's going to come about later and whether or not we've read it will come about later but for right now, you can copy and paste this, you can pull it out of the course materials, if you pull those down but make sure we have books. Alright, now it's red underscore 'cause we're not using it yet so let's add it. If we come down here to where we're rendering books, right now we're sending in the nav, the title, and then we're going to send in books. Now we used to have to do books books and you'll see ESLint yells at me right away because we don't have to do that. Notice the error says expected property shorthand. We can just do that. So now I'm sending books into my render for books. So if I come over to books dot ejs, and we look for the nav, so if we scroll down to where we do the nav, you'll see we've got this for loop right here where we iterate over our nav. So I'm going to copy that for loop and we're going to scroll down. Let's look back over here. See repurpose content to reach a wider audience? So this is where it says div class equals row, that's where we want to copy that for loop. So let's paste that and close our for loop. Then we're going to copy this row. Let's just copy the whole row and we'll drop it in there. 'Cause this is what we want to loop over. Now if we look back at this, realistically what we want to do is this title, repurposing content to reach a wider audience, is going to be the title of the book. This 97thfloor.com is going to be the author. So let's just change that. Repurpose content to reach a wider audience, is going to be books sub i dot title because in app.js in our books array, that's what we called it, title and author, books and we're sending books in right here. So let's come back over books sub i dot title and I know we haven't changed up on the array yet but we will, hold on. Here where it says 97thfloor.com, we're going to do author. Now we're iterating over books so let's come back up here and change that books. Alright, we'll save that, now all these other rows we want to get rid of, row, row, row, row. Just delete 'em, they're gone. So now we're just going to loop over books. Let's save that, come back over, refresh our page and notice we've got War and Peace, Les Mis, Time Machine, all of our books looped over, just like that. So the next piece of this is come back over here, see this read more right here? Well that read more is actually kind of way over to the side. So let's scroll over, let's move this down to the next line so we can see everything, let's actually implement this to slash books slash the ID and we put the equals sign now because we're going to write out the value and we're just going to say i. Let's save that and refresh our page and now the read more, when you hover over it, notice it says books two or books one. Now we want to build out those single routes and so if we come back over here, here we've got our single route and here's our other route and all this stuff is starting to get a little bit crowded. Our app.js is already over a hundred lines of code and that's too much so as we're building out the single route, let's see how we can pull all this code out and drop it in a different file so that we have a cleaner and easier way to encapsulate all of our code.
Separate Files
Alright, so let's take a look at how to separate out all of our files into individual files for each thing that we do. Alright, so what we're going to do is let's take where we start with const books all the way down to bookRouter dot route single and we're going to just command x that, control x that. We're going to click here and we're going to right click on source, we're going to create a new folder called routes, we have a folder called views and now we have a folder called routes. We're going to create a new file called book routes dot js and we're going to paste all this stuff in here. Now we're going to need a couple of things. So if we come back up to the top, we're going to need express, we're going to need to format our document a little bit, and then if we look over here, we also need our bookRouter equals express dot router. So all of this stuff we've already had, right? So we just bookRouter our book router, book router, all that stuff is there. Now we just have to export it. So we just say module dot exports equals bookRouter and that's it, so all of this stuff, used to be in dot js and we just pulled it out and we don't even need this line anymore 'cause we need bookRouter from this, not from express dot router, so actually what we're going to do is now we're going to say require and now here's an important thing. Notice up here we have all these require statements and we just say path or morgan or debug and when you require them that way, it goes to node_modules. Instead we're going to say dot slash source slash routes slash bookRoutes. Now bookRouter is coming from this other file and so because we have the dot slash source, it's actually going to look in that place. So we'll save that, it's restarted already. There it goes. And there you go, it still works. So all it took was taking that chunk of code, moving it over here, to a new file called book routes, and then requiring it this way and what we're actually going to end up doing, I'll move this line down here, let's move this line down, so we can put them all together, as we have more routes, like we'll have auth routes when we start doing users, we'll have all of our routes lined up right here. Const bookRouter equals require. Const authRouter equals require and then we'll just app use right below it. So now we have two lines of code to pull in everything. That makes our lives quite a bit easier and it's easier to figure out what's going on.
Single Book Route
Alright, so now we're going to set up our route for just the single book. Now if you recall, when you hover over read more here, and we go to it, we get slash one or slash two or whatever the ID is of that book and so what we want to do is back in our book routes, when we get to slash single, we don't it to be slash single, we need it to be the ID of the book that's being passed in and the way that works is we put a colon here and then whatever we want to type. In this case we'll type ID because that's the variable name associated with what it is that's being passed in but what happens is when I do this, Express takes whatever is beyond that last slash and so in this case it's slash one and it sticks it in a variable name called ID but it's not directly in that ID. It's going to put it in req dot params dot id and that's going to be whatever it was that was beyond the slash and so what we're actually going to do is we're just going to say const id equals req dot params dot id and then we're going to take everything that's in this render, just take the whole thing. Here we're not going to render book, we haven't created that yet but we're going to render book and instead of books, we're going to say book sub id. Now, yes, we could have just said req dot params dot id right there but I'd rather pull everything I'm using out up at the top, that just looks a little bit cleaner. We don't need a semicolon on the end there. And then we go from there and this is interesting, notice I have a red underscore and this is one of those ES6 things that's kind of cool. It's saying, "Hey, use object destructuring." We're going to prefer destructuring and so let's do that. So we have this object called req dot params that has an ID on it and this essentially works exactly the same way. So it looks for, because I have these two curly braces, it looks for id inside req dot params and just pulls that out. So it's just a shortcut notation to get what we want. So we'll save that and now we're not going to look at it yet because I don't have book for my rendering yet. So let's go create a book view and go from there.
Rendering a Single Book
Alright, so now we're going to render our single book, we're just going to create a view for that. Let's slide this back out and go to our views directory and let's create a new file called book view dot ejs and let's actually, let's change this, we'll rename this to bookListView dot ejs so we've got our book list view and then just our book view. Let's come into book list view, just copy the whole thing and we'll paste it because for the most part, these are going to be the same thing, we just want a single view and the way that we're going to do that is if we scroll up to our loop right here, we've got our for loop, I'm just going to get rid of the for loop and down at the bottom I'm going to get rid of the close of the floor loop 'cause I'm only going to display one book and then here where we have book sub i dot title, just have book dot title, book dot author, and then we're going to get rid of our read more, we'll actually just get rid of all this. Now I have this book view. If I come up back over to my bookRoutes dot js, here I've got, I'm rendering book, we're going to render bookView and we're passing in book, book id, and then here we're going to do bookListView. Let's save that, it's going to refresh, there we go. Let's come back here. There we go, we're rendering. Let's click read more slash two. Oh, and everything's broken. So let's figure out why that is and the way we're going to do that is we're going to right click and we're going to view inspect and this is going to open up our Chrome console window and if we click on network and I refresh, notice when it goes to load the styles, it's looking for slash books slash css. Well, that's not going to work for us is it? Because what happened, and the reason why this happens, if we go back to our book view dot ejs and we go up to the top where we pull all these things in, let's minimize this, notice we don't have a slash at the front of this, we're going to stick a slash there and basically what a slash means is it's going to back to the route. I'm going to stick a slash here too and then down at the bottom where we're pulling in our JavaScript, I'm going to stick a slash in there too. When you don't have the slash, it looks at the same level so our other page was working, books was working because it was the same level as books. Now it's looking for the same level here. So let's make sure we save that, we saved it. Let's refresh and now it all works. And there we have the Time Machine. So if I go to slash four, we've got The Dark World and we put more information in here typically. If it's, you know, the single book, we'd have more information, not the same information but we're not quite there yet, well get there here in another module or two but for right now we've got it working. If I click back, we have our books pages and I click read more and it takes me to that thing. So we're making some good progress here. What I don't like, there's a couple things I don't like so far and one of them is the fact that we've got this nav here and we're copying and pasting this nav everywhere that we're doing it, so in book routes, we've got nav here and nav here and I want to be able to reuse this and there's a bunch of different ways to handle our nav but I want to show you something that's specific and nav is a convenient way to do it. Let's look at a way to pass this nav into book routes when I create it so that app.js is the only thing that needs to understand what this nav is, so that'll be our next clip.
Router Functions
Alright, so what we're going to do now is we're going to figure out some dynamic ways to implement our router so that we don't have this nav hardcoded everywhere and so if we go to our bookRoutes dot js, see we've got nav here, we've got nav here, it's being reused everywhere and what I really want to do is I'm going to copy this nav, and what I really want to do is right here, I want to say const nav equals this array. Just like that and I want to then take this nav and I want to just pass it in to my require for book routes and remember, like, look up here, when we were debugging, when we were setting up debugging, and require debug and we pass in app so we pass in some configuration data and it uses that information to do what it needs to do. Now we're going to take the same concept down here in our book routes, our book router, and the way we're going to do this is we're going to turn our bookRoutes dot js into a function instead of what it is right now and you can pass in all kinds of stuff. We can pass in configuration information, we can pass in database stuff, you know, whatever we want to do, there's a hundred different things we can do but we got to talk about how to make that happen. So let's save this file, we'll pop over to book routes and let's minimize everything so we got it all on one page. So we want to keep the first two lines the same but then we want to say, we want to create a function called router and we are going to put everything in this file, except for our module dot exports, inside this function and then let's minimize everything again so you can see it all on one screen. Alright, so the only thing we need to change. We've copied everything up in here is right here on the bottom line, it's going to make me expand it before it'll let me do it, is we need to return book router because we're creating book router, now we just need to return book router out of our router and remember this router function takes nav, it takes a parameter in, now we need to use this nav. So if we come down here to bookRouter route slash, here instead of passing this nav in, we can just do that and in our slash id, instead of passing in our nav, we can just do this. And then the last thing we need to do is instead of exporting bookRouter, we need to export router. So let's save that, format our document to get all of our stuff out of the way. Save this whole file, okay, we'll come back over to app.js. Now let's change this just a little bit. So let's change book and let's change authors and we'll see how that looks. So we'll come over here, let's refresh our page and it didn't work and it didn't work because I changed the wrong thing. We want to change it here, alright, let's save that, refresh, and there you go, everything still works. So that's how you pass data in and implement this kind of dynamic setting up of your routes. Just kind of the same way we did up here with debug. Now the one thing that still bugs me that we got to fix right now is this book array. I don't like the hardcodeness of this and so we have reached the part of this course where we're going to go start talking about databases and we're going to start pulling this data out of a database and so that, we start to get pretty far along. Okay, so let's recap real quick and see how far we've come and then let's start implementing a database.
Summary
Now we've made quite a bit of progress in our journey to build out a web application in Node.js. In this module specifically, we started to build out routes and we discovered this router thing that Express has that lets us encapsulate up our routes into one object that then we can pass to app to use. We started separating out our files. We moved our router logic out to separate files so that not everything's all clogged up in app dot js. We started using parameter variables and we talked about how we have params attached to our request that allow us to pull in items from our URL to use and we ended with a conversation on router functions and how instead of returning the router, we can return a function that will return a router based upon some configuration information that gets passed onto us. So that's great, we've made great progress. Now it's time to start hooking things up to a database.
Databases
Introduction
Alright, Now it's time to start talking about databases and how to get and put data into our application from a database. We're going to talk about a couple of different kinds of databases just because one size doesn't always fit all. We're working our way through building out a web application. At this point, we've got a couple of pages, we've got some data flowing through to a template engine. It looks kind of nice. But all the data is hard-coded. Now it's time to hook things up to a database. I know one size doesn't fit all on databases, so we're going to talk about two different types. Kind of like we talked about two different types of templates, we're going to talk about two different types of databases. The first one is going to be SQL Server. I'm intentionally doing SQL Server because it's usually not thought of as being something you connect to from Node. But all of the .NET developers out there who are moving to Node, or all the Microsoft kind of people, I'm going to show you, you can still use SQL Server from a Node application. I'm also going to do the more traditional Node database of MongoDB. So you'll see the difference between the two. Now don't freak out if you are using a Mac. I'm going to talk about SQL Server. In this course, I'm going to set up an Azure database and connect to it that way. I'll show you how to do that as well so that no matter what platform you're on, you can still connect to SQL Server. We're going to talk about the Mongo command line a little bit because that's going to be a little different. If you're used to more of a traditional SQL Server kind of thing, I'm going to show you the command line for Mongo. We're going to insert data. Obviously that's generally a good start. We're going to put data in the database, and we're going to pull data out of the database. Then I'm going to show you a couple of different query types. We're going to implement our find and our findOne. So by the end of this module, we're going to be pulling data out, and we're also going to be doing a search, and we're just going to pull out that one. We're going to do that single book route, so we can pull out just one. All right. Let's get started by setting up a SQL Server instance.
Creating a Database
In order to use a database, first we've got to create a database. Since I said we're going to use Azure for our SQL Server, I'm going to walk you through how to create an Azure database so that you can connect up to a SQL Server instance no matter where you're from. It just makes things a little bit easier that way. If you go to azure.microsoft.com, you'll get this start free screen, or you'll get something similar. If I can click on this, if you create a free account, you can get a $200 credit for 30 days, and that should be more than enough, like ridiculously more than enough for you to create a SQL Server instance out here just to play around a little bit so you can experiment with connecting to SQL Server from a Node application. All right. When you're done with that, run out to portal.azure.com, and that's where you're going to want to end up in order to create your SQL databases. What I've done is I've clicked on SQL databases, and that takes me to this screen. It's just a very simple, easy creation process. I want to create a SQL database. My database name is going to be PSLibrary for Pluralsight library. Now it has to be unique. If it's not unique, just create something else. Your subscription. I've got a Visual Studio Enterprise subscription. You'll have your free subscription that you created, or you'll have a subscription somehow, so just pick your subscription. We're going to create a new resource group called Library. We're going to create a blank database. Now we've got to set up a server. We're going to create a new server called PSLibrary. I'm going to create just a simple library, Library. Now it doesn't like that because it's not long enough. Look at this, and you'll see there is some restrictions on passwords. Uppercase letters, lowercase letters, numbers, not enough numeric characters. It's got to contain three of those. I'm going to just create a password. You can find out what it is later. But keep in mind, don't use mine 'cause this will go away. Create your own. Put in whatever logins and passwords you want, and put your location. I am not in Western Europe, I am in the Eastern United States, so that's what I'm going to go with. I'm going to select that. All right. Our pricing tier starts as standard. You can really pick whatever you want. You got basic, standard, premium. You can, in each, adjust what is required, what's not required, what you want. In basic, storage is very small, but that may work out best for you. It's cheap, but if you're on the free tier, you can do what you want with it, and then we're going to apply this, and go with that. I'm going to create. All right. Now my database is being created. It's going. It'll show up here in just a minute. Now I can start connecting to it from my Node database. If you wait long enough, you eventually get this, deployment succeeded. We're going to click go to resource. Here I have my database. Notice we've got nothing in it. We've got SQL Server. Nothing there. In order to do anything, we need a table. We're going to come in here. We're going to log in with the credentials that we had. Now notice I've got no tables. I'm going to to create a new query. I'll slide this over a little bit. I've got a query going here. We're just going to create a table in our query. We're going to create a table called Books. Let's see. We need title. Varchar 255. And we need author. Same thing, varchar 255. What that's going to give us is just the two columns in this table. We're going to execute this query by clicking run. Query succeeded. If I click this refresh right here, now I have a Books table with title and author. Now that only gets us so far. We've got to insert some data into this table. Let's do that, and then we'll be ready to go. I'll slide this back over. Here I've got my insert. I just went ahead and did it. You can copy it or you can do your own or whatever. Just get to this spot. Now you'll notice, we left one thing off of our query. I did it on purpose 'cause I want to show you one other thing, we have ID, title, and author. When we created our table, we only created it with title and author. We're going to show you how to alter a table in SQL Server just in case you want to add genre and read later as you're working through this. So just alter table books. We're going to add ID. That's an int. We're going to run this query, refresh this. I see Books has all three. All right. I'm going to go back to query one. I'm going to run this. Query succeeded, eight rows. If I do one more new query, I'm going to say select star from Books. I want to run this. Notice there is all my stuff with my ID at the end. All right. We have SQL Server set up. It's running. We've got data in there. Let's go start querying stuff out of our database.
Connecting to SQL
Now that we've got a database created, let's go through the process of getting our Node Express application connecting up to our SQL Server Azure instance. We're going to use a tool called mssql. If you go to npmjs.com and just look for mssql, it's just this one right here. Now this is going to do all of the work for SQL Server for us. It's going to open our connections. It's going to handle our queries. It's going to do all that stuff for us. All we have to do is install it and use it. The first step is going to be npm install mssql. Let's just run that. When it's done running, if we come into package.json, you'll see 4.1.0. That's the version we're going to use. As always, the first thing you're going to do once we have it installed is to use it. Let's do const sql equals require mssql. We'll save that. Now we're going to skip the quick example because I don't want to get there quite yet. So we're going to come all the way down to the bottom. We're going to look at this config document. I'm going to copy this. Right now here under where we set our port up. First, let's close a couple of things to make it better. I'm just going to paste that in there. I didn't paste anything special. I just pasted exactly what we had off the website. The user I created in my Azure instance was library. The password was pslibrary with a one 'cause I had to have something in here. Now for my server. This part is where you might forget, or you don't remember where you put it. If you go back over to portal, and you go to your SQL database, PSLibrary in this case, you'll notice right here, it has your server name. You can actually just click it, and it's going to copy it to your clipboard for you. Now we're going to come in here and just paste that. And then the database we created, or it's just PSLibrary, just like that. I'm going to leave this encrypt section exactly the way it is, and then we're going to close it out. Now I'm going to use that config to open up my connection. At this point, we just go sql.Connect, and pass in the config. Now this returns a promise that lets you do stuff after your connection is done. I love autocomplete except when it doesn't do what I want it to do. Now it returns a promise, but I don't want to do anything with this just yet. I'm going to do just a .catch right here on the end just in case there is a problem. If there is a problem, we'll have that lined up. It doesn't like curly braces for one line, which is fine. Really, I don't need the parentheses either. We'll just clean that up. There you go. All right. Now I get a connection. Let's save that, open this up. Type npm start, hit Enter. There we go. Now everything just broke. Interesting. I got an error that's spit out from my connection. Cannot open server requested by the login. Client is not allowed to access the server. That's 'cause we didn't do one thing. Let's go fix that problem. It's important. I kind of wanted to demonstrate this to you instead of just doing it upfront so you get an idea of how this works. Now my connection was open, but it couldn't get there because it didn't get to the IP address. We're going to come back over to our portal. Right up here, we have a set server firewall. I'm going to click on that. They've made this really easy. I just click this add client ID button, and it's done. I save it. It updates the rules. Now I'm done. I close this. I do an npm start. That'll work. Okay. I've got a connection, but I'm not doing anything with it yet. Let's pop over to bookRoutes, and let's start using this thing. Let's minimize books because we're going to delete that here in just a second. Same thing here. Const sql equals require mssql. We're going to save that. Let's come down inside our BookRouter. Inside our get, let's actually try this out. All we have to do is create a request and then we're going to use it. So we're creating a new sql.Request. Red squiggly just means we haven't used it yet. And then we just go request.query, select star from books. Now we've got a bunch of options here. We can use callbacks, we can use promises, we can do async, we can do all of those things. I'm going to start with a promise. This is going to return a promise with a .then on it. It's going to send me back. If we come back over to our documentation, it's going to send us back a result, and then we can catch the error. Right here. Let's look at what the result is. Just so we're not confusing things, let's put our book list up inside here. Okay. There is my open. What we're going to do now is let's look at the result. I'm not ready to just drop it in here into books 'cause I don't know what this looks like. We want to debug result. The problem with debug first of all is we haven't created it. Let's come up here, const debug equals require debug. Remember, we have to pass something into debug. What do we want to pass? Because we could pass app but we're not in it now, so I don't want to just pass the same thing we passed before. Ideally what we want to do right now is I'm going to pass app.bookRoute. We'll save that. Now that's not going to work because we're not using bookRoutes. I'm going to come back over. When I say using, I'll show you what I mean to package.json. To our start, we have debug equals app. I don't want just debug equals app, I want all of it. We're going to save that. We're actually going to close everything and start it over again. All right. This is all red because we don't have parentheses around result. Let's add that to clean that up. I don't need it, but if I'm building something bigger, it likes to have it. Down at the bottom, we'll stick our semicolon, clean up our empty lines. We'll save that. Watch it restart down at the bottom. If we click on books, we get back our list, but remember, that's just the hard-coded list. Over here, look at this, we've got bookRoutes. Make this big. We've got recordsets with a whole bunch of objects. And then we have a recordset with all of our stuff in it, title, author, ID. That's what we wanted. And how many rows, rows affected. Result.recordset is what we want. Back in here, let's do books equals result.recordset. That should be what we need. Refresh my page. Now it works, I guess. If I hover over more, notice it's still books sub zero, but War and Peace is actually one. The reason why it's doing that, if we come back over to our views, our bookListView, here we've got nav.title. Scroll down to where we have our, there is the books of i's of author. Read more is i. Really, what I want is that to be .id. We'll save that. Refresh. Hover over read more. Now you see we've got one.
Using Async
We are successfully pulling out of the database at this point. But we're doing things the old style. Let's spend a couple of minutes, and look at how to do things in new style JavaScript. Let's just do this a little bit differently. Here I've got a .then. I don't have to use promises anymore, which is very cool. I can do async await. Async await basically means I can get rid of the .thens, and get rid of all that promises stuff. The way we're going to do that is async await requires an async function. This isn't in an async function, but there's an easy way around that. I can just create an IIFE. This IIFE is actually going to be an async function with no parameters in. And then everything else goes inside. We have a lot of red. Let's clean that up real quick. It doesn't want a nameless function first of all, so we'll just name it real quick. It's the space there. Everything was red because I didn't have a space. That's the way it works. Get rid of that. There we go. All right. Now that I have everything wrapped in async, I can just do await. I can go like this. Check this out. I use a const result equals await request. Get rid of my then. Format my document to move everything over one space. That's it. Notice how this reads now. I open a request, I wait for my query to come back, then I spit out my results. Just like that. Especially when we start doing multiple instances of queries, and we stack things together, this lines things up much, much more nicely. Let's save that. Just for fun, we'll run this one more time. It still works. If you look over here, we still have our debug output. We don't necessarily need that anymore. We can just get rid of that. All right. Now we don't use debug, so I got a red underscore, but that's fine. Now I need that to pull up the right book. Let's make our query a little more complicated. Come down here to our bookRouter.route with an ID, and actually pass values in to our select statement.
Input Parameters
All right. It's one thing to query everything out of a database, but let's talk about how we query specific things and add some query parameters to what we're doing. Basically what we want to do is we want to create this page, just book sub one, and query a single book. If you recall in the last clip, we made this work. But now in read more, I just want to click on book one. The way we're going to do that, if you look down here, bookRoute, we pull an ID out of req parameters. We're going to try and do the same thing that we did up here down there. We're going to start by pulling an async function. The way we do that, remember, is we're going to create an IIFE, which basically is two parentheses. The way I always say this is two parentheses and then put a face inside of it, so it's two eyeballs and a nose. It's kind of gimmicky, but a lot of times, if things don't work, people have forgotten the second eyeball, and all you can say that in training, it's like you've left an eyeball off. Okay. At the beginning, async function. We're going to give it a name just because yes, it wants us to. And then we're going to move all of this up inside. Format, clean it all up. All right. Now this sql.Request, let's just copy down. Okay. I want to talk about two things real quick. The first one being, we pull in a single request, and we pull in the query, but notice, we never connected to the database. I want to talk about that for just one second. Over here in app.js, we connect to the database. This actually does the connection. Remember, we hit the error. Before we queried anything, we just hit the error right here on connect with our firewall issue in the last clip. If we come over to bookRoutes, and we look up at the top, how is it that this is already connected? The way that works is when we say require mssql here in bookRoutes and over at app.js up at the top, it's the same instance of mssql. The way Node works is it creates an instance of mssql here, and then it just passes that same thing. It caches it and passes it everywhere that it's being used. That's very helpful when here I can do a connect, and then I just pass the same thing around everywhere that we go. When it comes over to bookRoutes, and I do sql equals require mssql, it's the same thing for map, so it's already connected to a database. That just makes our lives pretty easy. All right. If we come down here, I have const request equals new sql.Request. Now I want to query. Old school, I'd go like this. I'll move this down here where we do something like this. This is gross, and we don't like this. It actually even says that is preferred template, and we'll get to that later. But this is gross, and we don't want to do this. What we're actually going to do is something like this. The way we do this. .input. You'll even notice when I hit a dot right here, it actually is listed right here in my options, request.input. What input is going to take is a name of itself, ID in this case. That's what we're passing in. We can pass. Here you go. Just with the help, you've got the name and the value or you can do the name, the type, and the value. We're going to do the name, the type, and the value. It's sql.Int is what we're passing in. And then we're going to pass in the actual ID. And then we're going to chain to that our query. We'll actually pull this right up here. Select star from books where id equals @id. And then that will get us result. What result is going to be. Let's actually just look at that. We'll go to the next line, and we'll do debug.result. Got to refresh. And then you'll see the result that came back was recordset again. Notice it's still an array. So we are going to take recordset. Result.recordset sub zero. Now we've done this twice now. Look at this, result.recordset thing. We don't like that. I really just want to say hey, we're going to pass back the recordset. Remember destructuring. Let's just do this and pull it out. I want result.recordset. We'll take it out of book. There you go. We'll get rid of our debug, save that. Let's see if this all works. We have refreshed. Let's go to our book list here. We got our list of books. We'll click on number three. And we get the Time Machine. That's connecting up to SQL. That's the basic idea here. We have a query, we do a config, and then our connect. It just works for us. The idea is not to do a lot. If you go back to npm, you can read through some more of the documentation here. If you continue with SQL Server, and do inserts, so here's input. You can do transactions, prepared statements, all of those types of things to get this all going. I've gotten you marching you down a path of SQL Server. I at least wanted to expose that to you a little bit. Now there's one thing left though that I want to touch on, a phrase that you may have heard called middleware. I think we even used that a little bit in this conversation. I want to go into bookRoutes, and I want to introduce you to this concept of middleware around our slash colon ID.
Middleware
I want to take just a minute to introduce you to this concept of middleware, and show you some things that we can do with it. Now one example of middleware that we already have is if we go back to our app.js, we have this app.use morgan tiny. Morgan is a piece of middleware. What morgan does is as something comes in, it looks at the request, and logs something out of the console. When we get to passport, passport is middleware. Basically all middleware is, is a function that is executed on everything that comes in. Here, let me do a debug. My middleware. Let me save this. Now if you're familiar with middleware at all, you already know there's going to be a problem here. That's fine. Let's restart our app, flip over, and let's just go back to books three. Notice I'm just sitting and spinning. Everything's broken, but I come back over here, and nothing's done at all anywhere. If I call next and save. I'm going to restart. Now I get it although I don't get my debug. The reason for that, if we come back over to package.json, we did app. There we go. I got my app here. We did colon star, but with we forgot to leave app on. All right. Let's come back over here. We'll save that, refresh our page. Now you see we get my middleware. Everything that's called. Notice, boostrap.min, my middleware, everything, everything that you asked for gets this little my middleware thing. If we take next back off, and save that, what next does is say hey, when you're done with this, run the next thing. Now I can refresh, and notice now I'm going to sit and spin, but I did get my my middleware. What this is used for ultimately is I can interrupt the process flow, and I can do whatever I want to do. We'll use this from time to time throughout our application. I'm going to show you one place where we want to use this right now. If we come over to our bookRoutes, on line 72, we have bookRouter.route with an ID. What this is, is I'm going to go pull an ID. We've got our .get. But ultimately eventually, we may also have a .posts, a .put, a .patch, all of those things. What I don't want to have to do is replicate this book selection code every time. It doesn't make sense for us to do that. What we're going to do instead is we're going to implement a piece of middleware. We're going to do that. In a route, you use .all. Instead of route.use, we're just going to do a .all. What .all is going to take is a function, request.next just like everything else. We're actually going to take this entire thing, cut it, leaving the .get empty, and pasting it in to the all. Now we're almost there. Basically what's going to happen now is no matter what you do, going to slash ID, whatever you do, put, post, get, we're going to return back this bookView, and we don't want to do that. We're just going to take this back out. Just take the render, put it back down here. All right. What we've got is in all, we are going to go query for the ID, and then do nothing with it. What we want to do is we want to go query the ID, and then pass it along to everything else. The way we're going to do that is we are going to modify our request object. We're just going to add something to it because all the request is, is an object that's passed around from one piece of middleware into the next. We can manipulate it. We can do things with it. We can say req.book equals recordset, and then call next just like that. We'll save that. Now what this is complaining about right here if I hover over this real quick, it says to use array destructuring. We talked about object destructuring. We're doing it up here on line 75. What array destructuring is, is when I just do that. Now req.book becomes whatever recordset sub zero was. If there was more than one thing, you could just add commas. Array sub one would be the next thing. This is fine. I find this to start becoming confusing. You can do what you want. I'm going to leave this like this. What I would potentially do in a personal project is I would leave it like that, and I would change the rule, but whatever works. Okay, now that this is here, we now have to use it. Here we have next. Down here, we can say instead of returning recordset, we could just return req.book. There you go. You can harden this up. You can check to see if there is a req.book, then you do something. If there isn't a req.book, you return a 400 error. There's all kinds of stuff you could do. But for right now, we're going to leave it like this just so we can make sure that this works. I want to save this. We're going to come back over. Everything still works. All right. That's it for middleware. That gets us where we want to go. Now let's switch gears, and move from what we have here with SQL Server, and we're going to go and connect to a MongoDB database instead.
MongoDB
Now that we've looked at one side of the extreme with SQL Server, we're going to now look at the other side with MongoDB, and the comparison between the table-based structure and the unstructured setup of MongoDB. MongoDB tends to be fairly popular on the Node.js side. If you're coming from a .NET or Java background, I'm going to spend a little bit more time on the Mongo side because this is something you may not be as familiar with. The first thing we're going to do is we're going to go right on to mongodb.com, and we're actually going to install Mongo. I know on SQL, we just set up a cloud instance. The reason why we use the cloud for SQL Server is because you can't install that on everything. I'm working on a Mac, or if you're working on Linux, I don't have an option to install SQL Server on my Mac, so we set it up on the cloud that way. MongoDB can install anywhere. We're just going to go through the motions of installing Mongo locally, so we can play around a little bit more. The first thing we're going to do is we're going to click on solutions, and we want to try it now, MongoDB 3.6. We're going to click try it now, and go to the community server. This is what we're going to download. Notice for me, it defaults into OSX. If you're on Windows, that's cool. Click on Windows. And then we're just going to download it. Now that'll start downloading. I'm going to click the back button though 'cause there's one thing I want you to look at. If you go back to community server, there's an installation instructions right here. On Windows, it's in the same spot. If you click that, it actually has fairly detailed instructions on how to install. If you're on Windows, I'm not going to walk through the Windows installation in part because it's actually fairly straightforward 'cause you get an installation file. You just double-click the MSI, and it kind of goes. MacOS is a little bit different, so I'm going to walk through that one, but click on the installation instructions, and you can kind of see what's going on. Now this is downloaded. I'm going to open a terminal window, and I just created a directory called MongoDB, and I'm going to drop this TAR file in here. I'm going to right-click, open it with the archive utility. Now I have a file. I'm going to copy all this, paste it, and then delete what I just downloaded. Now I have just a bin directory and some readme stuff. That's cool. If we open the bin directory, you'll notice a couple of things. We've got two executables here that matter to us. We've got mongo and mongod. Mongod is the actual server. We're going to run that to start up a server. Mongo is our client application. That's what we're going to run to connect to our client. Let's go to a terminal window. I'm already in the bin directory here. I'm just going to type ./mongod. That's going to fail. The reason why it's going to fail, if you work through the installation instructions is it says we don't have a /data/db directory. We're going to work on that by going make dir -p /data/db. Now I'm getting a permission denied. You may or may not, but if you do, just come back and sudo it. Now I don't want mongo to have to be running in admin mode. I don't want to sudo mongo, so we're actually change the permissions of this directory so that it doesn't have to do that. We're going to do a change mod 777 /data/db except we can't do that because I've got to sudo it. All right. Now I should be able to just type ./mongod, and now my database is running. We can check that by opening a new terminal window, and running mongo. You can see a whole bunch of stuff here, but ultimately we are connected. I can just do this. Show dbs, and see I've got two. I've got admin and local. You see over here on the server side, I have this received client from. That means hey, I'm connected. I've got MongoDB up and running. It's ready to go. Now let's actually start playing around with this a little bit. Let's create something on our server that's going to install data for us. In the SQL Server side, we wrote a install script. On the Mongo side, let's go a little bit more in depth, and let's actually create an adminRoute in our application that's going to populate data for us.
Admin Routes
Alright, what we're going to do next is actually build a series of routes in our application that will handle the insertion of data into Mongo for us. I'm going to do this for a couple of reasons. One is we only have one router set up right now, so I want to give you an opportunity to create another router. This also is just an easy way to take the date we've already typed once, and just copy and paste it, and then have the application inserted for us. That's what we're going to do. If we pop back over into our application, I've reverted back to how we had it set up back at the beginning of this module. I've taken all of that SQL Server stuff out of it. If you need to restart, just pull down the course materials, and the starter module six code should be in there. You can just start from there if you would prefer to do that. The first thing we're going to do is we are going to come in and create a new route called adminRoutes, and this is the routes that's going to deal with this insertion of data for us. Let's click on routes. Right-click and create a new file, adminRoutes.js. If you look at bookRoutes, here at the top, we've got express, require express, and bookRouter equals express bookRouter. Let's just snag those two, and paste them here. Now instead of bookRouter, we're going to do adminRouter. All right. Now to create a route, remember we have this setup as a function. And then down at the bottom, we export this function. Now you could, and I haven't talked about this, you could just do this like that, and that's perfectly fine. I prefer to have my exports down at the bottom all in one place. That's why I do that. But yes, if you asked the question, why can't I just do that, you can, that's fine. All right. Now we're going to set up our route. adminRouter.route is going to be that. And then we're going to append to that our .get. What we basically want to do with .get is we want to have it insert a whole bunch of stuff for us. Before I go any further, look, I'm getting all these red under squigglies. That's because I created a new file down here at the bottom. See, I have spaces four. We're doing spaces two. I'm going to format my document. There you go. It all cleared up, not all of it but most of it. We'll just get that out of the way real quick. Now I've got my .get. What we're doing with our .get is we're going to use that to insert. Basically I'm just going to go to localhost/admin, and it's going to drop a whole bunch of books in there for me. That's the idea of what we want to do. Our get is going to take in arrow function, req and res. This arrow function is going to insert the books. Now we're not quite ready to do that. I don't want to drop on my Mongo code in here yet. Let's just do a res.send, inserting books. I add my semicolon. Hit Enter right here to clean that up. We're not using nav. I'm just going to leave that there because we may use it later. Actually we're not here anyway but I'm just going to leave it. This one, we haven't ever done. Go ahead and clean that one up too. All right. We've got that there. Now we just have to hook it up. We've got our adminRoutes created. We just have to hook it up in app. Let's come over to app. Right here where we do bookRouter equals require bookRoutes, I'm just going to duplicate that line, and then I'm going to say admin. Here we have app.use books. Here we're going to say app.use admin and adminRouter. Before we only had one. Now we've got two. App.use is basically saying hey, if you get a request to /books, send that stuff to the bookRouter. If you have a request for /admin, send that stuff to the adminRouter. Those were pulled up right up here on 24, 25. That should be all set. Now if we just come down and do an npm start, we've mistyped something, so come back over to our adminRoutes, and look at what we forgot. Down here at the bottom. Our function router. Let's look at this error. I want to give you an example of some of the weird errors you're going to get. You got a type error. Router.use, which is essentially what we did right here, app.use, requires a middleware function. Remember, a middleware function is something that has req and res and those types of things to it. We got a get type function instead. It's something weird that didn't even work. What we forgot is we have our adminRouter here. When we execute this function, it doesn't do anything. We've got to actually add right down here, return adminRouter. We forgot to return our adminRouter. Now when app.js executes this function right here, it's going to get back an adminRouter instead of nothing because that's what it was getting back before because we weren't returning it from adminRoutes. All right Now we're working. If we go to /admin, we now get this message, inserting books. That's where we want to be. If you got that, you caught up. Now let's look at MongoDB, and get our things going.
Inserting Books
All right, now let's spend some time writing the code that's going to insert some books. Let's actually start using MongoDB in our application. Just like we did with SQL Server, we're going to go out to npmjs.com for our MongoDB side. We're just going to type in MongoDB. You see here, the official MongoDB driver. Let's click on that. You can usually tell the success of a package by looking down here, downloads last month. This one is used, so let's use this one. You can get documentation right here. It goes out to MongoDB's documentation. Lots of stuff out there. But for us, I'm going to walk you through it, so you don't need to worry about any of that. But MongoDB is what we're going to use. If we come back, we're going to close this, and we're going to do an npm install mongodb. If we go our package.json, there it is right there, 3.0.1 is the version that we are using. Now that we have MongoDB installed, we need to start using it I'm going to do this just a little bit differently than we did on the SQL side. On the SQL side, we went into app.js, and I opened a connection over there. I'm not going to do that for this. We're going to do it a couple of different ways in the various things we're doing, but for right now, I'm just going to do it all right here in adminRoutes. Up here at the top, we're going to do mongoClient equals require mongodb. Now in order to use it, what we actually have to use is not, we're not pulling in all of MongoDB, we're actually just going to use MongoClient. Now remember, in the fancy new world, we don't have to do this anymore. I wanted to type it out so you at least saw it and understood, but now we take this, and we destructure that. All right. Now that we have a MongoClient, we come down into our actual router. I'm going to minimize some stuff so that you could see what's going on. We're going to do all of our database stuff right in here. The first thing we're going to do is create a variable just for our URL, mongodb://localhost:27017. That is the standard port that everything runs on. If I come back over to my terminal that mongod is running on, I'll widen this a little bit so you can see it, when it was done setting up, it says waiting for connections on port 27017. That's just the default port. That's what we're going to do. Then we have to have our database name. In this case, think of it just like SQL Server. SQL Server has databases, Mongo has databases. We are going to call this libraryApp. The big difference between Mongo and SQL though is I have not done any work on the Mongo side to create that database. I'm just calling it libraryApp right here. I just typed it in. I haven't typed it anywhere else. And it's going to create it magically for me when it's not there. That may be great or it may be concerning to you. Either way, it is what it is, but that's what we're doing. All right. Now just like the SQL side, we're going to use async await as we're dealing with Mongo. You can do it with promises. If you go back out to the MongoDB documentation, and look here, it walks you through using its promises. That's cool. We need to get comfortable using the new stuff. I'm going to do everything in async await because it lines out very nicely. We can just go from there. We're going to create an IFFE. This is my standard how you create an IFFE. We're going to create a async function. We're going to just call our function mongo. I do this, remember, just because if I don't, then it yells at me because it doesn't like unnamed functions. Naming your functions is a general good idea. Inside our async function, we're actually going to create a thing called a client. This is going to be what we're going to use. We're going to create it up here because now check this out, I'm actually going to do a try-catch block. I want access to the client but in both, and I want to be able to close down below. I'm puling my client up here. My try, we're going to open our client. We do MongoClient.connect. Did I type everything correct? We're connecting to our URL, which is localhost:27017. Now it's going to wait. It's going to wait for that to happen, which is exactly what we want. Actually let's just spit out so we can see it. Hey, we connected to the server. Now I don't have debug yet, so let's add that. In this case, we want it to be app.adminRoutes. Now that we've connected to the server. The next thing we do is actually pull the database. We're actually going to tell our client, hey, we're going to use the database libraryApp. Once that's done, now I'm connected, I've got a database, I'm going to insert some data. The way we do that is by awaiting db.collection. Now the collection is kind of like, some people would be highly offended by this statement, but it's kind of like a table. It's not a table at all. But in SQL Server, you have databases and tables. In Mongo, you have databases and collections. It's kind of like a table, but it's not at all like a table. You'll see what I mean by that here as we go into this. But we're going to create a collection just like we created a table called books. And then we are going to insert many books. Books. Now I didn't copy books over. Let's come back over to bookRoutes. There's books right here. We're going to copy that. Just remember, I've minimized it, but it's just this list of books. We're going to come back up here to the top, and we're going to paste it. Now I have this thing called books. That's our list of books. Okay. I'm going to insert many. What this will do is it's going to return the results of that. Let's actually save that into this variable called response so we can look and see what that looks like. Let's send that back. We haven't talked about JSON yet. We've done a res.send. We've done a res.send file. We've done a res.render. Res.json is going to send back a JSON object. It's going to format it for us. It's going to set the header types all properly. It's going to do all that for us, but it's going to send back a JSON object, which just so happens to be what our response is. That makes it pretty simple just to send that back as JSON. Now in case there's a problem, let's log that out. And then down when we're done, let's close our connection, and then get rid of our inserting books. That's it. We've got it all set up. Now let's go try it and see what happens, and then go from there, and I'll show you a couple other things about Mongo as we go.
Testing Insert
All right, now that we've got our code written, let's test it to see what's going on, and we're going to talk a little bit about Mongo as we go. If I pull my thing back up, and I do an npm start, and we go to localhost:4000, everything should still work. I'm going to now do /admin. Now look at what we get back here. This is interesting. We got a result that says eight. That's how many books we inserted. And then we have this ops, which has all of our stuff in it. Now notice a couple of things. I'm going to go back to our terminal window for a second, and I'm going to do show dbs. Now I have a libraryApp database. I did not have that before. Like I said in the last clip, it's just creating it. If you actually look at our thread over here on mongodb or the mongod, you actually see this line right here, createCollection: libraryApp.books. It just creates it because it needed it, which is great. That's a fundamental distinction between SQL Server or Oracle or MySQL and MongoDB, which is more of the unstructured. It's just going to create whatever it needs. All right. The other thing it enforces, it created this underscore ID. Everything now has an ID. When we do an insert, and part of why we pull it back is we want access to this ID so we can kind of start doing stuff with it. All right. That's all there. It's all good. I've got data in the database. If we go back to our command line, I can actually do a use libraryApp. And then I can do a db.books.find().pretty(), and it will give me my books. You see, they're all right here in our database. It's all there. If you don't do the .pretty, you can do it without it. It just looks gross. .pretty makes it all nice and it looks good. All right. Now that that's there, let's start implementing mongo over on the bookRoutes, so we can start pulling stuff out and do some searches over there.
Select Many
All right. Let's implement select many, or pull out a list of books from our MongoDB database to make our books page work. One thing I want to fix real quick as part of our adminRoutes 'cause we're going to use this in our bookRoutes as well is notice I have, on line 66, a debug statement that didn't get printed out. The reason why is 'cause when I reverted everything back to the beginning of four, we didn't add something back in. Let's come back over to our package.json file. Here on line eight where only DEBUG equals app, let's add our app colon star. Now we'll get our messages spit out that we needed. Okay, let's come to our bookRoutes. We're going to hang out in this file for a little while. First thing we're going to do is we're going to come up here, and we're going to add our two lines, MongoClient and our debug. Instead of adminRoutes in this case, we're going to do bookRoutes. Okay. We've got require mongodb. Our debug equals our bookRoutes. If we come down into our slash right here, if I come back over to adminRoutes, I'm going to borrow much of what we did. I'm going to do our URL, our database name all the way down to our try. I'm going to copy all the way down to db.collection books, not the insert many, just the collection. We're going to come back over here, and we're just going to drop this in right there. After our render, we're going to close our try, we're going to close our client, and then we're going to close everything else. All right. We're going to format that. All right. We're all set. Now I just have to implement everything. Here we copy this over. Let's change this. We're going to just say our collection. Our collection equals await db.collection. Now we have to do our find. The way that works in Mongo is instead of a select select like we do in SQL, we actually use the word find in Mongo. It's going to return back our books, our collection.find().toArray() because it's going to hand back a whole big thing, and I don't want all of that, I just want the array. What find does in this case, it's just going to hand us back everything. For us, that's cool. We don't need to filter yet. We're going to filter in the next clip. Right now we just need everything. Col.find, just give me everything. And the these books is going to come down here, and overwrite, and be done. Let's save that. We're restarting. That's it. It should work. Let's open up /books and see what we got. I've got books coming back. It looks like it worked. If I come back over here, you'll notice we still have our thing. The reason for that is in our package.json, we changed this, and that's great, that's correct, but what we didn't do is restart, which you actually do have to do. All right. Now let's refresh. now you'll see connected correctly to the server from our bookRoutes. Okay. The best way to know that this worked, and we're pulling from the right place is we're actually going to come into our bookListView, and look at one thing. Notice when I hover over read more, I still get zero and one. Now I actually have real IDs that I want to use. We're going to come back over to our bookListView. Right here on line 105 where we say i, we're going to say books of i dot underscore ID. And then we'll refresh this. Now you can see I'm pulling those out. Now when I click on this, it doesn't work because everything's horribly broken at that point, but here at this page, it totally works. What we need to do now is implement this single route. We're going to do the same thing that we just did up here down below to give us our book.
Select One
All right. We've got this select many out of the way, which was the easy one because it's just give me everything you've got in the database. We've got that part covered. Now we're going to do a select one, which means I've got to start doing some queries, and I actually have to provide a query into my Mongo find. Let's talk a little bit about how to do that. If we look back, let's talk a little bit about what we're doing, we're here on books, and I want to be able to click on this read more, and go to this route, and actually have it work. It doesn't work right now. Blows up because this thing doesn't exist in that array that we have. Let's fix that. All right. If we come back into bookRoutes, almost everything we do in this clip is going to be in bookRoutes. If we come back down, the first thing we're going to do finally is we're going to delete this array. I have had it minimized most of the time, but it just clutters everything up, so let's get rid of it. We don't need it anymore because now everything is going to be in the database. We're going to come down into our bookRouter. Let's copy these two things. We're going to type everything else, but let's copy those two lines of code. Right here under our ID, remember we pulled in our ID right here, under that, let's paste these two things. And then we're going to do our async function again. I always type an async function like this, and I do that on purpose because I want to make sure I've got the whole thing lined up. Then I'll come back in, and I'll fill it in. We're going to do an async, async function, and we're going to name it just because. You can name it whatever you want to name it. It doesn't really matter, but in general, we want to have a name to function there. Okay. Now if we come back up here, a lot of this is the same. We're going to let client, we're going to try client, we connect it to the server, we connect it to the database, we connect it to the collection. All that's the same. Let's actually just copy that. We're going to drop it right there. Let's close that and catch. And then if there is an error, we're going to debug our error set. Now comes the interesting part because we've got our collection, and remember up here, we did a books equals col.find().toArray(). What we're going to do down here is const book equals. Same basic idea, col.findOne. What findOne does is it just finds the first one. If I do a find and do at a query that limits to just one, I still get an array back. FindOne is just going to hand me back the one individual thing, and I don't have to worry about arrays. Now when we're finding in Mongo, I'm actually going to pull the terminal up here for just a second. Db.books.find, the way we find is we add in an array. I'll make this bigger for you for a minute. You pass into Mongo a JSON object, title, just like that. Now we only get the one item. This is how it works. We're going to pass in a JSON object to filter down in just the one item. Now in this case, we want underscore ID, and we want our ID. Now in theory, this is great. In practice, this doesn't work. Now the reason why it doesn't work is if we come back over here and notice that our underscore ID is not just a string, it's this thing called an ObjectID. That's different than just the string. That's important for us. What we actually need to do is use Mongo to build out this ObjectID. If we come back up here, right now we've got MongoClient. We also need ObjectID. ObjectID is going to do this thing for us. Let's copy that. We're going to come down here, and we're going to pass into our ID. Instead of just ID, we're going to pass in a new ObjectID, and we're going to save that. Now once that's done, we're going to take our render, and we're going to render it, but instead of books, we're just going to do book. And I don't even have to do that, I can just do that. Okay, one thing we forgot, we got to add await in front of our findOne, so it's going to wait for that to happen, and then we're going to render it. Let's spit out right here the book just so that we can look at it a little bit, and make sure we're doing the right thing. All right. Let's save this. Let's clean it up a little bit. All right. We have restarted. If we come back over here, let's hit Enter, and now you see I get my book. If we come back over, you see right here our connected to server, and then our book just comes back as an object. We've got our ID, our title, genre, authors. It's just the object, which is great, and that helps us get our stuff done the way we want it. All right. That's it for Mongo for right now. We're going to add stuff later, and we'll implement some more things when we start doing our login and user routes. But right now we're able to pull data out. Let's add some security in the concept of a user so that we can sign in and we can sign out and we can restrict access to things using passport in our next module.
Summary
All right. We got quite a bit done in this module. We talked about a couple of different concepts while we were at it. We're working our way through building a web application. Now we actually have something that we could call an application where we're displaying some data that we're pulling from a database, we insert data, we did all of those types of things. We started by getting data from SQL Server. We set something up out on the cloud. We did our basic selects from SQL Server, both the single select and the select multiple, and we got that all working. I then showed you the other extreme with MongoDB, and how now we've got a Mongo database running that we can use to insert and pull data from. We looked at a little bit of the Mongo command line just so we can play around with that a little bit. And then we inserted data using some admin routes. I showed you how to dump some data in, and then how to pull out both one and many items. Now that we've got all that working, let's add the concept of users, and start dealing with this thing called passport that's going to handle our authentication for us.
Authentication
Introduction
In this module we're going to talk authentication and creating users for our web application. Now, we've come quite a long way in this course on building a web app with Node.js and Express. And we've got databases set up, we've got routing done, we're pulling stuff out of the database, displaying it to the screen, all that's there, but there's an important thing that we're missing that most applications that you might be working on require, and that's the concept of a user. So in this module, we're going to start creating users. We're going to create new login, the password, you can sign up and sign in, and all those types of things. We're going to do authentication. You'll enter a username and password and we'll validate that that's correct, and we'll log you in appropriately. We'll do authorization. And so, authorization is the ability to block certain pages. We're actually going to block most of the website if you're not signed in. So, you can't get to the profile page. You can't get to the books. We'll block everything if you're not signed in. And we're going to do all this using this thing called Passport. And Passport is the default npm package that Express uses for user management. We're going to mostly use the local strategy in this course, but there's other strategies for handling Google, and Facebook, and LinkedIn, Integration, and all those other things. So, let's get some stuff done.
Sign Up
In this module, we're going to create a sign up form. We don't have this concept of a user at all yet, so sign in doesn't work. We've got to start with sign up. And so, we're going to change our first page up in order to create this sign up form. So, if you're following along, your home screen should look like this. We've got this Library home page with the standard items that came with the template. Our books page actually has some books in it, but our home page has what was left over from when we created the template. We're going to repurpose this to build our sign up form. And so, if we go over to our view, and we open up source, views, index.ejs, this is that home page. I'm going to minimize everything so you can see more of the screen. If we go down to line 96, depending on where you're at it might be a little different. It's going to take this right here from this anchor tag all the way down to these two breaks, and I'm just going to delete them. And we're going to use this space right here to create our form. And so, let's start with this. Let's just say, "Hey, sign up," and then we'll create a form. In our form we're going to post but we don't have anyplace to post it to. And what we're going to do with this, right now we've got, if we come back over here, in our routes we've got our adminRoutes and our bookRoutes. And either one of those is what we want to use. We're going to use a new set of routes called auth. So, auth/signup, that's what we're going to post to when this form gets filled out. And then we're going to have two things. We're going to have a username and a password, and they're both going to be inputs. Now, I'm going to leave the type of password as just text, mostly just so you can see the passwords that are being typed. Normally for a password we'd have type of password like that, but we're not going to do that because I want you to see what's being typed so you can validate it later. All right, the last thing we need is a button. So, if we did this right and we come back over here and I refresh my page, now we have a sign up form. And you'll see mine, I use a form entry thing that automatically fill my password in because I do a lot with local host, but that for you is most likely blank, but then we've got all this stuff. So, let's delete that. We're going to delete pretty much everything from this line right here all the way down to this a href. We'll leave these two divs. So, about 186 is where I'm at right now. We'll save that and refresh. There you go, we've got our website up. Let's go build out the rest of this. So, we've got now to build this auth/signUp, which means we've got to build a route, we've got to build some views potentially, we've got to hook all that stuff up. So, let's go do that in the next clip.
Auth Routes
Now, that we've got a sign up form, we actually need to implement the routes that are going to handle the post of the form to create that new user. So, we're going to go out to our source directory, our routes, and we're going to right click and create a new file called authRoutes. Now our authRoutes are going to require a couple of things, the same thing as normal here. So, we need express. We will eventually need MongoClient. And let's go ahead and pull in debug. And for debug, let's say app:authRoutes. Now, we've got all kinds of red underlines because we're not using any of this stuff. So, let's go ahead and start using it. Let's do function, our router function, and then module.exports router. What we want to do in our function is create our authRouter and then create our routes, just like we've done everything else. And we've been doing this up here. It doesn't matter, you can do it down below if you want to. We're just doing const authRouter equals express.Router. And then we do authRouter, and we're creating the sign up. Remember over here in our index.ejs, we posted to sign up. In our authRoutes, we're going to sign up. Now so far, we've only done gets. We've always just put here a .get. Well, in this case, now we're going to handle post. And while I'm thinking about it, let's type sign up correctly. There we go. So, this is what's going to be used whenever our form posts to /signUp. But ultimately, it works exactly the same way. We still have a function with req and res. We still pull things out of the requests. We post things to the response, all of that stuff. But we now have one thing we need to do. Because if we look at index, we have this form with our username and our password that's going to be posted to our authRoutes. And this works a little bit different. Remember over in our bookRoutes if we scroll down, we had our :id, and we pulled out our req dot parameters, and all of that stuff, that just worked. The body of the post works a little bit differently. And so, we need to pull in a package at this point called body partial. So, we're going to pull this up and at this point I'm going to show you one more thing. I've got my app running here. And normally, we've been Control + C, cancel it, npm install, I'm going to stop doing that. We're far enough along you should be comfortable kind of with this part of it. I'm going to click this plus right here. And this is going to add a new terminal window. Now, I have two. I've got node and bash. If you're on Windows, you'll probably have PowerShell here. That's the option that shows up in Windows 10. So, if I'm here I can just do npm install body-parser. And if I go to my package.json file, you'll see there it is, 1.18.2. And so, what body-parser's going to do is look at the body, and then pull everything out and put it in our req.body. So, we need to tell it to do that. So, heres our app.use statements. We're doin' morgan, we're doin' express static, all of those things. Let's add our body-parser to this. So, up here at the top, we need to pull it in. And then down here right after app.use morgan, we're going to use body-parser. Now the order does matter, so we want to keep it up here at the top. We don't want to have it down at the bottom after our books and our adminRoutes are used because it's not going to work quite right. So, here were going to put it up here at the top, app.use. And we're actually going to go ahead and do two things, because most of the time you're going to want both of them. We're going to do bodyParser.json and execute that, and then app.use bodyParser.urlencoded. And then urlencoded requires an object with extended: false. We're just going to take that for right now as some boiler plate code. That's setting up body-parser. Don't worry too much about it, just this is what gets us there. Now, what that's going to do is pull out our post and add it to our body. And we can try that and we can play around with it by coming over to authRoutes right here and doing a debug req.body. Put our equals there, format our document. And then don't forget, right down here at the bottom to return authRouter. Change our indent using spaces to two, because that's what I've been doin'. The semicolons are a fine line, right? So, if I have one, it says, "Hey, you don't put one." If I don't have one, I got an error that says, "Hey, I need one." So, semicolons are a little weird. All right, we're going to save it, 'cause in either case it'll work just fine. We're going to save that, now we got to wire it all up. So, we come down here to our adminRouter. We're going to do an authRouter. So, pull the authRouter in, app.use authRouter, get it all set up and we should be good. I'm going to break something for a second. I'm going to do this and I'm going to save that. I'm going to flip this back over to where we're running, and I'm going to refresh this page. And you'll notice like everything just stops, which is painful and interesting. I'm going to add that back. And now, I'm going to refresh my page and it works. So notice, I didn't even get like a helpful error there. There we go, there's my helpful error. I'm going to save that. The reason for this is because it's using this bodyParser.json as a middleware. And so, it calls this function bodyParser.json, and it's waiting for bodyParser.json to call next. And it's not calling next. So, it just sits here and spins. So, if you're having something like that happen, double check and make sure that your middleware is all there and correct. Now, that that's there, everything should be wired up. Let's refresh this page, and let's type jon and password. We'll click sign up. Now, it froze, it didn't do anything, but look at this. In my authRoutes, here my debug req.body look, body pulled out username and password. And so now, we're froze, we're spinning because we're not passing anything back. And so, we can fix that. But I wanted to kind of to show you this, username, password, all of it set up. Now here, I can do res.json and send back my, I'll just send back my req.body. And res.json just sends back properly formatted json. It sets your headers properly. It does all that stuff for you and it sends back json. So now, when this refreshes, and I click sign up, whoa, now everything wants me to save. I get jon and password. All right, that's that. Now, let's implement our Passport to actually create users and add users to sessions and things like that. Let's get into the meat of this module and use Passport.
Passport
All right, we're going to use Passport in this course to deal with user authentication and authorization and all of that. And if we run out to npmjs.com and you can actually just type passport, you'll get this right here. This is the default thing that most Express applications are using. You'll see it's got over a million downloads last month. It's just the easy, simple way to deal with authentication and authorization. There's documentation here you can work through, but I'm just going to do it. So, let's jump in and start playing around with this. So, if we come back over to app.js and minimize everything, we are going to use Passport. And so, we need to pull Passport in. But what Passport does, well let's kind of work through it. So, const passport equals require passport. Now, what Passport does is deal with maintaining your user object in the session. And it also deals with dropping it in a cookie, and pulling it out of a cookie, and applying it to sessions, and all those types of things. So, that all being said, we need a couple more packages. We need cookie-parser and express-session. Now, cookie-parser is just kind of like body-parser, it does the same thing and it's also with a dash, and express-session. So, let's Control + Tilde, pull this back up, drop over to our other one, and install these. And if we jump to our package.json, see cookie-parser, express-session, and passport. All right, we've got those set up and we're goin'. Now, we have to use them. So, we're going to scroll down, same way we did here. We've got bodyParser. Now, let's use cookieParser. And then cookieParser's example, don't forget to execute cookieParser. And then app.use session. Now, session takes something called a secret. It's just something it uses when it builds the cookie. And so, what are we going to do? It really doesn't matter, so I'm just going to do library. Format that, all right. Now, we need to do the Passport stuff. And there's going to be quite a bit of it actually. If we come back over to our documentation, setting up Passport, serializeUser, we'll talk about what all this stuff means. There can be quite a lot of code here, and I don't want to just stick it right here in our code. I want to pull that out somewhere else just kind of like we did with the routes. So, what we're going to do is just do a require, source, config, password.js right here, and pass in app. And then we'll just move all of that Passport code that we would have done right here over into this other thing. Now, we got a red underscore because that thing doesn't exist yet, but we'll go create that and put everything in there. So, notice we've created this new thing called config, and we'll put other stuff in here, too. So, we'll create a folder called config. And this is where we'll put all of this type of thing. It'll create a new file called passport.js. Now, this is just a file, right? I mean, we don't need to pull Express. Password doesn't care about Express because we're passing the app in. So, all we really need right here is passport. That's the only thing that we're going to care about. Now here, I'm just going to do module.exports. And I'm going to do this just so you can see both ways to do it. We've been creating a function and then exporting it. Here I'm just going to do module.exports so that you can see this is an equally viable way to do it. Just kind of figure out your own personal preference. And we're going to export this function called passport.config. Change my spacing. Now, Passport does a few different things. Now, remember I said Passport, the first thing that it's good for is maintaining your user object in the session. And there's two functions it uses to do that, serializerUser and deserializeUser. And what serializeUser does is store the user in the session. And what deserializeUser is to retrieve the user from the session. And the way it does that is by executing a function. And so, we'll fill these in as we go. The other thing in order to get ready for that, we've got to do two things. So, we've got to initialize. This is where Passport just sets itself up on the app, on the request as it comes through. And then we have app.use passport.session. And that's going to just build up the session and pull things out. That's actually where we're going to start calling the serialized and deserialized users. Now, what these two things take are functions, just like everything else. And it's going to pass in two things. It's going to pass in the user and a done callback. And then we have to then take that and store it into the session. We have to do what we want to do with it and then store it in the session by calling done. Now, we haven't really talked about callbacks very much in this course, mostly because everything we're doing is a single wait. But in node we have a way that we do things in callbacks, it's error first and then the thing, whatever it is that we're doing. And so, you always check the first one to see if there is a problem, and then you do something with the second one. In this case, we're just going to pass in null and the user. Now in this case for us, we just have a user and a password. We're not going any further than that. But oftentimes, we don't want to store the entire user in the session. We only want to store a piece of the user. And so, you could actually do user.id and only pass the id of the user in. And then down in deserialize, you could pull that id back out. We're not going to worry about that right now. We'll talk a little bit more about that as I'm building our deserialize user, but just for right now, we're going to store the whole user in the session. And then deserialize is the same idea. Actually we can just copy, check this out, the whole thing. Now down here, if I was doing .id, that would be userId. We can call it whatever we want to, right? It's our function. But what Passport would be passing back in was just the id. And then we would... do something with Mongo where we'd go find the user and then we'd pass that user into done. But I'm going to set it up just like this and be done. Now, all that we're doing so far is we're taking the user and we're storing them in a session or pulling them out of a session. That's not really what we want to do totally. There's a whole lot more to this. And the problem with authentication in general is there's so many different ways to do it. So, we're doing username and password, but you could do log in with Google, log in with Facebook, log in with all these other things. And I don't want to have to write a whole bunch of different code to do all these different things. So, what Passport does for us is it implements this idea of a strategy. And if you scroll down right here, you use strategies to do it. And actually, if we come up and we just look for passport strategy, and we look at popularity, we'll just sort by popularity. Passport-local, local usernames and passwords. That sounds like what we're doin', so we're going to use that one. Just scroll down to, they've got an oauth2, they've got a Facebook, they've got a Google, they've got a Twitter, there's LinkedIn, there's just everything. And that's what you can use to use that type of authentication. We're just using local, so we're going to use passport-local. But again, there's going to be a whole lot of code. And I potentially am going to do it a whole lot of different ways. We're not in this course, but as you build it out, you might have a Facebook, and a Google, and a Twitter, and all of those. So, I'm going to break these out. And I'm just going to require right here a strategies directory and a local strategy. And that's where we're going to put all of our Passport code around local strategy. So, we'll save that, we'll save our app. And then I'll put a stopping point right here, and then we'll go implement this local strategy and get our stuff going.
Local Strategy
Now, that we have the pieces set up for Passport, let's implement this local strategy and see what that looks like. So, the first thing we need to do if we come back over to our terminal window is actually install the local strategy. So, we'll do an npm install passport-local. And if we go to our package.json file, you'll see there it is, version one. Now, in Passport we said, "Hey, we're going to pull "from strategies, local strategy." And you'll notice, I'm just going to call this out right here, eslint is giving us a hard time because there's this unexpected require just kind of sitting in the middle. And you'll notice over here in app.js, we did the same thing and it doesn't have a red squiggly underline. And the reason for that is because we're passing app in here, which implies that we need to get to a certain point and then pass it in. Over in Passport, we don't have to do that. So, I'm actually going to move that up to the top so we can get rid of that squiggly line, and it doesn't matter. And that's kind of the cool thing and we'll talk about that just a little bit here in just a minute. Now, we have to create this thing. So, let's right click on config and create a new folder called strategies. And then we'll create a new file called local strategy.js. Don't forget to put that js, that's probably the most important part. What we're going to do now is actually build out what the local strategy should be. And what that looks like, first of all, we've got to pull in Passport. Const passport equals require passport, and then we're going to pull in a strategy. So, passport-local is a object. It's a package that has this thing called the strategy attached to it. And in the olden world, you'd see pulling in .Strategy. We're not going to do that in our new world because we're going to destructure it over here, just like that. Okay, same thing as passport, what local strategy's going to return is a function. I'm going to give it a name, localStrategy. It doesn't matter what you call it because you're just exporting the function. But it's generally a good practice to have that function have a name. Set our spaces to two. Now, all that this file's going to do is tell Passport about this local strategy. So, the only thing it needs to do is say, "Hey, passport.use," and we're going to use a new strategy just like that. I like the red squiggly lines 'cause it reminds me, hey, strategy's not defined or we're not using it, that means I spelled it wrong. You probably yelled at me as I was typing, hey, you spelled it wrong, but I couldn't hear you because I recorded this a little while ago. So, passport.use new strategy. And what the new strategy thing takes is two things. And now, each strategy's going to be a little different, but localStrategy looks like this. And basically, what the strategy is is how we deal with a username and password, and how we identify that as a user. And so for us, the first thing we're going to pass in is the usernameField. We just have to tell it, hey, strategy, our usernameField is called, and come back over to index.ejs, username, and our password field is called password. And what that's going to do for us is now the strategy's going to deal with pulling that out of the body. And that's just a little shortcut. That's all it does. And then the strategy is going to call a function, and it's going to pass that function, the username, the password, and the done callback. And so now, it's up to us to define what that user is. And so, this is where here in a couple of clips, we're going to go out to the database, and we're going to validate the user, and we're going to check their password, and we're going to do all that code right here in this thing. But for right now, let's just create a user. We're just going to make one up with the username and password. And then we're going to say, "Hey, that's our user." We're going to call done, with null, and our user. So now, if you log in with a username and a password, it's just going to create a user with that username and password. That's all it's going to do, nothin' fancy. Wrap those in tick marks because these are strings. Don't forget. Make sure we're all done. Bring that up a little bit, all right. Now, our strategy is done. But we're not really doing much with it yet. So, let's go ahead and implement just a little bit so we can play with this. So, let's go back over to our authRoutes. And we're going to right click, I'm going to close everything else, just mess with our authRoutes. When you post a sign up, right now we're just taking what's in req.body and showin' it. What we should be doing is creating our user and then doing something with it. And we're not quite there yet. In the next clip we're going to implement creating the user and saving it to the database. But really, what we're going to want to do is log that user in. We're going to create the user right here. Once the user is created, we're going to log them in. You know how when you create a new account somewhere, you don't then have to go log in, it logs you in automatically. And so, that's what we're going to do. And we do that just with req.login. I now have this thing called login on my requests. And where that comes from, to go back over to passport. When I do passport.initialize, it creates these things on the request that I now have access to and login is one of them. And so, req.login, we're just going to send it req.body, which is the username and password. And then it's going to log that user in. And then once it's done logging that user in, we want it to go somewhere. And in this case, we're going to don our redirects. We've done res.render, res,json, all these things. Res.redirect just tells, it sends a redirect to the browser and say, "Hey, go to this other place instead." So, that's what we're going to do. We're going to actually go to auth/profile, and that doesn't exist yet. We're going to create that here in just a second. But what auth/profile's going to do is just show us the users created. So, what's going to happen here is when you sign up, I'm just going to create a login, which before we get to all the Mongo stuff, I want to show you what this looks like. And then I'm going to go to auth/profile and that login exists. So then down here, we're going to create another route called profile. And we're going to attach a .get to that. And what we're going to do with this is we'll take a req and res, just like normal, but what we expect at this point is because I'm logged in, Passport is going to take that user, it's going to serialize it into the cookie, it's going to do all this stuff, all magic for us. But when the request is made to the profile, it's going to attach that user as if by magic to the request. And so, let's just send it out. So, let's just look at what happens here. We'll just get rid of that for right now. We'll come back and deal with it later. Here, let's save that. Now, if we've done everything properly, this is still running, close that. Let's go to auth/signUp. Here we pass Jon a password. Now, let's say, "Hey, jon, and I'll use Pluralsight "as my password," and we'll click sign up. Ah, it says, "Cannot get auth/profile." Why? Because I left my slash off. I don't think we've talked about this, but that slash is important because it defines where you're going. Sign up, there we go. This is our user. So, our user was created, and a whole lot of stuff just happens to flow through all of that. Because here we took our req.body, jon, and Pluralsight. We logged in, and then we redirected. Which means then Passport shoved this user into the session. When this auth/profile get request came it, it pulled that user back out of the session, and then created that user, this user that we have right here, it added it to the request and it moved on. So, if you're here, the plumbing works. And I wanted to make sure your plumbing worked before we got to where we're dealing with Mongo. So now, if you've got this piece, everything's working. Now, let's actually go through the motions of getting a user created.
Creating a User
All right, now that we have this post working, let's actually go ahead and implement the Mongo piece to get this user created. Now so far, we've got this post working where we have this username and password. And we're just going to create the user with those two pieces of information. There's no real reason to build out this big user object at this point, because it's going to be different for everybody. So, I'm just going to keep the username and password, and we're going to create our user around that. And so, when you post, I'm going to minimize everything again, when you do this post right here on line nine, what we want to do is add this user, create this user in the database, and then call this req.login. So, all the work we're going to do is right here on line 10. Well, it's where we're going to start anyway. There's going to be a whole lot. So, right here we've got req.body, and if you remember, req.body includes username and password. And so, we need to pull those two things out. So, the first thing we're going to do is pull username and password out of req.body. Then we'll pull in our Mongo URL, because we're going to need that. And we'll pull in the database name. Same things we've been doin' all along. And then we're going to create our async function. Always create it like this. Just a helpful tip because nine times out of 10, no, not nine times out of 10, but often, you'll forget this other trailing pair of parentheses. I always, always, always create it like this and then fill it in. It just makes my life easier. I'm going to call this function addUser, because that's what we're doin'. Now, what we want to do, first things first, is create our client. And then we're going to do our trycatch. And then we're just going to do all this stuff we normally do. So, we've got to open our connection. And then let's go ahead and throw our debug out that just says, "Hey, you connected to the server." I like to have that just because it shows, hey, things are happening. Then we're going to connect to our database, library app. And then we have to connect to our collection. Now, up till now we've been using this books collection. We don't want to put this in the books collection. So, let's put it in a new collection called users. And this is just another one of those cool little things about Mongo, or terrifying, depending on who you are, that says, "Look, I can create a new collection just by using it. "I don't need to do any extra work." So, let's create a user with the username and password. And before I go nuts, I'm going to add my space right here so that all those red lines go away. It is a little funny that eslint to get ahold of you just throws all of this stuff at you and then goes away when I just do that. So, I've got my collection open. I've got my user created. Now, we need to do an insert. And we haven't done an insert yet. All we've done so far is reads. We've pulled things out. Well no, we did do an insert, remember? We did an insert in our adminRoutes. Here we did an insert of many, and then we just dumped the response back. Well, we don't want to insert many. We want to insert one, but we still want the results. So notice, I've got insert, insertMany, and insertOne. I'm going to insertOne, we're going to insert our user. Now, what that's going to send us back is a big object. Let's actually look at it. And then we'll add something here just in case. There we go. Now, let's save it, let's just stop right here. Now, it's going to die because we're not doing anything, but let's try it and see what we get. We'll pull this back up. Okay, so now, when I click sign up, let's pull this terminal window back over here, we used this a little while ago. If I do a db.users.find I get nothing. If I click sign up, it's going to give me my Pluralsight. And the reason why it did that instead of just spinning is because I went ahead and called my req.login down here. So, this happens, it went ahead and worked. It didn't wait. So, just async, only asyncs to this point. Req.login was still down there, so it still worked. But here's what I got back from the database. I got kind of this big thing. If you click the little caret, it's huge, it's this big, long thing that said, "Hey, you got a CommandResult, "your connection information." And then right down here, you have this thing called ops, O-P-S, that is you're username, password, and then that id that we want. When I come back to my terminal and I do db.users.find, there's the user I just inserted. So, what I actually want is this ops and then the first item in this array. So, if I pull this back down, what I'm going to actually use in my req.login, let's delete that. I'm going to come up here to my debug results and there I'm going to req.login. And we're going to do results.ops sub zero. And this is now going to be the user that is created. Now, I'm going to save that and it's going to restart. Now, one important thing that I'm going to call out right here is that every time the server restarts, this goes away. And the reason for that is this auth profile is stored in a cookie, in a session. And every time my session restarts, or every time my server restarts, this cookie goes away. So, if I go to slash profile right now, it's empty because my server restarted. Let's create a different one, I'll click sign up. And now, what you'll see in my profile is I've got my id. That means this user was inserted into the database. We're kind of there. That's some pretty good progress actually. We have our user being created. Now, what we want to do is use our local strategy to pull up out of the database and authenticate our user.
Sign In
All right, now that we have our user being created, the next piece is equally as important. Let's actually sign in. So, what we're going to do here is we'll create a sign in form and we'll validate our login, and then sign in. We'll actually start using a little bit more of Passport as we do this. So, if we stay in authRoutes, we'll minimize some of this for right now. Right now, we have sign up, and we're posting, and that all works, that's great. So, I'm actually going to just minimize that. We've got our profile here, which is great. What we don't have is a sign in. So, let's just do authRouter.route signin. I'll format this and then now we're going to minimize it. Now, what our signin route's going to do is actually display a sign in form. Right now we've got our sign up form, we need a sign in form. So, we've got a .get, and then what this is going to do is just render a sign in form. And we're going to send to that nav, so we're passing it in, I'm just not receiving it. So, there's nav. We're going to send it nav and our title. Now, I know that doesn't exist yet, but we'll create it in just a second. And then we'll take a .post, as well. So, we're not going to create the post yet, we'll create that in just a minute. First, let's actually implement this sign in. So, we need to render a sign in form. So, if we come down to our views, what we're actually going to do is let's just copy and paste our index. And then we can actually rename this signin.ejs. Now earlier at the very beginning, we had an issue that we fixed in our bookView of having slashes in front of our css and our JavaScript down here at the bottom. So, we didn't fix those in index because it didn't matter, but now it will for this. So, let's go ahead and put those slashes in there. So, just in front of this js bootstrap, and then up at the top css bootstrap and css styles. Now, that we have the file, let's come down here to our sign up form. And actually, let's call it our signInForm. Change that to signIn. And then we're going to auth/signIn instead of signUp. Everything else can stay the same. We're posting to sign in, oh, we need to change our submit button. On index, we actually need to add a link right here, or sign in and we send it auth/signIn. So, let's save that. Let's save our authRoutes. Let's come back over here, refresh our page. Now, we have or sign in, let's click sign in, and we can't get auth/signin. So, let's look at why. Auth/signin 404. Ah, the slash, whenever you're creating a new route, if it's not working, oftentimes, it's because we forgot that slash. Let me refresh. Now, we have our sign in page. Jon and password, I'm going to click sign in. Oh, I can't post. Because we haven't created that yet. But I'm posting now to auth/signin and so that's all working. Okay, let's go to our authRoutes, minimize things again. Now, what we want to do is when you post to sign in, we don't care about what you're posting, because that's not our business. It's got to be Passport that deals with that. I actually want to post to Passport, and then have Passport deal with everything that's goin' on. And Passport has this thing, passport.authenticate that will deal with that for us. And so, the first thing we have to do is come up here and include that. And then we have to tell Passport what we're doin'. Now, if you're signing in in this case, what we want to do is use the local, as opposed to the Google, or the Facebook, or the Twitter. We want to use the local strategy to authenticate this user. And then if it works, we're going to say, "Hey, on success, redirect to my profile. "If it fails, send it to just slash." Okay, so I've got my post figured out, that's going to go. We've got our sign in goin'. There's one thing we've got to fix, is our localStrategy returns a function that does a passport.use. When we pulled it in, I just pulled it in here. We didn't execute. So now, I'm executing it. So, what's going to happen now is when I sign in, I'm going to send information to my localStrategy. And so, let's take a pause here and in the next clip, we'll build out our authentication strategy in this localStrategy.
Validating User
Now that we have sign in there and posting, let's actually set up our validation so we can log a user in. Now, all of this work is going to be done in localStrategy. So, I'm actually just going to close everything else. Now, what we want to do when a user logs in, right here, when I'm pass this username and password, I'm going to go into Mongo and I'm going to figure out everything from there. So, a lot of this you've seen before, so I'm going to kind of go quickly through it. Now in this case, when we're debugging local.strategy. So, I just dropped some code in here that we've typed a ton of times, URL, our database name, our iffy with our async function. We're creating our client. We're opening our connection, db.name, which is libraryApp, our users collection, all that. Now is the point where it actually starts to be different. So, kind of type all this stuff. I'll scroll so you can see it all. But it's the same code we've typed a whole bunch of times. But what we're going to do now is let's actually go find the users. So, this is sign in, so let's find the user associated with the login that we just had posted to us. So, let's say user await and we're going to findOne. And in this case, what we want is something with username. And remember, we can shortcut, it would look like that, but we're shortcutting it to just look like that. Okay, once we have that user back from the database, and because we did a findOne, we don't have to do the ops sub zero and all that. It just hands us back the first one. So, we say, "Hey, if the password "of the user we just got back matches the password "that got passed into our function up here," remember down below the way this worked, we passed no for error and user for the user. So, up here if it works, we're going to say, "Done, "no for the error, and user for the user." If it fails, we're going to pass still null, 'cause guess what, it didn't error, it just failed. And we're going to pass false for the user. Clean it up just a little bit. There we go. So, if the passwords match, it's going to pass. If they fail, it's going to fail. And what that means is if I come back over to my authRoutes, if it's successful, we're goin' to profile. If it's fails, we're goin' to slash. All right, so let's save that and let's see what happens. So, jon password, right down here, jon Pluralsight, or Jonathan pwd are my options. So, jon password isn't an option. So, if I click sign in, I get kicked back 'cause it failed. If I type jon Pluralsight and I click sign in, I'm getting taken to my profile and there's my id. So, that's how that works. The localStrategy says, "Hey, I'm just going to, "you're going to hand me username and password, "I'm going to pull it out of the database. "I'm going to deal with it. "I'm going to validate it. "And then I'm just going to drop a user on the request, "so then I can just say req.user at the end." So, that gets us to where now we have a user, but how do I protect my routes. So, I don't want you to go to profile if you're not logged in. How do I do that? So, in this next clip, we'll finish this module off with how to protect your routes.
Authorizing Users
Now, let's talk about how to protect our routes so that you can't get certain places unless you are allowed to. So, let's start with our authRoutes. You should be able to get to sign in if you are not logged in. Either of those routes is fine. Profile, on the other hand, I don't want you to be able to get to it unless you're signed in. Because profile will be empty because I'm just sending back the user object. And the way we do that in most cases is with some middleware. So, I'm just going to say, "Hey, execute this function "every time somebody tries to do anything "to /profile, req, res, next." And here, think about it just for a second. If a user is not signed in, Passport won't put a user object on the session. So, if there's a req.user, I'm good. If there isn't, I'm not. So, if req.user, call next, otherwise, res.redirect. And now, my profile is protected. If I save this, it's going to restart my server so I am automatically not logged in. So, if I hit profile, it'll redirect me back here. If I do log in, though, I can go here and I can get there. So, that's working. What about books, though? So, if I go to book, I can see all the books. If I click read more, I get the one book. What I want to do is protect all of books. You can't get to books at all. Both the id and the slash total if a user doesn't exist. And the way we do that is we just attach something right on the bookRouter. We just do a bookRouter.use. The same way we were doing app.use, we can do a bookRouter.use, and just append our middleware here. And then we do the same thing, what we just did in authRoutes with this, we're going to do right here and save that. Now, because I saved it, it kicks me out. It logged me out and I hit book. We go to books, I can't get there. I do jon Pluralsight, it logs me in. I go to books, now I can get there. So, the way you authenticate everything is just with doing checking for the user and checking to see if they're valid. Now, you can authorize even more by saying, "Hey, if req.user.admin, or .roles includes something." Because if you remember in our localStrategy, we're just pulling the user out of the database. So, if you append roles or whatever to that user, it just works. One thing I'll challenge you guys to do on your own is institute log out. I was restarting the server in order to log out. I will tell you if you do /logout right here, same place, same where we do up here, we just do req.login. There's a req.logout that will sign you out. So, if you institute a logout button, you just call req.logout and that deals with that for you. All right, that's it for Passport. Now, let's go and finish this course out with a talk about third party APIs.
Summary
All right, we made quite a bit of progress in this module. And now, we're kind of starting to look like a real application. We've built out this web application, this library application, that's going to hold some books from a database, display them on a page. In this module specifically, we instituted Passport, which handles all of our user authentication. We created some users, then we did authentication, where we logged in and we used the local strategy to validate the user and then create that user object in our session. We also did authorization just by checking to see if the request had a user on it. And if it did, great, if it didn't, then we kicked you back out to the home page. This next module, we're going to wrap up by talking about how to make third party API calls. And we'll use a package to help deal with our HTTP requests.
Structure and Third-party APIs
Introduction
All right, we're going to round out this course with this last module, and we're talking about a couple different things. We're going to talk about the structure of our code, and we're doing that on purpose, because we're going to build on some services for some third party API calls. Alright so, we are almost done with this course of building a web application and if you've made it this far, which you have, because you're listening to this then great job, you've learned a lot and we're going to round this out by talking about some code structure. Right now, everything's in one file. Like all of our routes have all of our code in them, and that's not very testable. It's not very easy to deal with, and so we're going to talk about how to pull those things apart, and implement some controllers, and our controller is what's going to have all of our router code built into that. We're also going to build some services, or specifically, a third party API service. So, we're going to hook up to Goodreads, which is a website that deals with books, and we're going to pull information from a Goodreads API to populate our web page.
Controllers
Alright, we're going to start off by talking about controllers and implementing some structure to our application. So we're going to go to our book routes, and I'm going to minimize everything. And if you look at, like our bookRoute. Look at all of this stuff. So if I were to ask you, just by looking at our routes, what routes does bookRoutes handle? Like, what does it do? It's actually more difficult to figure out than you might think. So we've got a dot get on slash, we've got a dot get on colon ID, that's it, but over on our authRoutes, we've got a dot get and a dot post here, and it actually isn't as simple as just looking and seeing what's going on. So what I want to do is try and simplify this just a little bit. Now we're going to institute this concept of a controller. So let's come over here first. Let's come right here and say hey, we're going to have this thing called a controller... Coming from controllers/bookController. And we're going to move all of this code into this bookController. So let's come over here. Let's go up to our source directory, create a new folder called controllers. Rename that to be controllers, and then create a new file called bookController dot js. Now what bookController's going to do is be a function. And then we're going to export it. So what, but bookController's going to do is just be a series of functions. It's going to have a function called getIndex, and a function called getById. And these functions that the controller has are going to substitute for bookRoute and the colon I'd here. And we're just going to replace this with that. So basically all we have to do is we take this function, everything in this dot get right here, and cut it, and drop that right there. So basically all I did is I took getIndex, fix our spacing, is take getIndex, from inside this get, and just created a function over here. Alright now let's wire that up. And there's a few things we've got to do to wire that up. First and foremost, we need nav, right down here, so let's pass nav in, into our bookController when it's created. And so down here, right inside our router function where we have nav, we want getIndex. Let's execute this function. Execute the bookController function, pass in nav and then we want to pull getIndex back. So now we're passing nav into bookController right here, and what we're expecting back is an object with this getIndex in it. Right now, getIndex is just a function. I'm going to minimize that, and minimize getById and come down here and we're going to use that's called the revealing module pattern. And what the revealing module pattern is, is I've got a function with a whole bunch of functions in it and I'm actually going to return an object that has the two functions in it and the reason why we do this is when all our codes here, if you don't have code folding, 'cause not everybody does, you just scroll down to the bottom and say hey look I've got my two returns, or my two functions that this returns. This controller handles getIndex and getById for the bookRoutes. You'll see debug is red ungular squiggly 'cause we don't have that, and Mongo is red ungular squiggly 'cause we don't have that either. So let's add those two things from bookRoutes. We don't need ObjectID yet, but we will. And then we'll change our debug, instead of bookRoutes to bookController. Alright, now what that does, is now I have a function. So let's think about this for just a second. I have a function that takes a req and a res, and just looks at rec dot body, and actually this one doesn't even look at rec dot body, and just calls res dot render and passes some stuff into it. So this is actually very testable. I can just test bookController and pass in res and actually have mocha course out there that covers testing of all of this stuff. So once this is done, pop over there and watch that course to learn more about testing with these. Okay, we're going to save that, bookRoutes. Now, all we need is to use getIndex, just like that. Now the slash id, we pull that out, we just copy everything from there or cut everything from there, come over to our bookController, scroll down to getById, and paste. Get rid of our, we're not doing an arrow function anymore, so get rid of that. Other than that, that's it. Let's save it. We'll save this. We'll say hey, getById. We'll pull that out, too. Alright, now I'm going to save. I restarted. If that works, then everything's working, and actually you'll see our debug stuff will change. I'm going to change one more thing while we're at it. I'm going to comment all of this out. We're going to save that. The reason for that is, I want to be able now, at this point to go to this book, and have it work because if I left our middleware there, that was protecting the books, then it's not going to work. Now look. Now I have my debug stuff coming from bookController. So we move, we didn't write new code. I mean hardly at all. We wrote a few lines. For the most part, we just copied everything over into bookController for bookRoutes. And actually let's just pull this out, too. Let's just call it middleware. Now we're drop our middleware over here, and our bookController down here at the bottom. Let's create a new function called middleware... And return that. Save it... It'll restart. Now I got a book... Go to read more, and everything still works. But, now when I look at bookRoute, my router code, especially when I get rid of these two things that I don't use anymore, it fits on one page. I can say hey, slash does getIndex and slash colon id I just do a get on both of those. And that's all they do. So that's a controller and that's the idea of controllers in our application. It was a pretty quick little look, but I wanted to give you that idea, because now we're going to do the same, basic idea, but for services, so we can make a third party API call.
Goodreads API
Now chances are, your application is not going to be standing alone. You're going to have to call other APIs or other services somewhere else, and so I'm going to walk you through an experience of how to deal with third party APIs. And we're going to use, in this course, the Goodreads API. And if you go to goodreads.com/api, you're going to get this page. And the first thing I want you to look at is, up here at the top, the developer key. If you click that, I have a developer key all set up. Now, don't copy this because I'm going to click this reset and it's not going to work and then you're going to be sad. But, if you click that, go and create your own developer key, so that you can start to play around with this API. You can play around with this page without a developer key and that's great, but for our stuff you're going to have to have one. What we're going to do for this, is try and fill in this read more on War and Peace. I want the details of this book down here and maybe the book cover as well. And so the API call we're going to use for that is show. So if you scrolls down books dot show and you click on that, this is going to hand us back all that information, and we click on sample url, and basically you get this XML response. War and Peace just so happens to be 656, and we want this right here. This detail here and then there's our image and we want to deal with this stuff, and so notice the call. Just goodread.com/book/show, the id of the book, and then the key is the developer key that we need to have. In this case it throws one in there just for show and for playing around, but you'll want to go create your own on top of that. So this is what we're going to do. We're going to make an API call. We're going to pull this data out of the book, and then we're going to display it on our webpage.
Services
Alright, so the way we're going to deal with this API is using a service, and when I say service, what I mean is kind of like what we did with a controller. I'm going to come out here to our application and I'm going to close everything, except for our bookController just to fix our open editors, and I'm going to create in source a new folder called services. And under services, I'm going to create a new service, a new file called goodreadsService dot js. And we're going to put stuff in here. Now what we're going to put in here, let's talk about. Let's actually build all the other pieces first, and then we'll come back and we'll fill this in. So if I come back to my book controller, what I actually want to do. Let's go to bookRoutes first, actually. So if I go to my bookRoutes, where I create my bookController, let's actually pass in this goodreadsService. And it's dot dot slash, because we're moving up to services slash goodreadsService. Now the reason why I called a bookService instead of goodreadsService is because I may change that. I may use a different API at some point, and I only want to have to change it in one place and here I'll have to change my require, but if I just use bookService from here on out, I won't need to worry about it. Okay, so then in my bookController, I'm going to pass in my bookService. So we'll save that. Now let's go to my bookController, and hey, now we're getting a bookService here. And what I really want to be able to do, in my controller, is down here, I want to say, in my getById controller, after I do everything from Mongo, I want to come down here and add some details from bookService dot getById. So I want to create a thing that has a getById on it, and I'm going to pass it the id and it's going to hand me back some details. And then I'm going to use those details later on. So let's implement that, and the important part is I'm awaiting. I'm not using callbacks, I'm not promises, I'm not doing, I'm using a wait, because I want it to fit nicely in with our Mongo db stuff. And so let's talk about how to implement that over in our goodreadsService. And it actually really is fairly simple at this point, because all a goodreadsService is is a function. It doesn't even take anything. And it has one method. And I'm actually going to call it getBookById. So let's come back over to our bookRoute or our bookController, and change it to that. And then we're going to return that function. Now what this function has to do, is return some details in a way that a wait's going to work with it. And node's pretty cool in the way this is done because really, it converts promises to something that uses a wait. So if I just return a new Promise here, that's going to work. Just return new Promise. I now can use a wait. So with a Promise we have a function that receives two parameters: resolve and reject. And in this case we're just going to resolve. We're going to add a description, our description. Now this function needs a name. Let's call it goodreadsService, and then we'll export it. Okay, now we don't need anything passed in. This goodreadsService just works. We're not passing anything into it. And so instead of, over in bookRoutes, where it pulls in the bookService, I was looking in controller. It's not in Controller, it's in bookRoutes, where I'm requiring it, everything we've done up til now I've had to execute. I'm not going to do that this time. I'm going to go ahead and execute it here. And so I'm going to just return this object with getBooksById. It's going to work just fine. It'll be great. So I'm going to save this. There's one piece left. Now, if we look at our controller, I'm going to pull the book out of the database and then I'm going to add this book dot details. And on the details, I'm returning a description. So let's copy that and let's go to our bookView dot ejs. I'll minimize this. I'll scroll down to right here where we have our book dot author, our book dot title. Inside these Brs right here, let's go book dot details dot description, and we'll save that. Now if I refresh this page, I now get our description coming from our service. So bookRoutes, or the bookController added this thing and added to book dot details that did all that work for us. So the book goodreadsService just created this object for us with our description that now flows through. And despite the fact that I'm returning a promise, notice in bookController, I didn't have to do a dot then on the end. I used a wait. It was great. Now, let's actually like wire up to the Goodreads API and pull something real back.
Making API Calls
Alright now let's actually go make that API call and pull that data back. Alright, so in order to do this, we need a couple of things. The first one being, we're getting XML back. So show/656 XML. We're going to get XML back. I don't want to deal with XML, I want to deal with JSON so we're going to use one tool for that and if you watched the previous version of this course, we used HTTP. I don't want to deal with HTTP either. We're going to use something called Axios. And so let's go to our goodReads service. This is all we're going to work in so I'm going to close everything but the goodReads service, I'm going to minimize this. Let's pull up our window, and in here let's do an npm install. We're going to use something called Axios, and we're going to use XML to JS. And once those are installed, if I come back over here to my package dot JSON, notice xml2js is four dot 19 and Axios is 17 dot 1. Those are the versions that we're using. Okay, so let's come back over to our goodreadsService and let's pull these two things in. Okay, xml2js and Axios. And then let's go ahead and pull in debug, and in this case we'll use goodreadsService as our app, so just kind of whatever the file's called, that's what we stick in there. Alright, now what we want to do, and this becomes very easy, is inside our promise, we're actually just going to do an Axios dot get. Now, I could do the await stuff just like I have. I'm not going to here. I'm going to actually do a dot then and dot catch. We're just going to use that the way it should be. So for right now, let's actually just pull this right here. 656 it gets us back what we're lookin' for. Let's just do an Axios dot get for that. Once that comes back, we do a dot then. And if it fails we do a dot catch. Let's actually implement the catch first. Hey, if something goes wrong, we're going to reject and debug the error. If everything goes right, we're going to get a response. And what we're going to do with this response, is now deal with the XML that we get back, and that's where this xml2js comes in. So we're going to create up here at the top, a Parser. And Parser is just a function that we execute, it's going to create a new Parser. And we're going to pass in one thing: explicitArray equals false. And the reason for this, is because xml2js by default make everything an array. So if just one item is on the XML document it creates it an array and so it makes it just painful to deal with so you turn that off by setting a default. Okay so what we're going to do down here, let's look back at this document we get back. Notice we've got a goodreads response. We've got the request and then we've got a book and so all I want is the goodreads response dot book and that gives us the book title, the book image URL, and the book description. Those are the things we want. So if that works, we're going to do, we're going to parse that with our Parser. And it does this asynchronous thing, so in a true callback style. We're going to send the data over here, and then we're going to add a function. Now in true node style, we haven't done a lot of this so I'm going to kind of explain it again, we have error first and then the result. So you always check the first thing for if it's an error, otherwise you go with it. So, if error, we're going to debug the error. Otherwise, we are going to debug the result just in case something goes wrong, we can kind of see what we're doing. And then, instead of down here we resolve this, now, I'm going to resolve the result dot GoodreadsResponse dot book, and we'll save that. Okay so we did quite a bit here. We did a get to the 656, so we're hard coding that for right now. I haven't pulled in an id yet, although we will eventually. So let's go ahead and stick that there. And then we're parsing our response, and we're resolving our promise with that. So that means when we come back over to our bookController, we're taking whatever gets back and we're dumping it in book dot details. So let's look at that and see if that worked. I come back over to library and I refresh. I now get the full description in this big text. I also have this image URL, this image URL right here. Let's see if we can't drop that right there. So let's go over to our bookView, and here we have our image. Minimize this so we can fit it all on the screen. Instead of this source right here, I now want it to be book dot details dot image_url. Let's save that, refresh, and see if it worked. There you go. Now I have my War and Peace. Now we can fix it. We've got a class of image circle. So there you go. One thing though. We haven't talked about this yet. Let's talk about it now. Notice the Brs and the is and all of this stuff everywhere. That's because EJS by default escapes everything and that may not be necessarily what we want, especially in this case. I'm getting HTML back and I want to show it. So let's fix that, and the way we fix that is instead of this equals, we just use a dash. And the dash will eliminate the escaping of these HTML characters, so if I refresh, now we get what we were looking for. Okay, so we're almost done. It's almost working. Let's add the id in here and then we'll be done.
Passing the ID
So right now we have it hard coded. If I come back over to books and I go to Les Miserables, hey look, we're still getting War and Peace. That's because we have hard coded the id in our goodreadsService to be 656 and the reason for that is because we don't have the id in our database. So if we go to adminRoutes, and we look at our book lists, we need our id in here, and so I'm actually going to add a book id. War and Peace with 656, and we'll add one more. Let's do Les Mis as well. And you can take my word for it, you can go out and look, but, the book id for Les Mis is 24280. And we'll just save those two. You can fill in the rest if you would like to, but let's just save these two for right now. Now I've got 'em here, if we come back to our terminal. Let's drop our database. There's a little bit of a safety here, because it says right here, remove needs a query. Oh yeah, so you don't accidentally remove everything from your database, and actually it's a good thing it did because I don't want users, I want books. Oh good. Okay, so let's give it a query. So I said there was a little bit of a safety. It's not a lot of a safety, because I just dropped everything in books. Alright, so now that I'm here, let's add 'em all back. Now I've got book ids for War and Peace and Les Mis. Now we can double check. Yep, bookId, bookId. Alright, so now what I want to do, is in my bookController, here I was passing in book dot bookId, from getBookById. It's already there. I'm already passing it in, so let's go to my goodreadsService and use this Id. Now there's one last feature in VS6 that we're going to use that we haven't talked about yet. A string templates. So see the difference between the regular single tick and the tick mark that's kind up above the tab key. It's next the, on the same key as the tilde. Now notice everything turns this orange color. That's because the string template wraps everything and keeps your formatting and so the reason why we like the string template, is because it used to be I would have to do tick, plus, id, tick, plus, tick, and I don't want to have to do that. Instead what I want to do, is that: a dollar sign and then curly braces on either side. Now I can pass in id and that's going to work. So let's save that, come back over here to books, and see okay, let's click on Les Mis, I got Les Mis, and I got the Les Mis. And then let's click on this. I got War and Peace and I got my War and Peace description. That's it, we've covered everything. You should have all the pieces now to try and get this working. Let's sum everything up real quick.
Summary
Alright, that wraps up the whole course, actually. We're done, and just to summarize this module, kind of what we did is we've built out a web application. We've got all the pieces working, everything's there, we've got users, we've got all the stuff. In this module specifically, we started talking about structure. We pulled controllers out. We pulled services out. We've got our code kind of starting to line up the way it should, by having everything be separate. If you want to now use those structures in order to test things, I've got a Mocha course that you can go look at to see how to test the things that we have. We built controllers and services that are now testable and they're stand alone pieces. We ended with third party APIs. We called the goodreads API to pull some extra pieces of data, the image URL and the description that we incorporated into our book. And that's kind of it. Hopefully you had a good time with this course. I had a good time doing it and I'd love it if you checked out a couple of my other courses as well.
Course author
Jonathan Mills
Jonathan Mills is a JavaScript and Node.js expert working mostly in the MEAN Stack with individuals and companies to help build their technical skills to cope with the constantly changing landscape...
Course info
LevelIntermediate
Rating
(60)
My rating
Duration5h 12m
Released23 Mar 2018
Share course