Check out a free preview of the full API Design in Node.js (using Express & Mongo) course:
The "Exercise 6" Lesson is part of the full, API Design in Node.js (using Express & Mongo) course featured in this preview video. Here's what you'd learn in this lesson:

In this exercise, you will be loading the envConfig variable with the correct configuration data based on the environment. You will also be properly configuring the routers. Before beginning the exercise, Scott briefly walks through the application architecture.

Get Unlimited Access Now

Transcript from the "Exercise 6" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Speaker 1: So if you will join me on step six.
>> Speaker 1: Boom. [LAUGH] There's a lot of stuff going on here so I'm just gonna, I'm gonna walk you through it before I set you loose and explain to you what you're really gonna do. Cuz there's a lot of stuff in here.

[00:00:22] If you want to look at some of this stuff, I encourage you to. But, a lot of stuff in here, we won't be touching. So notice that a lot of stuff has changed. We now have this, well we had this server folder, but now inside this server folder we have an API folder, a config folder, a middleware folder and a utility folder.

[00:00:37] A lot of stuff. So let's just walk through it. The first thing I'm gonna do is look at server.js. Or actually let's look at index.js and see what changed. So index.js has got some stuff in here. There's nothing you're gonna do in here, but I got a lot of comments on what's going on and what's changed and why I'm doing certain stuff.

[00:00:57] So really what's happening in here is I'm just requiring this config. We'll talk about config later. We talked about this on the last step why we exported the app. I'm doing the same thing just importing the app like we did on the last step. This logger thing we'll talk about that in a minute.

[00:01:09] And then I'm just listing on the server. The only difference is before we hard-coded the port in here. This time we're getting a port from whatever the config says the port is. So again this is why it's nice to have this config object that we don't have to guess what's going on.

[00:01:23] If we just put config.port there we'll leave it up to config to determine what the port is and that can be dependent on some hard coded value in the config or some process.environment.port or whatever. And then the logger we'll get to it in a minute it's just a wrap around console.log that can be turned on or off, that's all that is, and it like changes the colors and stuff for you.

[00:01:47] So then we're going to server js and this is where it gets kind of confusing cuz a lot of patterns we haven't seen, I'll tell you about this pattern before but haven't really gotten into it. It's a very small file, but it's actually doing quite a lot. So just like before, we have express, we have our app, this is a router.

[00:02:06] I didn't call it API router cuz it just seemed redundant but that's a router that we've made for a line router or a tiger router, it's just the API, that's a router. And then this part is actually interesting. You notice I'm not setting a variable over here. There's nothing to the left of this.

[00:02:23] That's because I don't really need to. It's not returning anything. It's just a function that's doing something. So if you go look at it. Middleware app, middleware. It's doing what we already know. It's just setting up global middleware. That's all that it's doing. It just takes in an app and sets up global middleware on it.

[00:02:38] That's it. It doesn't return anything. That's why I have a variable to the left of it. It's just like, if you give me an app, I'll set up some middleware on it, that's it.
>> Speaker 1: So that's why that's there. So you can imagine all this just being over here.

[00:03:00] It's the same thing. Nothing's changed. I just put it in another file. It's the same thing. If I left this here, it would work exactly the same. But we only have three pieces of global middleware in a row. Applications you probably have like 15. So that's why I took it out.

[00:03:18] Cuz maybe it's a premature optimization but you will have more than just three, more or less. So I took it out and did that instead. So remember, this require is gonna require whatever this file is. This file is a function right? This is a function right here. It's a function so I immediately invoking the function and satisfying its argument, its signature, which is an app.

[00:03:50]
>> Speaker 1: Everybody follow me there, how it's just a function? It might be easier if I just did this, if I said Var setupMiddleware = require and then not do that. And then down beneath I said setup,
>> Speaker 1: Oops, set-
>> Speaker 2: [LAUGH]
>> Speaker 1: [LAUGH] App. It's the same thing, I just didn't feel like putting it on two lines.

[00:04:20] All right, so let's go back.
>> Speaker 2: There's a question on convention. When would you use relative path versus absolute path in node, is there any kind of rules for it?
>> Speaker 1: Right, so relative path for all required statements. Absolute path for file systems. Anything related to the file system, pretty sure it's absolute paths.

