Bagian sebelumnya memperkenalkan metode membaca parameter permintaan secara langsung. Jika terlalu rumit untuk membaca setiap parameter secara individual, kerangka kerja iris juga menyediakan mekanisme pengikatan parameter, yang dapat mengikat parameter permintaan ke dalam sebuah struktur, dan juga mendukung mekanisme validasi parameter formulir.
Pemetaan Model dan Validasi
Untuk memetakan badan permintaan ke suatu tipe, gunakan pemetaan model. Saat ini, kami mendukung pemetaan tipe seperti JSON
, JSONProtobuf
, Protobuf
, MsgPack
, XML
, YAML
, dan nilai formulir standar (foo=bar&boo=baz).
// Di bawah ini adalah definisi fungsi untuk memetakan parameter permintaan dari berbagai format ke dalam sebuah 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
Saat menggunakan ReadBody
, Iris akan menyimpulkan pemeta pengikat berdasarkan header Content-Type. Jika Anda yakin tentang konten yang ingin Anda ikat, Anda dapat menggunakan metode khusus ReadXXX
, seperti ReadJSON
atau ReadProtobuf
.
ReadBody(ptr interface{}) error
Iris dilengkapi dengan validasi data bawaan yang cerdas. Namun, Anda dapat melampirkan validator yang akan otomatis dipanggil pada metode seperti ReadJSON
, ReadXML
, dll. Pada contoh ini, kami akan belajar bagaimana menggunakan go-playground/validator/v10 untuk memvalidasi badan permintaan.
Harap dicatat bahwa Anda perlu menetapkan tag pemetaan yang sesuai pada semua bidang yang akan diikat. Misalnya, ketika melakukan pemetaan dari JSON, tetapkan json:"namaBidang"
.
Anda juga dapat menetapkan beberapa bidang sebagai bidang yang diperlukan. Jika suatu bidang memiliki dekorasi binding:"required"
dan tidak ada nilai yang disediakan selama pemetaan, sebuah kesalahan akan dikembalikan.
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 berisi informasi pengguna.
type User struct {
FirstName string `json:"fname" validate:"required"` // Nama depan, wajib
LastName string `json:"lname" validate:"required"` // Nama belakang, wajib
Age uint8 `json:"age" validate:"gte=0,lte=130"` // Usia, rentang antara 0 dan 130
Email string `json:"email" validate:"required,email"` // Email, wajib
FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` // Warna favorit, harus berupa nilai warna heksadesimal, RGB, atau RGBA yang sah
Addresses []*Address `json:"addresses" validate:"required,dive,required"` // Daftar alamat, tidak boleh kosong dan setiap item alamat harus wajib
}
// Address menyimpan informasi alamat pengguna.
type Address struct {
Street string `json:"street" validate:"required"` // Jalan, wajib
City string `json:"city" validate:"required"` // Kota, wajib
Planet string `json:"planet" validate:"required"` // Planet, wajib
Phone string `json:"phone" validate:"required"` // Telepon, wajib
}
type validationError struct {
ActualTag string `json:"tag"` // Tag aktual
Namespace string `json:"namespace"` // Namespace
Kind string `json:"kind"` // Jenis
Type string `json:"type"` // Tipe
Value string `json:"value"` // Nilai
Param string `json:"param"` // Parameter
}
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 {
// Tangani kesalahan, berikut adalah cara yang benar...
if errs, ok := err.(validator.ValidationErrors); ok {
// Bungkus kesalahan dalam format JSON, pustaka yang mendasarinya mengembalikan kesalahan berjenis antarmuka.
validationErrors := wrapValidationErrors(errs)
// Kembalikan tanggapan application/json+problem dan hentikan menjalankan penanganan berikutnya
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Kesalahan Validasi").
Detail("Salah satu atau lebih bidang tidak lulus validasi").
Type("/user/validation-errors").
Key("errors", validationErrors))
return
}
// Mungkin kesalahan JSON internal, tidak ada informasi lebih lanjut yang disediakan di sini.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("Halaman ini digunakan untuk menjelaskan cara menyelesaikan kesalahan validasi kepada pengembang web atau pengguna API")
}
Permintaan Contoh
{
"fname": "",
"lname": "",
"age": 45,
"email": "[email protected]",
"favColor": "#000",
"addresses": [{
"street": "Pelabuhan Eavesdown",
"planet": "Persphone",
"phone": "tidak ada",
"city": "Tidak Dikenal"
}]
}
Tanggapan Contoh
{
"title": "Error Validasi",
"detail": "Satu atau lebih bidang gagal divalidasi",
"type": "http://localhost:8080/user/validation-errors",
"status": 400,
"fields": [
{
"tag": "dibutuhkan",
"namespace": "User.FirstName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
},
{
"tag": "dibutuhkan",
"namespace": "User.LastName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
}
]
}
Mengikat parameter kueri URL
Metode ReadQuery
hanya mengikat parameter kueri, bukan data permintaan tubuh. Gunakan ReadForm
untuk mengikat data permintaan tubuh.
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("Success")
}
Mengikat data sembarang
Ikatan tubuh permintaan ke "ptr" berdasarkan jenis konten data yang dikirim oleh klien, seperti JSON, XML, YAML, MessagePack, Protobuf, Form, dan kueri 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("Person: %#+v", person)
ctx.WriteString("Success")
}
Anda dapat menguji dengan perintah berikut:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
Mengikat parameter jalur 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("myParams: %#v", p)
})
app.Listen(":8088")
}
Permintaan
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
Mengikat parameter header permintaan
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")
}
Permintaan
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
Respon
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}