Guia prático de variáveis ​​de ambiente no Go

Olá Habr! Apresento a você a tradução de Um guia sem sentido para variáveis ​​de ambiente em Go by Enda Phelan.

As variáveis ​​de ambiente são a melhor maneira de armazenar configurações de aplicativos, pois podem ser definidas no nível do sistema. Esse é um dos princípios da metodologia Twelve-Factor App , que permite separar aplicativos do sistema em que estão sendo executados (a configuração pode variar significativamente entre implantações, o código não deve ser diferente).

Usando variáveis ​​de ambiente


Tudo o que é necessário para interagir com variáveis ​​de ambiente está na biblioteca padrão do sistema operacional . Eis como obter o valor da variável de ambiente PATH:

package main import ( "fmt" "os" ) func main() { // Store the PATH environment variable in a variable path, exists := os.LookupEnv("PATH") if exists { // Print the value of the environment variable fmt.Print(path) } } 

E assim - defina o valor da variável:

 package main import ( "fmt" "os" ) func main() { // Set the USERNAME environment variable to "MattDaemon" os.Setenv("USERNAME", "MattDaemon") // Get the USERNAME environment variable username := os.Getenv("USERNAME") // Prints out username environment variable fmt.Print(username) } 

Carregando variáveis ​​de ambiente de um arquivo .env


Em uma máquina de desenvolvimento, onde muitos projetos são lançados imediatamente, o armazenamento de parâmetros em ambientes variáveis ​​nem sempre é conveniente; seria mais lógico dividi-los entre projetos usando arquivos env. Você pode fazer isso, por exemplo, usando godotenv - este é o dotenv portado para a biblioteca Go Ruby. Ele permite que você defina as variáveis ​​de ambiente necessárias para o aplicativo a partir do arquivo .env.

Para instalar o pacote, execute:

 go get github.com/joho/godotenv 

Adicione as configurações ao arquivo .env na raiz do projeto:

 GITHUB_USERNAME=craicoverflow GITHUB_API_KEY=TCtQrZizM1xeo1v92lsVfLOHDsF7TfT5lMvwSno 

Agora você pode usar estes valores no aplicativo:

 package main import ( "log" "github.com/joho/godotenv" "fmt" "os" ) // init is invoked before main() func init() { // loads values from .env into the system if err := godotenv.Load(); err != nil { log.Print("No .env file found") } } func main() { // Get the GITHUB_USERNAME environment variable githubUsername, exists := os.LookupEnv("GITHUB_USERNAME") if exists { fmt.Println(githubUsername) } // Get the GITHUB_API_KEY environment variable githubAPIKey, exists := os.LookupEnv("GITHUB_API_KEY") if exists { fmt.Println(githubAPIKey) } } 

É importante lembrar que, se o valor da variável de ambiente estiver definido no nível do sistema, o Go usará esse valor em vez do especificado no arquivo env.

Agrupar variáveis ​​de ambiente no módulo de configuração


É bom, é claro, ter acesso direto às variáveis ​​de ambiente, como mostrado acima, mas manter essa solução parece bastante problemática. O nome da variável é uma sequência e, se for alterado, imagine uma dor de cabeça que resultará no processo de atualização de referências de variáveis ​​em todo o aplicativo.

Para resolver esse problema, criaremos um módulo de configuração para trabalhar com variáveis ​​de ambiente de uma maneira mais centralizada e suportada.

Aqui está um módulo de configuração simples que retorna parâmetros de configuração na estrutura Config (também definimos os valores padrão dos parâmetros caso não exista variável de ambiente no sistema):

 package config import ( "os" ) type GitHubConfig struct { Username string APIKey string } type Config struct { GitHub GitHubConfig } // New returns a new Config struct func New() *Config { return &Config{ GitHub: GitHubConfig{ Username: getEnv("GITHUB_USERNAME", ""), APIKey: getEnv("GITHUB_API_KEY", ""), }, } } // Simple helper function to read an environment or return a default value func getEnv(key string, defaultVal string) string { if value, exists := os.LookupEnv(key); exists { return value } return defaultVal } 

Em seguida, adicione os tipos à estrutura Config , pois a solução existente suporta apenas tipos de cadeia, o que não é muito razoável para aplicativos grandes.

Crie manipuladores para os tipos bool, fatia e número inteiro:

 package config import ( "os" "strconv" "strings" ) type GitHubConfig struct { Username string APIKey string } type Config struct { GitHub GitHubConfig DebugMode bool UserRoles []string MaxUsers int } // New returns a new Config struct func New() *Config { return &Config{ GitHub: GitHubConfig{ Username: getEnv("GITHUB_USERNAME", ""), APIKey: getEnv("GITHUB_API_KEY", ""), }, DebugMode: getEnvAsBool("DEBUG_MODE", true), UserRoles: getEnvAsSlice("USER_ROLES", []string{"admin"}, ","), MaxUsers: getEnvAsInt("MAX_USERS", 1), } } // Simple helper function to read an environment or return a default value func getEnv(key string, defaultVal string) string { if value, exists := os.LookupEnv(key); exists { return value } return defaultVal } // Simple helper function to read an environment variable into integer or return a default value func getEnvAsInt(name string, defaultVal int) int { valueStr := getEnv(name, "") if value, err := strconv.Atoi(valueStr); err == nil { return value } return defaultVal } // Helper to read an environment variable into a bool or return default value func getEnvAsBool(name string, defaultVal bool) bool { valStr := getEnv(name, "") if val, err := strconv.ParseBool(valStr); err == nil { return val } return defaultVal } // Helper to read an environment variable into a string slice or return default value func getEnvAsSlice(name string, defaultVal []string, sep string) []string { valStr := getEnv(name, "") if valStr == "" { return defaultVal } val := strings.Split(valStr, sep) return val } 

Adicione novas variáveis ​​de ambiente ao nosso arquivo env:

 GITHUB_USERNAME=craicoverflow GITHUB_API_KEY=TCtQrZizM1xeo1v92lsVfLOHDsF7TfT5lMvwSno MAX_USERS=10 USER_ROLES=admin,super_admin,guest DEBUG_MODE=false 

Agora você pode usá-los em qualquer lugar do aplicativo:

 package main import ( "fmt" "log" "github.com/craicoverflow/go-environment-variables-example/config" "github.com/joho/godotenv" ) // init is invoked before main() func init() { // loads values from .env into the system if err := godotenv.Load(); err != nil { log.Print("No .env file found") } } func main() { conf := config.New() // Print out environment variables fmt.Println(conf.GitHub.Username) fmt.Println(conf.GitHub.APIKey) fmt.Println(conf.DebugMode) fmt.Println(conf.MaxUsers) // Print out each role for _, role := range conf.UserRoles { fmt.Println(role) } } 

Feito!


Sim, existem pacotes que oferecem uma solução pronta para configurar seu aplicativo, mas quantos são necessários se for tão fácil fazê-lo você mesmo?

E como você gerencia a configuração no seu aplicativo?

Source: https://habr.com/ru/post/pt446468/


All Articles