Les sections précédentes ont introduit la méthode de lecture directe des paramètres de requête. S'il est fastidieux de lire chaque paramètre individuellement, le framework iris propose également un mécanisme de liaison de paramètres qui permet de lier les paramètres de requête à une structure, tout en prenant en charge un mécanisme de validation des paramètres de formulaire.
Liaison de modèle et validation
Pour lier le corps de la requête à un type, utilisez la liaison de modèle. Actuellement, nous prenons en charge le "binding" des types tels que JSON
, JSONProtobuf
, Protobuf
, MsgPack
, XML
, YAML
, et les valeurs de formulaire standard (foo=bar&boo=baz).
// ci-dessous se trouvent les définitions des fonctions pour lier les paramètres de requête de différents formats à une structure
ReadJSON(outPtr interface{}) error
ReadJSONProtobuf(ptr proto.Message, opts ...ProtoUnmarshalOptions) error
ReadProtobuf(ptr proto.Message) error
ReadMsgPack(ptr interface{}) error
ReadXML(outPtr interface{}) error
ReadYAML(outPtr interface{}) error
ReadForm(formObject interface{}) error
ReadQuery(ptr interface{}) error
En utilisant ReadBody
, Iris inférera le lien en fonction de l'en-tête Content-Type. Si vous êtes certain du contenu que vous voulez lier, vous pouvez utiliser des méthodes spécifiques telles que ReadJSON
ou ReadProtobuf
.
ReadBody(ptr interface{}) error
Iris est livré avec une validation de données intégrée intelligente. Cependant, il vous permet d'attacher un validateur qui sera automatiquement appelé sur des méthodes telles que ReadJSON
, ReadXML
, etc. Dans cet exemple, nous allons apprendre comment utiliser go-playground/validator/v10 pour valider le corps de la requête.
Veuillez noter que vous devez définir les balises de liaison correspondantes sur tous les champs à lier. Par exemple, lors de la liaison depuis JSON, définissez json:"nomduchamp"
.
Vous pouvez également spécifier certains champs comme des champs obligatoires. Si un champ a la décoration binding:"required"
et aucune valeur n'est fournie lors de la liaison, une erreur sera renvoyée.
package main
import (
"fmt"
"github.com/kataras/iris/v12"
"github.com/go-playground/validator/v10"
)
func main() {
app := iris.New()
app.Validator = validator.New()
userRouter := app.Party("/user")
{
userRouter.Get("/validation-errors", resolveErrorsDocumentation)
userRouter.Post("/", postUser)
}
app.Listen(":8080")
}
// User contains user information.
type User struct {
FirstName string `json:"prenom" validate:"required"` // Prénom, requis
LastName string `json:"nom" validate:"required"` // Nom de famille, requis
Age uint8 `json:"age" validate:"gte=0,lte=130"` // Âge, compris entre 0 et 130
Email string `json:"email" validate:"required,email"` // Email, requis
FavouriteColor string `json:"couleurPref" validate:"hexcolor|rgb|rgba"` // Couleur préférée, doit être une valeur hexadécimale, RGB ou RGBA légale
Addresses []*Address `json:"adresses" validate:"required,dive,required"` // Liste d'adresses, ne doit pas être vide et chaque élément d'adresse est requis
}
// Address stores user address information.
type Address struct {
Street string `json:"rue" validate:"required"` // Rue, requis
City string `json:"ville" validate:"required"` // Ville, requis
Planet string `json:"planete" validate:"required"` // Planète, requis
Phone string `json:"tel" validate:"required"` // Téléphone, requis
}
type validationError struct {
ActualTag string `json:"tag"` // Tag réel
Namespace string `json:"espaceNom"` // Espace de noms
Kind string `json:"type"` // Type
Type string `json:"categorie"` // Catégorie
Value string `json:"valeur"` // Valeur
Param string `json:"param"` // Paramètre
}
func wrapValidationErrors(errs validator.ValidationErrors) []validationError {
validationErrors := make([]validationError, 0, len(errs))
for _, validationErr := range errs {
validationErrors = append(validationErrors, validationError{
ActualTag: validationErr.ActualTag(),
Namespace: validationErr.Namespace(),
Kind: validationErr.Kind().String(),
Type: validationErr.Type().String(),
Value: fmt.Sprintf("%v", validationErr.Value()),
Param: validationErr.Param(),
})
}
return validationErrors
}
func postUser(ctx iris.Context) {
var user User
err := ctx.ReadJSON(&user)
if err != nil {
// Gérer les erreurs, voici la manière correcte...
if errs, ok := err.(validator.ValidationErrors); ok {
// Encapsuler les erreurs au format JSON, la bibliothèque sous-jacente renvoie des erreurs de type interface.
validationErrors := wrapValidationErrors(errs)
// Retourner une réponse application/json+problem et arrêter l'exécution des gestionnaires suivants
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Erreurs de validation").
Detail("Un ou plusieurs champs n'ont pas réussi la validation").
Type("/user/validation-errors").
Key("errors", validationErrors))
return
}
// Il pourrait s'agir d'une erreur JSON interne, aucune information supplémentaire fournie ici.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("Cette page est utilisée pour expliquer comment résoudre les erreurs de validation aux développeurs web ou aux utilisateurs de l'API")
}
{
"title": "Erreur de validation",
"detail": "Un ou plusieurs champs n'ont pas passé la validation",
"type": "http://localhost:8080/user/validation-errors",
"status": 400,
"fields": [
{
"tag": "obligatoire",
"namespace": "Utilisateur.Prénom",
"kind": "string",
"type": "string",
"value": "",
"param": ""
},
{
"tag": "obligatoire",
"namespace": "Utilisateur.NomDeFamille",
"kind": "string",
"type": "string",
"value": "",
"param": ""
}
]
}
Liaison de paramètres de requête d'URL
La méthode ReadQuery
lie uniquement les paramètres de requête, et non les données du corps de la requête. Utilisez ReadForm
pour lier les données du corps de la requête.
package main
import "github.com/kataras/iris/v12"
type Person struct {
Name string `url:"name,required"`
Address string `url:"address"`
}
func main() {
app := iris.Default()
app.Any("/", index)
app.Listen(":8080")
}
func index(ctx iris.Context) {
var person Person
if err := ctx.ReadQuery(&person); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Application().Logger().Infof("Personne : %#+v", person)
ctx.WriteString("Succès")
}
Liaison de données arbitraires
Lie le corps de la requête à "ptr" en fonction du type de contenu des données envoyées par le client, tel que JSON, XML, YAML, MessagePack, Protobuf, Form, et la requête d'URL.
package main
import (
"time"
"github.com/kataras/iris/v12"
)
type Person struct {
Name string `form:"name" json:"name" url:"name" msgpack:"name"`
Address string `form:"address" json:"address" url:"address" msgpack:"address"`
Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1" json:"birthday" url:"birthday" msgpack:"birthday"`
CreateTime time.Time `form:"createTime" time_format:"unixNano" json:"create_time" url:"create_time" msgpack:"createTime"`
UnixTime time.Time `form:"unixTime" time_format:"unix" json:"unix_time" url:"unix_time" msgpack:"unixTime"`
}
func main() {
app := iris.Default()
app.Any("/", index)
app.Listen(":8080")
}
func index(ctx iris.Context) {
var person Person
if err := ctx.ReadBody(&person); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Application().Logger().Infof("Personne : %#+v", person)
ctx.WriteString("Succès")
}
Vous pouvez tester avec la commande suivante :
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
Liaison de paramètres de chemin d'URL
package main
import "github.com/kataras/iris/v12"
type myParams struct {
Name string `param:"name"`
Age int `param:"age"`
Tail []string `param:"tail"`
}
func main() {
app := iris.Default()
app.Get("/{name}/{age:int}/{tail:path}", func(ctx iris.Context) {
var p myParams
if err := ctx.ReadParams(&p); err != nil {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
ctx.Writef("MesParamètres : %#v", p)
})
app.Listen(":8088")
}
Requête
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
Liaison de paramètres de requête d'en-tête
package main
import "github.com/kataras/iris/v12"
type myHeaders struct {
RequestID string `header:"X-Request-Id,required"`
Authentication string `header:"Authentication,required"`
}
func main() {
app := iris.Default()
r.GET("/", func(ctx iris.Context) {
var hs myHeaders
if err := ctx.ReadHeaders(&hs); err != nil {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
ctx.JSON(hs)
})
app.Listen(":8080")
}
Requête
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
Réponse
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}