Building command-line applications and handling system configurations.
full lessons here👇:
https://programmerscareer.com/zh-cn/golang-basic-skill/
Generated by AI, there may be errors, for reference only
Topic: 1.1 Command Line Applications
Building command-line applications or CLI apps allow us to interact with our programs in a text-based interface. This can be really useful for creating scripts, automation, server-applications, or when you are SSH’ed into a server.
In Go, you can write powerful and efficient CLI applications and Go provides several libraries that make it even easier. For our examples, we’ll be working mostly with the “os” and “bufio” libraries.
The “os” package provides functions and types for interacting with the operating system in a platform-independent manner. The bufio package is used for buffered I/O operations, which can help to make I/O operations more efficient.
Here’s a simple example of a CLI app:
1 | package main |
In this script, we create a new reader wrapping the standard input (os.Stdin), prompt the user to enter their name, read the user input until a newline character, and finally print a greeting message to the console.
Your task now is to try to run and play around with this example. The next topic will expound on handling command-line arguments in Go applications.
Topic: 1.2 Handling Command Line Arguments
Command line arguments can provide flexible ways for a user to interact with your program. They might specify inputs, configurations, or any other runtime options that your program can use.
In Go, these command line arguments are available via the os.Args
variable which is a slice of strings. Keep in mind that the first element in os.Args
(i.e., os.Args[0]
) is the name of the program itself.
Look at this simple example that prints all arguments:
1 | package main |
You run it with arguments like this:
1 | go run main.go firstArg secondArg |
And this will print:
1 | Arg 0: /tmp/go-build123456789/command-line-arguments/_obj/exe/main |
From here, we’re able to use the arguments in any way we’d like in our application.
Our next topic will focus on reading from and writing to the console, which helps to make our command-line applications more dynamic.
Topic 1.3 Reading from and Writing to the Console
As useful as command line arguments are, sometimes we need more interactive user input. This is when reading from standard input can be useful.
We’ve already seen an example of this in the first topic where we read a line of input from the user. Let’s explore this a bit more and start introducing writing to the console as well.
1 | package main |
This script first reads a line of input from the user, providing a prompt for the user’s name. After confirming the name, it prompts for the user’s age and reads an integer from the console. The read value is then used to display the age to the user.
Your task is to review this script, run it, play around with it, and think about other ways you might want to read from or write to the console.
Topic: 1.4 Environment Variables
Environment variables are an excellent way to configure your program’s behaviour based on the environment it’s running in. They can hold values such as database connections, API keys, or anything else that you’d like to configure externally to your compiled program.
In Go, it’s easy to read and write environment variables using the os package. Check out this simple example:
1 | package main |
In the sample above, we’re using os.Setenv
to create a new environment variable called NAME
. Using os.Getenv
, we retrieve this value and print it out.
Please note that environment variables set with os.Setenv
are only available in the current process (i.e., your program). Once the process stops, the variable will no longer exist.
These variables are especially useful for configuring values that change based on the environment your app is running on, such as local, staging, or production.
Topic: 1.5 Creating Config Files
The configuration of an application is just as important as the application itself. It helps us to adjust the behavior of our application without changing our code. Configurations can be injected in many ways, but for this curriculum, we will create .env
and .yaml
configuration files which are commonly applied in many applications.
Let’s start with .env
files first.
Dotenv files
In Go, a common package used to read .env
files is godotenv. Create a .env
file and put this inside:
1 | GREETING=Hello from an env file |
Then, create a go file and use this content:
1 | package main |
The godotenv.Load()
function loads our environment file, and os.Getenv("GREETING")
retrieves the value set in the env file. Run the Go script and observe the output.
Have a go at this and observe what’s happening. In general, .env
files are recommended to use for local tests. When deploying into production, it’s advised to use actual environment variables due to security reasons.
YAML files
YAML (YAML Ain’t Markup Language) is a human-readable data serialization language, typically used for configuration files. Go has several packages to parse YAML, and we are going to use the most common one — go-yaml
.
Firstly, let’s create a config.yaml
file:
1 | settings: |
Now, we will try to read the configuration from this file. In your go script, utilize the following codes:
1 | package main |
In this script, we first define the structure of our YAML file. The conf
type says that our root object has a Settings
object, and the settings
type says that the Settings
object contains a Greeting
string. We load the file with ioutil.ReadFile
and parse it with yaml.Unmarshal
, then simply print the greeting message.
YAML files allow for much more complex structures compared to .env
. This might be handy for larger applications with more sophisticated requirements.
Hopefully, this exercise gives you a good grasp on working with config files in Go. Remember, you mainly use these files to configure the behavior of your application without changing your code itself.
Topic 1.6 Configurations with Viper
While Go’s standard library and many other external packages provide utilities to manage environment variables and configuration files, handling complex configurations with ease can be a bit challenging.
Viper is one powerful library that comes with a rich set of features to deal with:
- JSON, TOML, YAML, HCL, and Java properties config files
- live watching and re-reading of config files
- reading from environment variables
- reading from remote config systems (etcd or Consul), and watching changes
- setting default values
- creating aliases
Let’s initialize a Viper object and set it up to read the environment variables:
1 | package main |
As you can see, Viper allows us to do the same thing we would do with Go’s built-in os package but in a cleaner and less error-prone way.
Now, let’s assume we have the following config.yaml
:
1 | Port: 8080 |
We could access these configuration settings as follows:
1 | viper.SetConfigName("config") |
In the example above, we use viper.GetString
and viper.GetInt
to get our configuration values. Viper automatically provides us with the correct type.
Please try to work with this, and when you’re ready, we can move on to building a full application that utilizes all the concepts learned above.
Topic 1.7: Full Application — CLI Application with Flag Handling and Configuration
In this section, we will create a CLI application based on all the elements we’ve learned so far. It will demonstrate flag handling, parsing environment variables, and reading configuration from YAML
files utilizing the Viper package.
Our application will be a basic HTTP Server. Let’s start coding!
Firstly, let’s define the configuration for our application:
1 | type Configuration struct { |
To fetch the configuration from a file or the environment, we’ll create a LoadConfiguration
function:
1 | func LoadConfiguration(configPaths []string) (Configuration, error) { |
This function tries to read the configuration from the environment and falls back to the configuration file if no environment variables were set.
Now, let’s use this function in our main function and run our HTTP server:
1 | func main() { |
In this snippet, we’re loading our configuration from either the environment variables or a file in one of configPaths
. We then start our HTTP server on the configured port.
Make sure to replace "myapp"
with your application’s name and also substitute real values in the configuration paths.
Try running this application — pass different parameters and observe the output.
Topic 1.8: Review and Practice
We’ve covered significant ground in this course. Let’s go over the key points you’ve learned:
- Command-Line Applications in Go: You’ve understood the fundamentals of building CLI applications in Go, leveraging the standard “os” and “bufio” libraries.
- Handling Command Line Arguments: You’ve learned how to manage command line arguments using the os package, along with understanding flags, arguments, and options.
- I/O Operations on Console: You’ve mastered reading from and writing to the console using the “os” and “bufio” packages.
- Environment Variables: We covered how to read and set environment variables using the os package and discussed why these environment variables are crucial.
- Creating Config Files: We dabbled in creating
.env
and.yaml
files to store application configurations. - Complex Configurations with Viper: You learned about handling complex configurations using the Viper package.
- Full Application: Using all the knowledge you’ve gained, you constructed a fully functional CLI application, demonstrating flag handling and environment variable configurations.
Now, let’s test your knowledge with some exercises:
- Expand on the difference between flags, arguments, and options in a CLI application. Provide an examples for each.
- Explain how you would utilize environment variables in an HTTP server application in Go. What type of information would you store in them?
- Write a brief piece of code demonstrating how you’d read a
.yaml
config file in a Go application. - Create a small Go CLI application that takes a user’s name as a command line argument and greets the user.
These exercises will help cement the concepts you’ve learned.
Topic 1.9: Assessments
This session will assess your understanding and application of the topics we’ve covered. Don’t worry, these are designed to measure your comprehension and not to trick you. Take it as an opportunity to reflect on everything you’ve learned. Here we go:
- Command Line Applications: Explain what a Command Line Interface (CLI) is and why we choose to build applications for the command-line instead of a graphical user interface (GUI).
- Handling Command Line Arguments: Write a Go program that can accept command line arguments and print them.
- I/O Operations on Console: Write a Go program that reads an input string from the console and prints it back.
- Environment Variables: Write a Go program that can read an environment variable and print its value.
- Config Files: Explain the use of
.env
or.yaml
files for storing configurations. - Configurations with Viper: Write a Go program that reads a config value from a
.yaml
file using the viper library. - Full Application: Consider an application that requires several configurations (like an API key or a URL). How would you use everything you have learned to manage this?
Take your time, think about the questions, and do your best to answer them. Remember, this is your opportunity to reflect on the progress you’ve made.
中文文章: https://programmerscareer.com/zh-cn/go-basic-14/
Author: Wesley Wei – Twitter Wesley Wei – Medium
Note: If you choose to repost or use this article, please cite the original source.
Comments