Utilisation de la bibliothèque validator pour la validation de paramètres en Go

Introduction

Dans le développement d'applications web, la validation des champs d'entrée est une étape essentielle pour garantir la sécurité et l'intégrité des données. Au lieu d'utiliser des expressions régulières pour chaque champ, la bibliothèque validator offre une solution plus élégente et efficace.

Installation

Pour commencer, installez la bibliothèque validator :

go get github.com/go-playground/validator/v10

Dans votre code, importez le package :

import "github.com/go-playground/validator/v10"

Fonctionnalités principales

La bibliothèque validator propose de nombreuses fonctionnalités de validation :

Symboles spéciaux dans les tags

  • Virgule (,) : Sépare plusieurs tags de validation (sans espaces)
  • Tiret (-) : Ignore la validation du champ
  • Barre vertiacle (|) : Plusieurs tags où l'un suffit pour valider
  • required : Champ obligatoire
  • omitempty : Ignore le champ s'il n'est pas défini

Validations de plage

Pour les nombres, les chaînes, les tranches et les maps :

  • lte : Inférieur ou égal
  • gte : Supérieur ou égal
  • lt : Strictement inférieur
  • gt : Strictement supérieur
  • len : Longueur exacte
  • max : Valeur maximale
  • min : Valeur minimale
  • ne : Différent de
  • oneof : Doit être l'une des valeurs spécifiées

Exemple :

type Utilisateur struct {
    Nom  string `validate:"min=2,max=50"`
    Age  uint8  `validate:"gte=18,lte=120"`
}

Validations de chaînes

  • contains : Contient la sous-chaîne spécifiée
  • excludes : Ne contient pas la sous-chaîne spécifiée
  • startswith : Commence par la sous-chaîne spécifiée
  • endswith : Se termine par la sous-chaîne spécifiée

Validations de champs

  • eqfield : Champ égal à un autre champ de la même structure
  • nefield : Champ différent d'un autre champ
  • gtefield : Champ supérieur ou égal à un autre champ
  • ltefield : Champ inférieur ou égal à un autre champ

Validations réseau

  • ip : Adresse IP valide
  • ipv4 : Adresse IPv4 valide
  • ipv6 : Adresse IPv6 valide
  • uri : URI valide
  • url : URL valide

Exemples pratiques

Exemple 1 : Validation d'une valeur simple

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

func main() {
    validateur := validator.New()
    
    // Validation d'un email
    email := "test@example.com"
    err := validateur.Var(email, "required,email")
    if err != nil {
        fmt.Printf("Email invalide: %v\n", err)
    } else {
        fmt.Println("Email valide")
    }
    
    // Validation d'un nombre
    nombre := 25
    err = validateur.Var(nombre, "gt=0,lt=100")
    if err != nil {
        fmt.Printf("Nombre invalide: %v\n", err)
    } else {
        fmt.Println("Nombre valide")
    }
}

Exemple 2 : Validation d'une structure

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type Profil struct {
    Prenom    string     `validate:"required"`
    Nom       string     `validate:"required"`
    Age       uint8      `validate:"gte=18,lte=120"`
    Courriel  string     `validate:"required,email"`
    Adresses  []Adresse  `validate:"required,dive,required"`
}

type Adresse struct {
    Rue      string `validate:"required"`
    Ville    string `validate:"required"`
    Pays     string `validate:"required"`
    CodePostal string `validate:"required"`
}

func main() {
    profil := &Profil{
        Prenom:   "Jean",
        Nom:      "Dupont",
        Age:      30,
        Courriel: "jean.dupont@example.com",
        Adresses: []Adresse{
            {
                Rue:        "123 Rue Principale",
                Ville:      "Paris",
                Pays:       "France",
                CodePostal: "75001",
            },
        },
    }

    validateur := validator.New()
    err := validateur.Struct(profil)
    if err != nil {
        fmt.Println("Erreurs de validation:")
        for _, erreur := range err.(validator.ValidationErrors) {
            fmt.Printf("- Champ: %s, Erreur: %s\n", erreur.Field(), erreur.Tag())
        }
    } else {
        fmt.Println("Structure valide")
    }
}

Exemple 3 : Validation de tranches et maps

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

