Techniques avancées pour personnaliser la sérialisation JSON
Bien que les struct tags JSON de base couverts dans la section précédente soient très utiles, le package encoding/json
de Golang propose également des techniques plus avancées pour personnaliser la sérialisation et la désérialisation de vos structures de données. Ces techniques vous permettent de gérer des scénarios complexes et d'obtenir un contrôle plus fin sur la représentation JSON de vos données.
Gérer omitempty
et les noms de champs personnalisés
L'un des cas d'utilisation avancé le plus courant des struct tags JSON est de gérer la directive omitempty
et de personnaliser les noms de champs. La directive omitempty
indique au package encoding/json
d'omettre un champ de la sortie JSON si la valeur du champ est la valeur zéro de son type. Cela peut être particulièrement utile lorsqu'il s'agit de champs nullable ou optionnels.
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
Email *string `json:"email,omitempty"`
Password string `json:"-"`
}
Dans cet exemple, les champs Age
et Email
seront omis de la sortie JSON s'ils ont leurs valeurs zéro (respectivement 0 et nil
). Le champ Password
est complètement exclu de la sortie JSON.
Vous pouvez également utiliser des noms de champs personnalisés pour mieux correspondre aux conventions de nommage de vos données JSON. Par exemple, vous pourriez vouloir utiliser des noms de champs en snake_case dans votre JSON, même si votre struct Go utilise le camelCase :
type Person struct {
FullName string `json:"full_name"`
DateOfBirth time.Time `json:"date_of_birth"`
}
Gérer les structs et les interfaces imbriquées
Le support de Golang pour les structs et les interfaces imbriquées peut également être exploité lors de la manipulation de données JSON. Vous pouvez utiliser la directive de struct tag inline
pour intégrer directement les champs d'une struct imbriquée dans la représentation JSON de la struct parente.
type Address struct {
Street string `json:"street"`
City string `json:"city"`
Country string `json:"country,omitempty"`
}
type Person struct {
Name string `json:"name"`
Address Address `json:"address,inline"`
}
Dans cet exemple, les champs de la struct Address
sont intégrés dans la représentation JSON de la struct Person
, ce qui donne une sortie JSON plus compacte et plus lisible.
De plus, vous pouvez utiliser des interfaces pour créer des structures JSON plus dynamiques et flexibles. En définissant les champs de votre struct comme des interfaces, vous pouvez sérialiser et désérialiser une plus grande variété de types de données, ce qui permet une gestion JSON plus polyvalente.
Encoders et décodeurs JSON personnalisés
Dans certains cas, la fonctionnalité intégrée du package encoding/json
peut ne pas être suffisante pour gérer vos besoins spécifiques de sérialisation et de désérialisation JSON. Dans ces situations, vous pouvez créer des encodeurs et des décodeurs JSON personnalisés pour étendre les capacités du package.
Pour créer un encodeur ou un décodeur personnalisé, vous devez implémenter respectivement les interfaces json.Marshaler
ou json.Unmarshaler
. Cela vous permet de définir votre propre logique pour sérialiser et désérialiser vos structures de données.
type Person struct {
Name string
Age int
}
func (p *Person) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"name":"%s","age":%d}`, p.Name, p.Age)), nil
}
func (p *Person) UnmarshalJSON(data []byte) error {
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
p.Name, _ = v["name"].(string)
p.Age, _ = v["age"].(int)
return nil
}
En implémentant ces interfaces, vous pouvez complètement personnaliser le processus de sérialisation et de désérialisation JSON de vos structures de données, ce qui vous permet de gérer même les exigences JSON les plus complexes.