Transcript from the "Dynamic Configuration" Lesson
>> Scott Moss: A config driven app. Basically in order to make this production ready and easy to work with there's some things we just don't wanna hard code in and we want to change the values depending on what environment we're in. So just like any service side framework or language you would use, you would have access to environment variables.
[00:00:19] Who here doesn't know what environment variables are? All right, so your code is executed in some environment on some computer, right, so Linux computer, in my case this computer right here. We can inject variables from that environment that's executed in our code into our applications, and we can reference those in variables.
[00:00:38] And those variables are live, so that's a good way to switch configurations based off environment. So, for instance, my environment is testing, I might have a different url for my testing database. If it's production, I have to put my production database in it because it's deployed somewhere. So you want to switch things like that.
[00:00:57] A really good example for service is the port. You have no idea what port you're gonna be on when you deploy the service somewhere. How do you know what port to put in there? Well it's coming from the environment variable. Whatever service or stack that's hosting your application, its job is to inject that port in the environment variable because it can probably change.
[00:01:15] Who knows what it's gonna be. So you would just listen to it from the environment variable. So we want to keep all the configuration in one place. It's also a great place for things like secrets and stuff like that. So you wanna use config values in a place of hard coded values in our app.
[00:01:31] So in our app I think we're hard coded in the DB connection urls, we're hard coding the ports, we do not have one secret. We don't really talk about it, but the authentication section has a JSON web token secret. That's hard-coded. We want that to change for production and stuff as well.
[00:01:48] So all those places where things need to change depending on where our app is deployed, we should put that in a configuration file. And then what we need to do is we need to generate that configuration file, depending on what environment our code is executing in. So we'll have a base configuration file, and from there it will require the appropriate production, staging, local, testing configuration.
[00:02:09] It will merge itself and then give you a configuration file you can use in your app. And then it has different values on it. So this is a better approach to building out APIs to build stuff on the fly and not locking yourself into mistakes and accidentally putting secrets in your git repo and all types of nasty things.
[00:02:27] So you totally wanna do this, take advantage of this. You can't do something like this on a client side because you can't inject environment variables in a client side. Any code you put in the client's gonna be in the browser, right, you can't hide it, it's gonna be there.
[00:02:38] This, nobody's gonna see environment variables. They're coming from the environment. They can only see the reference to it. So it's perfect for that. So that's what we're gonna use. So let's take note of all the places where we're hardcoding things, again, and then we'll talk about how we can create a configuration system around that.
[00:02:55] So one of the first places I know was in dbjs right here. It's a hardcoded url for Mongo database. If we deployed this, if we try to connect to this, it'll break. This will totally break, unless, for instance, you have your own Linux machine up in the cloud where you had your own Mongo instance created.
[00:03:16] Then okay, maybe it would work. But most likely, you're probably using some cloud DB or something that's being hosted somewhere else, through some VPC or something like that, and you need a different url. You're gonna use that right rail for that, so that's one. The other one is the main one, which is the port inside of index.js.
[00:03:33] This just says 3000. This is not flexible at all, so some configuration needs to be changed. And then the last place is inside of off.js, which is this secret right here. This needs to change, and then for extra credit, this disableAuth right here, this allows us to turn off authentication for testing.
[00:03:55] So for testing, this is hey, can you just not check authentication please, thanks. That's what that does. So we can set all this up inside of a configuration file. So the way that will look is if inside your API, if you were to create a, actually let me check out what's in this other branch.
>> Scott Moss: Lesson-7, okay. So we're on lesson 7, and, oop, let me check out today's solution.
>> Scott Moss: Do we check out [INAUDIBLE] okay. So cool, so if you're inside of here, your repo, the way I've been doing it is, like I said, I want to keep the configuration in one place.
[00:04:45] I want it to be dynamic so depending on the environment, it inherits and merges its properties based on those different environments. And it's solely based on that. So that I can feel confident that, hey, all I have to do is change the node environment to testing and I get a testing configuration.
[00:04:59] All I do is change it to staging and I get a staging configuration. It's pretty simple. So to do that, if you look, and you don't have to turn off the branch, you can just look at my code right here. We start off with a base config, something like this.
[00:05:10] So you have a base config. Where the first thing is, you can forget about this import, but the first thing is you wanna make sure you have the environment variable that you're gonna read from. For us, and Node, the standard is NODE_ENV. That's just what we use in Nodes.
[00:05:26] You inject the appropriate environment in which we are running our code in. So process.env. Notice that there's no variable here for called process or anything like that. And that's because, again, in NOde, your entire code just wraps in a function like this. So I talked about this before, right, but what I didn't talk about is what passed in here.
[00:05:47] You get some stuff that's passed in here. You get dir name, which is a variable that represents your current directory that you're in. You get require, which we use to require stuff, you get file name, and there's tons of other stuff in here. And finally, you get process.
[00:06:11] Process is this, so even though you don't see it in here, it's given to you at run time, Node, execute your code in a iffy, like this. That's how it creates modules, that's all a module is, a module's just a closure. That's all it is, so you just get a closure, it's just a scope, so that's where that process comes from.
[00:06:29] You also get this thing called global. I'm not gonna tell you about it cuz you just don't use it, all right? [LAUGH] Do not use global. You're like, yeah I'm just gonna put everything on global. No please don't, do not use global. So process is there. And we want the .env property of it and then the environment variable that we want is env.
[00:06:47] Node.env, so every environment variables you got on your computer you can read them in here. Go assessment variables and read them. You'll see, they'll show up right here. So we want the Node.env. So basically what we're saying here is, we're gonna set it to development if it's not set already.
[00:07:01] We're defaulting to development. That's what this is doing, right? Node_env, or if that's nothing than it's going to equal development. So that's the first step. And the second step is to create you baseConfig. This is default configuration, everything is based off this, here is my default for everything.
[00:07:17] So by default port is 3000, I don't have any secrets, [INAUDIBLE] object, my database has a url string that is just this local database. Pretty simple? Okay? And then what we do is, depending on the env, right here, depending on that env, what we're gonna do is we're going to load up the appropriate file that has its own configuration in it.
[00:07:41] So if you notice here, there is a dev file, a prod file, a testing file Depending on what the env is if it's development or dev it's gonna load up that file. If it's testing or test it's gonna load up that file. If it's production our project is gonna load up that file defaulting back to just f.
[00:07:58] And then it merges it. It merges the env config on top of the base config overriding what's on the left. And then now when we require this file we get a extendable configuration that changes depending on node environment, all right? All we have to do override that environment is when we execute any scripts, and for us, only one we have is start, is that you just pass in an environment.
[00:08:21] Notice right here, I have NODE_ENVE=testing. So if this was development I can explicitly pass it in but although we do default to development I don't have to do it. But if this was production I could do that, and now we're in production mode. It'll make sure the configure's production, the database url is production database url, the secrets are expected to be injected, all that good stuff.
[00:08:43] That's how you would do it. On your platform of choice where you deploy it they have somewhere in their options somewhere that you can put environment variables. If they don't, leave that platform because you shouldn't be using them. Every platform has that. You just put your environment variables in there and that's how you inject them and then you can change them.
[00:09:00] And that also means that because you have a configuration driven development. Let's say for some reason you have the wrong database url. Some reason, it's hitting the wrong database url. All you gotta do is go ahead change your environment variable. You don't have to redeploy cuz you're like, it's got the wrong.
[00:09:14] It says staging, supposed to be production. Change to production and you're done. You don't have to redeploy your whole app. You just change the environment variable. These are live. It'll restart your app, the service provider. But you don't have to redeploy. So you want to configure as many things as possible on your environment variable and not hardcode them cuz it limits you having to redeploy.
[00:09:34] It also allows you to change it on the fly. And it just makes sense logically. It saves you code, less if statements. You can put one if statement inside this config file. Or a switch statement in my case. Or you can put an if statement in every single file that you would ever need a dynamic value.
[00:09:50] So I'd rather just have one place where it has the switch and if statements instead.