func main() {
    validateur := validator.New()
    
    // Validation d'une tranche
    noms := []string{"Alice", "Bob", "Charlie"}
    err := validateur.Var(noms, "max=5,dive,min=3")
    if err != nil {
        fmt.Printf("Erreurs dans la tranche: %v\n", err)
    } else {
        fmt.Println("Tranche valide")
    }
    
    // Validation d'une map
    preferences := map[string]string{
        "couleur": "bleu",
        "taille":  "moyen",
    }
    err = validateur.Var(preferences, "gte=2,dive,keys,eq=couleur|eq=taille,endkeys,required")
    if err != nil {
        fmt.Printf("Erreurs dans la map: %v\n", err)
    } else {
        fmt.Println("Map valide")
    }
}

Exemple 4 : Validation personnalisée

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type Produit struct {
    Nom        string `validate:"required,nomValide"`
    Prix       float64 `validate:"gt=0"`
    Categorie  string `validate:"required"`
}

func main() {
    validateur := validator.New()
    
    // Enregistrement d'une validation personnalisée
    err := validateur.RegisterValidation("nomValide", func(fl validator.FieldLevel) bool {
        nom := fl.Field().String()
        return len(nom) >= 3 && !containsNumber(nom)
    })
    
    if err != nil {
        fmt.Printf("Erreur lors de l'enregistrement: %v\n", err)
        return
    }
    
    produit := &Produit{
        Nom:       "Produit123",
        Prix:      19.99,
        Categorie: "Électronique",
    }
    
    err = validateur.Struct(produit)
    if err != nil {
        fmt.Printf("Produit invalide: %v\n", err)
    } else {
        fmt.Println("Produit valide")
    }
}

func containsNumber(s string) bool {
    for _, char := range s {
        if char >= '0' && char <= '9' {
            return true
        }
    }
    return false
}

Exemple 5 : Validation entre champs

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type Inscription struct {
    NomUtilisateur string `validate:"min=4,max=20"`
    MotDePasse     string `validate:"min=8"`
    Confirmation   string `validate:"eqfield=MotDePasse"`
    Email          string `validate:"email"`
}

func main() {
    validateur := validator.New()
    
    // Cas 1 : Mots de passe différents
    utilisateur1 := Inscription{
        NomUtilisateur: "jean",
        MotDePasse:     "motdepasse123",
        Confirmation:   "motdepasse456",
        Email:         "jean@example.com",
    }
    
    err := validateur.Struct(utilisateur1)
    if err != nil {
        fmt.Printf("Inscription 1 invalide: %v\n", err)
    }
    
    // Cas 2 : Mots de passe identiques
    utilisateur2 := Inscription{
        NomUtilisateur: "jean",
        MotDePasse:     "motdepasse123",
        Confirmation:   "motdepasse123",
        Email:         "jean@example.com",
    }
    
    err = validateur.Struct(utilisateur2)
    if err != nil {
        fmt.Printf("Inscription 2 invalide: %v\n", err)
    } else {
        fmt.Println("Inscription 2 valide")
    }
}

Exemple 6 : Traduction des messages d'erreur

package main

import (
    "fmt"
    "strings"
    "github.com/go-playground/locales/fr"
    ut "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    frtrans "github.com/go-playground/validator/v10/translations/fr"
)

type Etudiant struct {
    Nom   string `validate:"required"`
    Email string `validate:"email"`
    Age   int    `validate:"min=16,max=30"`
}

func main() {
    // Configuration du traducteur
    fr := fr.New()
    uni := ut.New(fr)
    trans, _ := uni.GetTranslator("fr")
    
    validateur := validator.New()
    frtrans.RegisterDefaultTranslations(validateur, trans)
    
    etudiant := Etudiant{
        Nom:   "Marie",
        Email: "email invalide",
        Age:   35,
    }
    
    err := validateur.Struct(etudiant)
    if err != nil {
        erreurs := err.(validator.ValidationErrors)
        messages := nettoyerNomStructure(erreurs.Translate(trans))
        fmt.Println("Erreurs de validation:")
        for champ, message := range messages {
            fmt.Printf("- %s: %s\n", champ, message)
        }
    }
}

func nettoyerNomStructure(erreurs map[string]string) map[string]string {
    result := make(map[string]string)
    
    for champ, message := range erreurs {
        result[champ[strings.Index(champ, ".")+1:]] = message
    }
    return result
}

Conclusion

La bibliothèque validator offre une solution puissante et flexible pour la validation des données dans les applications Go. Avec ses nombreuses fonctionnalités intégrées et la possibilité de créer des validations personnalisées, elle simplifie considérablement le processus de validation des données.

Étiquettes: Go validator validation de données bibliothèque Go

Publié le 6 juin à 05h08