Các phần trước đã giới thiệu phương pháp đọc trực tiếp các tham số yêu cầu. Nếu việc đọc từng tham số một cách rườm rà, framework iris cũng cung cấp cơ chế ràng buộc tham số, có thể ràng buộc các tham số yêu cầu vào một cấu trúc, và cũng hỗ trợ cơ chế xác nhận tham số của mẫu.
Ràng buộc và Xác thực Mô hình
Để ràng buộc nội dung yêu cầu vào một loại, hãy sử dụng ràng buộc mô hình. Hiện tại, chúng tôi hỗ trợ ràng buộc các loại như JSON
, JSONProtobuf
, Protobuf
, MsgPack
, XML
, YAML
, và các giá trị dạng biểu mẫu tiêu chuẩn (foo=bar&boo=baz).
// Dưới đây là định nghĩa hàm để ràng buộc tham số yêu cầu từ các định dạng khác nhau vào một struct
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
Khi sử dụng ReadBody
, Iris sẽ suy luận ràng buộc dựa trên tiêu đề Content-Type. Nếu bạn chắc chắn về nội dung mà bạn muốn ràng buộc, bạn có thể sử dụng các phương thức cụ thể ReadXXX
, như ReadJSON
hoặc ReadProtobuf
.
ReadBody(ptr interface{}) error
Iris đi kèm với xác thực dữ liệu tích hợp thông minh. Tuy nhiên, nó cho phép bạn đính kèm một trình xác thực sẽ được tự động gọi trên các phương thức như ReadJSON
, ReadXML
, v.v. Trong ví dụ này, chúng ta sẽ tìm hiểu cách sử dụng go-playground/validator/v10 để xác thực nội dung yêu cầu.
Vui lòng lưu ý rằng bạn cần thiết lập các thẻ ràng buộc tương ứng trên tất cả các trường cần ràng buộc. Ví dụ, khi ràng buộc từ JSON, hãy đặt json:"têntrường"
.
Bạn cũng có thể chỉ định các trường cụ thể là trường yêu cầu. Nếu một trường có trang trí binding:"required"
và không có giá trị nào được cung cấp trong quá trình ràng buộc, một lỗi sẽ được trả về.
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:"fname" validate:"required"` // Tên đầu tiên, bắt buộc
LastName string `json:"lname" validate:"required"` // Họ, bắt buộc
Age uint8 `json:"age" validate:"gte=0,lte=130"` // Tuổi, trong khoảng từ 0 đến 130
Email string `json:"email" validate:"required,email"` // Email, bắt buộc
FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` // Màu yêu thích, phải là giá trị màu hex, RGB hoặc RGBA hợp lệ
Addresses []*Address `json:"addresses" validate:"required,dive,required"` // Danh sách địa chỉ, không được trống và mỗi mục địa chỉ là bắt buộc
}
// Address stores user address information.
type Address struct {
Street string `json:"street" validate:"required"` // Đường, bắt buộc
City string `json:"city" validate:"required"` // Thành phố, bắt buộc
Planet string `json:"planet" validate:"required"` // Hành tinh, bắt buộc
Phone string `json:"phone" validate:"required"` // Điện thoại, bắt buộc
}
type validationError struct {
ActualTag string `json:"tag"` // Thẻ thực tế
Namespace string `json:"namespace"` // Namespace
Kind string `json:"kind"` // Loại
Type string `json:"type"` // Kiểu
Value string `json:"value"` // Giá trị
Param string `json:"param"` // Tham số
}
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 {
// Xử lý lỗi, dưới đây là cách đúng...
if errs, ok := err.(validator.ValidationErrors); ok {
// Bọc lỗi trong định dạng JSON, thư viện cơ sở trả về lỗi loại interface.
validationErrors := wrapValidationErrors(errs)
// Trả về ứng dụng/json+lỗi response và dừng việc thực hiện các xử lý tiếp theo
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Lỗi xác thực").
Detail("Một hoặc nhiều trường không vượt qua xác thực").
Type("/user/validation-errors").
Key("errors", validationErrors))
return
}
// Có thể là lỗi JSON nội bộ, không cung cấp thông tin cụ thể ở đây.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("Trang này được sử dụng để giải thích cách giải quyết lỗi xác thực đối với các nhà phát triển web hoặc người dùng API")
}
Yêu cầu Mẫu
{
"fname": "",
"lname": "",
"age": 45,
"email": "[email protected]",
"favColor": "#000",
"addresses": [{
"street": "Eavesdown Docks",
"planet": "Persphone",
"phone": "none",
"city": "Unknown"
}]
}
Phản hồi Mẫu
{
"title": "Lỗi Xác minh",
"detail": "Một hoặc nhiều trường không vượt qua xác minh",
"type": "http://localhost:8080/user/validation-errors",
"status": 400,
"fields": [
{
"tag": "required",
"namespace": "User.FirstName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
},
{
"tag": "required",
"namespace": "User.LastName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
}
]
}
Binding URL query parameters
Phương thức ReadQuery
chỉ ràng buộc các tham số truy vấn, không phải dữ liệu trong cơ thể yêu cầu. Sử dụng ReadForm
để ràng buộc dữ liệu trong cơ thể yêu cầu.
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("Thành công")
}
Ràng buộc dữ liệu tùy ý
Ràng buộc cơ thể yêu cầu vào "ptr" dựa trên loại nội dung của dữ liệu gửi bởi client, như JSON, XML, YAML, MessagePack, Protobuf, Form, và URL query.
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("Thành công")
}
Bạn có thể thử nghiệm bằng lệnh sau:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
Ràng buộc tham số đường dẫn 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")
}
Yêu cầu
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
Ràng buộc tham số yêu cầu tiêu đề
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")
}
Yêu cầu
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
Phản hồi
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}