Las secciones anteriores presentaron el método de leer directamente los parámetros de solicitud. Si resulta engorroso leer cada parámetro individualmente, el marco de trabajo iris también proporciona un mecanismo de enlace de parámetros, que puede vincular los parámetros de solicitud a una estructura y también admite un mecanismo de validación de parámetros de formulario.
Vinculación de modelos y validación
Para vincular el cuerpo de la solicitud a un tipo, se utiliza la vinculación de modelos. Actualmente, admitimos la vinculación de tipos como JSON
, JSONProtobuf
, Protobuf
, MsgPack
, XML
, YAML
y valores de formulario estándar (foo=bar&boo=baz).
// A continuación se presentan las definiciones de funciones para vincular parámetros de solicitud de varios formatos a una estructura
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
Al utilizar ReadBody
, Iris inferirá el vinculador según el encabezado Content-Type. Si está seguro sobre el contenido que desea vincular, puede utilizar métodos específicos como ReadJSON
o ReadProtobuf
.
ReadBody(ptr interface{}) error
Iris cuenta con una inteligente validación de datos integrada. Sin embargo, le permite adjuntar un validador que se llamará automáticamente en métodos como ReadJSON
, ReadXML
, etc. En este ejemplo, aprenderemos a utilizar go-playground/validator/v10 para validar el cuerpo de la solicitud.
Tenga en cuenta que es necesario establecer las etiquetas de vinculación correspondientes en todos los campos a vincular. Por ejemplo, al vincular desde JSON, establezca json:"nombre_campo"
.
También puede especificar ciertos campos como campos requeridos. Si un campo tiene la decoración binding:"required"
y no se proporciona ningún valor durante la vinculación, se devolverá un error.
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("/usuario")
{
userRouter.Get("/errores-de-validacion", resolverDocumentacionErrores)
userRouter.Post("/", postUsuario)
}
app.Listen(":8080")
}
// Usuario contiene información del usuario.
type Usuario struct {
Nombre string `json:"fname" validate:"required"` // Nombre, requerido
Apellido string `json:"lname" validate:"required"` // Apellido, requerido
Edad uint8 `json:"age" validate:"gte=0,lte=130"` // Edad, rango entre 0 y 130
Correo string `json:"email" validate:"required,email"` // Correo electrónico, requerido
ColorFavorito string `json:"favColor" validate:"hexcolor|rgb|rgba"` // Color favorito, debe ser un valor legal de color hexadecimal, RGB o RGBA
Direcciones []*Direccion `json:"addresses" validate:"required,dive,required"` // Lista de direcciones, no debe estar vacía y cada elemento de la dirección es requerido
}
// Dirección almacena información de dirección de usuario.
type Direccion struct {
Calle string `json:"street" validate:"required"` // Calle, requerida
Ciudad string `json:"city" validate:"required"` // Ciudad, requerida
Planeta string `json:"planet" validate:"required"` // Planeta, requerido
Teléfono string `json:"phone" validate:"required"` // Teléfono, requerido
}
type errorDeValidacion struct {
EtiquetaActual string `json:"tag"` // Etiqueta actual
EspacioNombres string `json:"namespace"` // Espacio de nombres
Tipo string `json:"kind"` // Tipo
Val string `json:"type"` // Valor
Parámetro string `json:"param"` // Parámetro
}
func envolverErroresDeValidacion(errs validator.ValidationErrors) []errorDeValidacion {
erroresDeValidacion := make([]errorDeValidacion, 0, len(errs))
for _, errorDeValidacion := range errs {
erroresDeValidacion = append(erroresDeValidacion, errorDeValidacion{
EtiquetaActual: errorDeValidacion.ActualTag(),
EspacioNombres: errorDeValidacion.Namespace(),
Tipo: errorDeValidacion.Kind().String(),
Val: errorDeValidacion.Type().String(),
Parámetro: errorDeValidacion.Param(),
})
}
return erroresDeValidacion
}
func postUsuario(ctx iris.Context) {
var usuario Usuario
err := ctx.ReadJSON(&usuario)
if err != nil {
// Manejar errores, la siguiente es la forma correcta...
if errs, ok := err.(validator.ValidationErrors); ok {
// Envolver errores en formato JSON, la biblioteca subyacente devuelve errores de tipo interfaz.
erroresDeValidacion := envolverErroresDeValidacion(errs)
// Devolver una respuesta de aplicación/json+problem y detener la ejecución de los manejadores subsiguientes
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Errores de Validación").
Detail("Uno o más campos no superaron la validación").
Type("/usuario/errores-de-validacion").
Key("errores", erroresDeValidacion))
return
}
// Podría ser un error interno de JSON, no se proporciona más información aquí.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"mensaje": "OK"})
}
func resolverDocumentacionErrores(ctx iris.Context) {
ctx.WriteString("Esta página se utiliza para explicar cómo resolver errores de validación a desarrolladores web o usuarios de API")
}
{
"nombre": "",
"apellido": "",
"edad": 45,
"email": "[email protected]",
"colorFavorito": "#000",
"direcciones": [{
"calle": "Muelles Eavesdown",
"planeta": "Perséfone",
"teléfono": "ninguno",
"ciudad": "Desconocida"
}]
}
{
"título": "Error de validación",
"detalle": "Uno o más campos no superaron la validación",
"tipo": "http://localhost:8080/user/validation-errors",
"estado": 400,
"campos": [
{
"etiqueta": "requerido",
"espacio-nombres": "Usuario.PrimerNombre",
"tipo": "cadena",
"valor": "",
"parámetro": ""
},
{
"etiqueta": "requerido",
"espacio-nombres": "Usuario.Apellido",
"tipo": "cadena",
"valor": "",
"parámetro": ""
}
]
}
Parámetros de consulta de URL
El método ReadQuery
vincula solo los parámetros de consulta, no los datos del cuerpo de la solicitud. Utiliza ReadForm
para vincular los datos del cuerpo de la solicitud.
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("Persona: %#+v", person)
ctx.WriteString("Éxito")
}
Vinculación de datos arbitrarios
Vincula el cuerpo de la solicitud a "ptr" basado en el tipo de contenido de los datos enviados por el cliente, como JSON, XML, YAML, MessagePack, Protobuf, Form y consulta de 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("Persona: %#+v", person)
ctx.WriteString("Éxito")
}
Puedes probar con el siguiente comando:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
Vinculación de parámetros de ruta de 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("misParams: %#v", p)
})
app.Listen(":8088")
}
Solicitud
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
Vinculación de parámetros de solicitud de encabezado
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")
}
Solicitud
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
Respuesta
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}