Die vorherigen Abschnitte haben die Methode des direkten Lesens von Anforderungsparametern vorgestellt. Wenn es umständlich ist, jeden Parameter einzeln zu lesen, bietet das Iris-Framework auch einen Parameter-Bindungsmechanismus an, der Anforderungsparameter an eine Struktur binden kann und zudem einen Mechanismus zur Validierung von Formparametern unterstützt.
Modellbindung und Validierung
Um den Anforderungskörper an einen Typ zu binden, verwenden Sie die Modellbindung. Derzeit unterstützen wir die Bindung von Typen wie JSON
, JSONProtobuf
, Protobuf
, MsgPack
, XML
, YAML
und Standardformularwerten (foo=bar&boo=baz).
// Unten sind die Funktionsdefinitionen für das Binden von Anforderungsparametern verschiedener Formate an eine Struktur
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
Bei Verwendung von ReadBody
wird Iris den Binder anhand des Content-Type-Headers ableiten. Wenn Sie sicher sind, welchen Inhalt Sie binden möchten, können Sie spezifische ReadXXX
-Methoden wie ReadJSON
oder ReadProtobuf
verwenden.
ReadBody(ptr interface{}) error
Iris verfügt über eine intelligente eingebaute Datenvalidierung. Sie können jedoch einen Validator anhängen, der automatisch bei Methoden wie ReadJSON
, ReadXML
usw. aufgerufen wird. In diesem Beispiel erfahren wir, wie man go-playground/validator/v10 verwendet, um den Anforderungskörper zu validieren.
Bitte beachten Sie, dass Sie entsprechende Bindungs-Tags für alle zu bindenden Felder festlegen müssen. Wenn Sie beispielsweise aus JSON binden, legen Sie "json:"fieldname"" fest.
Sie können auch bestimmte Felder als erforderlich kennzeichnen. Hat ein Feld die Dekoration binding:"required"
und es wird kein Wert während der Bindung bereitgestellt, wird ein Fehler zurückgegeben.
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("/benutzer")
{
userRouter.Get("/validierungsfehler", resolveErrorsDocumentation)
userRouter.Post("/", postUser)
}
app.Listen(":8080")
}
// Benutzer enthält Benutzerinformationen.
type Benutzer struct {
Vorname string `json:"vname" validate:"required"` // Vorname, erforderlich
Nachname string `json:"nname" validate:"required"` // Nachname, erforderlich
Alter uint8 `json:"alter" validate:"gte=0,lte=130"` // Alter, Bereich zwischen 0 und 130
E-Mail string `json:"email" validate:"required,email"` // E-Mail, erforderlich
Lieblingsfarbe string `json:"lieblingsfarbe" validate:"hexcolor|rgb|rgba"` // Lieblingsfarbe, muss ein gültiger Hexadezimal-, RGB- oder RGBA-Farbwert sein
Adressen []*Adresse `json:"adressen" validate:"required,dive,required"` // Adressliste, darf nicht leer sein und jedes Adressenelement ist erforderlich
}
// Adresse speichert Adressinformationen des Benutzers.
type Adresse struct {
Straße string `json:"straße" validate:"required"` // Straße, erforderlich
Stadt string `json:"stadt" validate:"required"` // Stadt, erforderlich
Planet string `json:"planet" validate:"required"` // Planet, erforderlich
Telefon string `json:"telefon" validate:"required"` // Telefon, erforderlich
}
type validierungsfehler struct {
AktuellesTag string `json:"tag"` // Aktuelles Tag
Namespace string `json:"namespace"` // Namespace
Art string `json:"art"` // Art
Typ string `json:"typ"` // Typ
Wert string `json:"wert"` // Wert
Parameter string `json:"parameter"` // Parameter
}
func wrapValidationErrors(errs validator.ValidationErrors) []validierungsfehler {
validierungsfehler := make([]validierungsfehler, 0, len(errs))
for _, validationErr := range errs {
validierungsfehler = append(validierungsfehler, validierungsfehler{
AktuellesTag: validationErr.ActualTag(),
Namespace: validationErr.Namespace(),
Art: validationErr.Kind().String(),
Typ: validationErr.Type().String(),
Wert: fmt.Sprintf("%v", validationErr.Value()),
Parameter: validationErr.Param(),
})
}
return validierungsfehler
}
func postUser(ctx iris.Context) {
var benutzer Benutzer
err := ctx.ReadJSON(&benutzer)
if err != nil {
// Fehler behandeln, dies ist die richtige Vorgehensweise...
if errs, ok := err.(validator.ValidationErrors); ok {
// Fehler im JSON-Format umhüllen, die zugrunde liegende Bibliothek gibt Fehler vom Typ Schnittstelle zurück.
validierungsfehler := wrapValidationErrors(errs)
// Gibt eine Anwendungs-/json+problem-Antwort zurück und stoppt die Ausführung nachfolgender Handler
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Validierungsfehler").
Detail("Ein oder mehrere Felder haben die Validierung nicht bestanden").
Type("/benutzer/validierungsfehler").
Key("errors", validierungsfehler))
return
}
// Es könnte sich um einen internen JSON-Fehler handeln, hier werden keine weiteren Informationen bereitgestellt.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("Diese Seite dient zur Erklärung, wie Validierungsfehler für Webentwickler oder API-Benutzer behoben werden können")
}
{
"titel": "Validierungsfehler",
"detail": "Eine oder mehrere Felder konnten nicht validiert werden",
"type": "http://localhost:8080/benutzer/validierungsfehler",
"status": 400,
"fields": [
{
"tag": "erforderlich",
"namespace": "Benutzer.Vorname",
"kind": "string",
"type": "string",
"value": "",
"param": ""
},
{
"tag": "erforderlich",
"namespace": "Benutzer.Nachname",
"kind": "string",
"type": "string",
"value": "",
"param": ""
}
]
}
Binden von URL-Abfrageparametern
Die Methode ReadQuery
bindet nur die Abfrageparameter, nicht die Daten des Anforderungskörpers. Verwenden Sie ReadForm
, um die Daten des Anforderungskörpers zu binden.
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("Person: %#+v", person)
ctx.WriteString("Erfolg")
}
Binden beliebiger Daten
Binden Sie den Anforderungskörper an "ptr" basierend auf dem Inhaltstyp der vom Client gesendeten Daten, wie z.B. JSON, XML, YAML, MessagePack, Protobuf, Form und URL-Abfrage.
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("Person: %#+v", person)
ctx.WriteString("Erfolg")
}
Sie können mit dem folgenden Befehl testen:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
Binden von URL-Pfadparametern
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("myParams: %#v", p)
})
app.Listen(":8088")
}
Anfrage
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
Binden von Header-Anforderungsparametern
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")
}
Anfrage
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
Ergebnis
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}