Gérer la configuration de votre application avec un fichier JSON
Il existe plusieurs moyens de stocker la configuration d'une application (fichier INI, fichier XML, base de données). Je trouve pratique et moderne d'utiliser le format JSON. Comme vous allez le constater dans cet article, la bibliothèque standard de go gère ce cas de figure.
Exemple de code
directives import nécessaires :
- encoding/json : JSON (pour JavaScript Object Notation) est un format de données textuelles permettant de représenter de l’information structurée. Go fournit le package encoding/json dédié au traitement de ces données.
- io/ioutil : Ce package golang contient un ensemble de fonctions utilitaires d'entrée / sortie.
Ce qui donne le code suivant :
import (
"fmt"
"encoding/json"
"io/ioutil"
)
Exemple de fichier de configuration
Votre fichier de configuration JSON peut contenir des données simples et complexes comme un tableau de valeurs :
{
"Port":":7777",
"Folders":
[
{
"Path":"un autre répertoire"
}
]
}
Décrire la structure du fichier de configuration
Il faut décrire en golang les structures de donnée, notamment le fait que
Folders est un tableau :
type Configuration struct {
Port string
Folders []FolderType
}
type FolderType struct {
Path string
}
Lecture de la configuration
La fonction
json.Unmarshal permet de
parser le contenu du fichier JSON et de ranger les informations dans la structure de données que vous avez décrite précédemment. Cet exemple de code est également l'occasion de voir la fonction
ioutil.ReadFile, capable de lire l'intégralité d'un fichier.
var config Configuration
file, err := ioutil.ReadFile("config.json")
if err != nil {
panic("Problème avec le fichier de configuration")
}
json.Unmarshal(file, &config)
fmt.Printf("Port : %s\n", config.Port)
fmt.Printf("Port : %s\n", config.Folders[0].Path)
Écriture de la configuration
Il est possible de faire l'opération inverse, c'est-à-dire de transformer une information structurée en JSON, puis de l'écrire dans un fichier. On utilisera la fonction
ioutil.WriteFile afin d'écrire le contenu entier d'un fichier en une seule opération.
config.Folders[0].Path = "un autre répertoire"
b, err := json.MarshalIndent(config, "", " ")
if err != nil {
panic("Impossible de transformer la configuration en JSON")
}
err = ioutil.WriteFile("config.json", b, 0644)
if err != nil {
panic("Impossible d'écrire dans le fichier de configuration")
}
On note que la fonction
json.MarshalIndent a pour dernier paramètre le ou les caractères qui seront utilisés pour indenter le fichier.
Ne pas indenter le fichier JSON
Il existe aussi la fonction
json.Marshal. Elle génère une sortie JSON d'un seul bloc. Ce qui n'est pas très lisible ni pratique pour un utilisateur. Si vous souhaitez l'utiliser dans le cas d'un retour HTTP d'une API JSON (on sort du contexte du fichier de configuration), voici un exemple de ce qui serait généré :
{"Port":":7777","Folders":[{"Path":"un autre répertoire"}]}
Fonctionnalités supplémentaires
Chargement dynamique
Il serait intéressant de surveiller le fichier de configuration et de recharger dynamiquement la configuration de l'application en cas de changement. Il existe un package – développé par l'équipe Go – et chargé de notifier le programme golang des modifications apportées à un fichier. Je vous conseille la lecture de mon article explique comment mettre en oeuvre
fsnotify.
Trouver le fichier de configuration
Dans le cas où votre programme golang est lancé en tant que service, il faut savoir que le répertoire de travail n'est pas forcément le répertoire où votre logiciel est installé. Il faut donc trouver un moyen élégant de récupérer le répertoire d'installation afin d'en déduire l'emplacement du fichier de configuration. J'ai pensé à ce cas de figure et j'en ai rédigé
un article expliquant comment savoir où est l'exécutable golang.
Cas particulier des services Windows
Comme expliqué dans mon article consacré
au développement d'un service en golang, l'initialisation du service doit être très rapide (le gestionnaire de service de Windows attend une réponse du service lancé lorsque ce dernier est prêt). Le chargement et l'analyse (
UnMarshall) d'un fichier est trop lent pour répondre dans les temps. Il ne faut donc pas développer le chargement de ce fichier de configuration en début de fonction
main (l'article cité explique tout cela dans le détail).