Introdução ao package Viper

A configuração de uma aplicação é um dos pilares essenciais para garantir flexibilidade e adaptabilidade em diferentes ambientes de execução, como desenvolvimento, teste e produção.

Em Go, gerenciar essas configurações pode ser um desafio, especialmente quando lidamos com múltiplas fontes, como arquivos, variáveis de ambiente e flags de linha de comando.

É aqui que entra o Viper, um package poderoso para gerenciamento de configuração que simplifica esse processo.

O que é o Viper?

O Viper é um package open source desenvolvido para ajudar desenvolvedores Go a gerenciar configurações de maneira eficiente e flexível. Ele permite que sua aplicação leia configurações de várias fontes, como:

  • Arquivos de configuração (YAML, JSON, TOML, HCL, etc.)
  • Variáveis de ambiente
  • Flags de linha de comando
  • Key-value stores (como Consul)
  • Configurações remotas

Além disso, o Viper oferece recursos como:

  • Watcher para detectar alterações em arquivos de configuração e recarregar as configurações dinamicamente
  • Suporte a valores padrão para evitar falhas quando uma configuração não é encontrada
  • Leitura de configurações em múltiplos formatos de arquivo

Essas funcionalidades tornam o Viper uma solução completa para quem precisa gerenciar configurações em aplicações Go.

Viper na prática

Vamos explorar como o Viper pode ser utilizado em diferentes cenários práticos, iniciando pelo mais básico, a leitura de um arquivo YAML.

1. Lendo configurações de um arquivo YAML

Um dos usos mais comuns do Viper é ler configurações de arquivos YAML. Suponha que temos um arquivo chamado config.yaml com o seguinte conteúdo:

server:
  port: 8080
  host: localhost

Para carregar essas configurações em sua aplicação Go, faça o seguinte:

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

func main() {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")

    err := viper.ReadInConfig()
    if err != nil {
        panic(fmt.Errorf("Fatal error config file: %w", err))
    }

    host := viper.GetString("server.host")
    port := viper.GetInt("server.port")

    fmt.Printf("Server running on %s:%d\\n", host, port)
}

Explicação:

  • SetConfigName define o nome do arquivo de configuração (sem a extensão).
  • SetConfigType especifica o tipo do arquivo (neste caso, YAML).
  • AddConfigPath adiciona o caminho onde o arquivo de configuração será procurado.
  • ReadInConfig carrega o arquivo de configuração.
  • GetString e GetInt são usados para acessar os valores das configurações.

2. Utilizando variáveis de ambiente

Em muitos casos, como por exemplo, aplicações executadas como containers no Kubernetes, é comum que as configurações sejam definidas através de variáveis de ambiente.

Por isso, nesse segundo exemplo, vamos configurar o Viper para ler variáveis de ambiente:

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

func main() {
    viper.SetEnvPrefix("app")
    viper.BindEnv("port")
    viper.BindEnv("host")

    host := viper.GetString("host")
    port := viper.GetInt("port")

    fmt.Printf("Server running on %s:%d\\n", host, port)
}

Explicação:

  • SetEnvPrefix define um prefixo para as variáveis de ambiente.
  • BindEnv vincula as variáveis de ambiente às chaves de configuração.
  • As variáveis de ambiente esperadas seriam APP_PORT e APP_HOST.

3. Usando valores padrão

Valores padrão são úteis para evitar falhas quando uma configuração não é encontrada.

Como podemos ver no exemplo abaixo, no Viper, definir um valor padrão é algo muito simples:

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

func main() {
    viper.SetDefault("server.port", 8080)
    viper.SetDefault("server.host", "localhost")

    host := viper.GetString("server.host")
    port := viper.GetInt("server.port")

    fmt.Printf("Server running on %s:%d\\n", host, port)
}

Explicação:

  • SetDefault define um valor padrão para uma chave de configuração.
  • Se a chave não for encontrada em outras fontes, o valor padrão será usado.

4. Monitorando alterações no arquivo de configuração

O Viper também pode monitorar alterações em arquivos de configuração e recarregar os valores automaticamente:

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

func main() {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    viper.WatchConfig()

    viper.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("Config file changed:", e.Name)
    })

    err := viper.ReadInConfig()
    if err != nil {
        panic(fmt.Errorf("Fatal error config file: %w", err))
    }
}

Explicação:

  • WatchConfig ativa a observação do arquivo de configuração.
  • OnConfigChange define uma função de callback que será executada quando o arquivo for alterado.

Conclusão

O Viper é uma ferramenta poderosa para gerenciar configurações em aplicações Go. Ele simplifica o processo de leitura de configurações de diferentes fontes e ajuda a evitar problemas comuns relacionados à configuração.

Gostou do conteúdo?

  • Inscreva-se na nossa newsletter para receber mais dicas práticas sobre Go, Kubernetes e desenvolvimento de software diretamente no seu e-mail!
  • 🚀 Torne-se um assinante pago do blog e tenha acesso a conteúdos exclusivos, como tutoriais avançados, estudos de caso e muito mais!

Faça parte da comunidade!

Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.

Livros Recomendados

Abaixo listei alguns dos melhores livros que já li sobre GO.

Deixe uma resposta