[00:04:44] And then I think that's about it, from my experience. There might some more other stuff out there, but mostly anything dealing with the file systems It's probably apps to pass and it'll tell you, it'll like log an error like that's not a real thing. And any piece of code that's interacting with the file system wants absolute paths too probably in my experience, unless the developer is nice enough to like not require that.

[00:05:16] All right and then right underneath that I'm just like all right let's set up our API so just like before we don't need that. So just like before, where we had we were mounting the tigers and the lions to the tiger router and the lion router, I'm doing the same thing.

[00:05:31] I'm mounting any request to /api to use the API router, that's what I'm doing, so same thing. So just like before, we had lions, so any request coming to lions use the lions router. That's what we had. That's the same thing. Anything that comes through API, use the API router.

[00:05:51] I'm exporting the app. So your first task in here is to set up error handling, some global error handling. So remember, error handling goes after everything else. So I'll just come in here and set up some error handling, so when we call next Inside of this router somewhere, it'll happen in here.

[00:06:08] Or if you want, because everything's encapsulated inside this router, you could also set up error handling on this router's Middleware stack and it will still happen. So it's up to you. But the reason I say put it there cuz if we add another API down here. You know it would be nice to have it at one place.

[00:06:25] So it's up to you. You can put it here or you can put it in API. Everybody following me so far? Okay. So now if you go into API. On the root there's an API.js. Again, I said I'm not using the index.js pattern because it's kind of confusing.

[00:06:39] But I probably would in my application. I always put index.js inside of here, that way I don't have to require API, API. I can just require API. But we're gonna stick with this naming convention for now. So inside of here you're gonna do a lot of work in here.

[00:06:57] So here's that router the API router that I've made but all this router's doing is setting up three other routers. So it's mounting slash users slash categories and slash posts which are the resources I said that we were gonna make, and it's expecting routers to be placed here.

[00:07:19] Just like with slash lions and lions tiger or lions router, just like we have here where we're saying slash API pass it to this router, it's doing the same thing, all right, slash users, pass it to this router. Slash categories pass it to whatever routers gonna go here, it's the same thing.

[00:07:38] So if you go look at the respective folders, the resources. You'll notice there's a routes file for each one of them with a router.
>> Speaker 1: All right. So there's only one thing, and its already been exported, so you only gotta do one thing to get it over there.

[00:08:12] Everybody follow me on there? The routers are already made, they already have their initial GIF functions so they don't air out when you go to them.
>> Speaker 1: So you'll be doing that. And the last thing you'll be doing is in the config folder. The config folder, there's a lot of crazy stuff going on in here.

[00:08:32] Just gonna walk with you, so Config.js is the root of the config folder. This is just like I was talking to you about in the example as far as what they config object is gonna do, so we have our config object with some properties on them. These properties are here, dev, test, and production.

[00:08:47] This is just me storing the name of the environment variables. So they're uniform. Cuz some people like to use test, testing, dev, development, prod, production, like, they like to use different terms. So I'm just like, if I just call config.dev, it would be whatever this is gonna be.

[00:09:03] I don't even know what it is, it's just gonna be this. All right, so this is just a way for me to keep things uniform. So I've set up a basic config object. This port right here, this is a convention. When you deploy this, the port that you're gonna listen to is probably gonna be this environmental variable.

[00:09:20] I know Heroku does this, I know AWS does this, it's gonna be process.env.PORT. Or, if that doesn't exist, then it's 3000. If you don't believe me when you start the server, just do an export before you start it, export PORT equals, and then put some number. That will be the port that you'll be listening to.

[00:09:37] And then we'll log it here. It will say on that port config.PORT.
>> Speaker 1: Okay, config.js, and then right here, I'm setting up the default environment. I'm like process.env.NODE_ENV is going to equal whatever it is, if i set it outside the context of this application like through Heroku, AWS, or on the command line.

[00:10:00] Or it's gonna default to whatever config.dev is which is development. So remember I said always default to development, just assume you're always in development unless you explicitly say you're not so that's what that is. That's why I have these strings here cuz I could have just typed in yeah just type in the string development, there's nothing wrong with that.

[00:10:19] But like I said sometimes these things, people mix these names up so if we have to use development somewhere else, I just didn't want it to be confused. So I'll just put config.development and you don't need to know what it is. Just know it's config.dev.
>> Speaker 1: And then I just set up the env.

