Home
Sign in Buy now

MVC & Application structure

Configuration and secrets

Completed
Master Fullstack Golang Logo

Watch for free

Create a free account to watch this video.

Start for free

Summary

In this episode, we set up environment-based configuration for our application using environmental variables and Go structs. We create a config package that reads values like app host, port, environment, and project name from a .env file, using struct tags and the env package to parse them automatically. We also establish global constants for development and production environments, add a method to generate TCP addresses from our config, and prepare our application to handle different settings across development, testing, and production environments without hardcoding values.

Transcript

Before we start configuring our server and see the results of our work, I want to introduce a way so we can configure certain settings based on the environment that our application is running in. Right now our application assumes a few things: it assumes what host it should run on, what port to listen to, what environment is running in, and we've been hard coding some of these values in different places. I want a specific place that these values get set and defined so we can reuse them throughout the application. This comes in handy when we start to add more things like secrets like database credentials or hashing keys and things that we don't want in our source code. Right now the environment settings that we have are rather limited. We will be able to configure the app host, the port, the environment, and the project name, and this will all be done through environmental variables. Now for the unfamiliar, you can think of environmental variables as pieces of configurations that live outside of your app in your operating system. They let you change settings without adding the code, and this is very useful when we go from development to testing to production. So for example, on your own computer you can have environmental variables set in your terminal. The environmental variable that we should look for is going to be uppercase APP underscore and then uppercase HOST. Then we can copy all of this, paste it down here, and then we just need to change HOST to PORT. So we have added these struct tags that specify a different name compared to the field name, and this is more of a convention, but it's also to tell the parser that we're going to add in just a second the name of the environmental variables it should look for. So now let's specify a new function here so we can actually create a config. Say config or error. Say cfg, which is just config for short, create an empty config struct. Then we're going to be using a package now called env where we can say pass options. You're going to pass a pointer to the cfg variable, and then we're going to say env.options. It's just going to be empty for now. Close that, and if the error is not nil, simply return the error. And if we have no errors, we return the config and nil. I'm going to give that a save, and we're going to have an error here because we're going to be using this package from Carlos Zero called env. So let me just add this to our go.mod file, and if I restart the LSP, it should go away. Great. And of course we also need to return an empty config struct if there is an error. Now this package is really really handy, and we can specify options like if an env variable should be required or not, so that we actually get an error if it can't find that env variable so we don't start running our application without all the expected environmental variables in place. Now we have set up our config struct with app host and port, but I also mentioned that we wanted to have environment and project name. These values are used throughout the application and sometimes in places where it can be awkward to pass an argument, like in our views for example. Therefore I tend to make these global in a sense that we simply expose them directly through the config package. Now you should not use globals as a general rule of thumb—they make the code harder to test and they can change unexpectedly. In this case we have a limited set of values and we can provide sane defaults, so we're not really risking shooting ourselves in the foot. For everything else like host, port, database credentials, whatever, we will stick to the config struct so values are explicit and testable. We have two environments: we have development and we have production. So I want to make sure that we have these as constants, and we can then check against these variables or values throughout the application. So I'm going to say const dev environment equal to development, const prod environment, and it's going to be equal to production. And then I want to use this get env method from the OS package to look up the value, and then we're simply just going to return the dev environment if it's not set. So to do that, we're going to create a variable that's going to be called env. Consider that equal to our function that returns a string. We're just going to immediately call that function. So if OS get env, and it's going to be environment, in all other cases that's not equal to an empty string, then we simply return that value. And if not, then we're going to return dev environment. Give that a save. And now we can do the same but for project name. So I'm just going to copy all of this, paste it below, say project name, project name, there we go. And here we can also provide a default. If you don't want this to be called Leading Edge, for example, you can overwrite it, but we're going to be defaulting the project name to be Leading Edge. All right. Now, the final thing we need to do is we need to add a .env file that will hold these variables. And the .env is more like a convention rather than a requirement. You can call it whatever, but a lot of tools will actually look for .env files. That's why we are going to name it like that. So I'm in the .env file here, and we're just going to add the env variable. So I'm going to say export APP_HOST. It's going to be localhost. Then we're going to say export APP_PORT. I'm going to set it to 8080. And then we're going to say export ENVIRONMENT equal to development. And then finally, export PROJECT_NAME. And I'm going to set it to Leading Edge. Again, feel free to overwrite this if you want the project to be called something else. Now, to actually have these variables in our terminal, we need to source them. And that is also why I have put this export keyword in front of the variable names. And this is because Go doesn't automatically load these .env files. Later on, we will add a tool that will handle this for us automatically. But for now, we need to go into the terminal and write source space .env. And then these env variables will be set in the terminal. And finally, I want to show you one more benefit of having all of our environmental variables live on a struct. And that is we can add methods to this struct to make our life easier. For example, we are going to be needing a TCP address that we are going to use for running our server. And that is going to be a combination of app host and app port. So to do this, we can simply just add a method, config, and say get TCP address. It's going to be a string. And now we can return fmt sprintf. We're going to say %s:%s. And then we're going to say app host and app port. Give that a save. And now we have everything in place so we can finally configure our server and our entry point and start actually running this application.

Episode Notes

Get the Full Course

Unlock all episodes and get lifetime access to course updates.

What others say

"With this course, I'm learning Golang + datastar while building my personal blog hitting several birds with one stone. It's a fantastic course."

Testimonial from ignacio
Ignacio Barceló
Bought Early Access

Video Completed!

Great job finishing this episode

Up Next

MVC & Application structure
Testable entrypoint