[00:10:37] So I put an env property on this config object that's equal to whatever this is. Which if we don't set it it'll be development, so this might be development as well. But it could also be production, it could also be testing. It's just so I don't have to type in process.env.NODE_ENV every time I wanna see what the environment is.

[00:10:54] I can just say config.environment.
>> Speaker 1: Cool, so all that's done for you. So what you're gonna do, this is a big paragraph right here. EnvConfig is nothing right now. It's just a variable. But, if you look on line 26 you got some context. Here's what's happening. We're doing this merge.

[00:11:10] This is definitely an object cuz we just set it up here. And we wanna merge this object onto this object. But, the problem is this is not an object. It's nothing. So, what we need to do is depending on whatever config.env is, or whatever process.env.NODE_ENV is, load up the appropriate file and assign the the value to envConfig, so that the merge at the bottom actually works.

[00:11:35] So again what's happening here that we have a base config in this file. This is the base config, and depending on what ENV we are in, we then merge those objects. I'm sorry, we're gonna conditionally load up a file depending on what ENV we're in. If you look, there's a development.js, there's a production.js, there's a testing.js, tight, and if you notice, they're the same names as this, development, testing, production.

[00:12:04] So depending on what environment we're in, which is gonna be development by default, it's gonna load up one of these files, what's also is exporting an object. And this object is gonna be merged in with this config object, and it's gonna override its properties. So if these same properties existed, or any one of those other files objects like development.

[00:12:29] This object takes precedence, and it will override what's over here. And that's only because we placed it to the right. That's how merge works. If I put another object here then all of its properties will be merged onto EMV config and all of its properties will be merged onto config, that's how a merge works and it will cursively go down and do that.

[00:12:55] So that's how this should work. So now if you go back to nx.js the very first thing our server does is require this config. So the first thing it does is run config and it sets all that up. It'll set up the environment, it'll set up all the secrets, all the logging.

[00:13:12] All that stuff, good to go. So that's the first thing we do. So, that's why we have to do that merge and have to export it. There's one more file in here. This is just something I wanted to show you guys. This is a wrapper around console.log that I made so you can do logging, this will show you why or how cool a config file is so we can conditionally turn off logging or not.

[00:13:34] So this file's just a logger that wraps console.log, so, have a no op function, that is just short for no operation, this is a function that does nothing. This is common pattern in JavaScript, sometimes you need a function that does absolutely nothing, in this case we do. So, what I'm doing here, I'm saying this variable console log if config.logging is true.

[00:13:56] Then set it's value equal to console.log this is a trick that's just gonna return a function with the same context, or it's gonna be no op. So this is either gonna be console.log or it's gonna be a no op, but it's definitely gonna be a function. And then log all it does is it does some trickery it'll take in all the arguments that's passed into it iterate over all of them.

[00:14:18] If it's an object it'll convert it to JSON and change it to purple, all the strings. If it's not an object it will just still change it to a string and change it to purple. That's all it's doing. And then it will call console.log with the arguments or no op, this is either console.log or no op, you don't know all right.

[00:14:36] So there's some funky JavaScript stuff happening here. This might look new to people who don't have a lot of experience with JavaScript but that's all I'm doing. I'm just wrapping console.log, adding some color to it, making everything look pretty, making all the JSON indent right. Changing it to from an object.

[00:14:52] Cuz if you console log object in node it'll just say like, eventually it'll get tired of logging everything and just like this is an object. It'll just say object, right, it won't even give you the properties on it. But if you turn it to JSON it will, it'll go here's everything.

[00:15:03] But then it's just like one long string. So I indent it so it looks like a regular object. And I make it purple so you can see it.
>> Speaker 1: Cool, everybody got that. So if you run it right now, NPM start. Yeah, it's going to break because this stuff isn't here.

[00:15:27] So it'll break because you got to add that stuff. But once you add that stuff, you'll see how the logging works and all that stuff. Actually I can just do it right here. If I go to index.js, if I say, before the app, or I gotta come up here.

[00:15:45]
>> Speaker 1: Probably just say, logger.log('heeeyyyy')
>> Speaker 1: No, it's just breaking, it's not even gonna let me do that. So, yeah, you got to fix that. Cool, any questions on what you're supposed to be doing? If you're lost, for sure tell me, I wanna make sure I explain it to you correctly.

[00:16:07] So, at the recap, you'll be messing around with this config.js. Making sure you load the right file and then inside of API.js. Getting these routers in there.