بخشهای قبلی روش خواندن مستقیم پارامترهای درخواست را معرفی کرد. اگر خواندن هر پارامتر به طور جداگانه برایتان سخت است، فریمورک iris همچنین یک مکانیزم بایندینگ پارامترها ارائه میدهد که میتواند پارامترهای درخواست را به یک ساختار (struct) ببندد و همچنین یک مکانیزم اعتبارسنجی پارامتر فرم را نیز پشتیبانی میکند.
مدل بایندینگ و اعتبارسنجی
برای اتصال بدنه درخواست به یک نوع، از مدل بایندینگ استفاده کنید. در حال حاضر، ما پشتیبانی میکنیم از انواع بایندینگ مانند JSON
، JSONProtobuf
، Protobuf
، MsgPack
، XML
، YAML
و مقادیر استاندارد فرم (foo=bar&boo=baz).
// زیرا وظایف توابع برای بایند کردن پارامترهای درخواست به یک ساختار داده
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
هنگام استفاده از ReadBody
، ایریس با توجه به هدر Content-Type، بایندر را استخراج میکند. اگر مطمئن هستید درباره محتوا که میخواهید بایند کنید، میتوانید از متدهای خاص ReadXXX
مانند ReadJSON
یا ReadProtobuf
استفاده کنید.
ReadBody(ptr interface{}) error
ایریس با اعتبارسنجی داده هوشمند داخلی تامین میکند. با این حال، این امکان را به شما میدهد که یک اعتبارسنج را متصل کنید که به طور خودکار در متدهایی مانند ReadJSON
و ReadXML
فراخوانی میشود. در این مثال، ما یاد خواهیم گرفت چگونه از go-playground/validator/v10 برای اعتبارسنجی بدنه درخواست استفاده کنیم.
لطفاً توجه داشته باشید که شما باید برچسبهای بایندینگ مربوط را بر روی تمام فیلدها برای بایند کردن قرار دهید. به عنوان مثال، هنگام بایندینگ از JSON، json:"fieldname"
را تنظیم کنید.
همچنین میتوانید فیلدهای خاصی را به عنوان فیلدهای مورد نیاز مشخص کنید. اگر یک فیلد تزئین شده با binding:"required"
باشد و هیچ مقداری در هنگام بایند کردن فراهم نشود، یک خطا برگردانده خواهد شد.
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("/کاربر")
{
userRouter.Get("/errors-documentation", resolveErrorsDocumentation)
userRouter.Post("/", postUser)
}
app.Listen(":8080")
}
// User contains user information.
type User struct {
FirstName string `json:"نام" validate:"required"` // First name, required
LastName string `json:"نام_خانوادگی" validate:"required"` // Last name, required
Age uint8 `json:"سن" validate:"gte=0,lte=130"` // Age, range between 0 and 130
Email string `json:"ایمیل" validate:"required,email"` // Email, required
FavouriteColor string `json:"رنگ_مورد_علاقه" validate:"hexcolor|rgb|rgba"` // Favorite color, must be a legal hexadecimal, RGB, or RGBA color value
Addresses []*Address `json:"آدرسها" validate:"required,dive,required"` // Address list, must not be empty and each address item is required
}
// Address stores user address information.
type Address struct {
Street string `json:"خیابان" validate:"required"` // Street, required
City string `json:"شهر" validate:"required"` // City, required
Planet string `json:"سیاره" validate:"required"` // Planet, required
Phone string `json:"تلفن" validate:"required"` // Phone, required
}
type validationError struct {
ActualTag string `json:"tag"` // Actual tag
Namespace string `json:"namespace"` // Namespace
Kind string `json:"kind"` // Kind
Type string `json:"type"` // Type
Value string `json:"value"` // Value
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 {
// Handle errors, the following is the correct way...
if errs, ok := err.(validator.ValidationErrors); ok {
// Wrap errors in JSON format, the underlying library returns errors of type interface.
validationErrors := wrapValidationErrors(errs)
// Return an application/json+problem response and stop executing subsequent handlers
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Validation Errors").
Detail("One or more fields did not pass validation").
Type("/کاربر/خطاهای-اعتبارسنجی").
Key("errors", validationErrors))
return
}
// It might be an internal JSON error, no further information provided here.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"پیام": "با موفقیت"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("این صفحه برای توضیح نحوه رفع خطاهای اعتبارسنجی برای توسعه دهندگان و کاربران API استفاده میشود")
}
درخواست نمونه
{
"fname": "",
"lname": "",
"age": 45,
"email": "[email protected]",
"favColor": "#000",
"addresses": [{
"street": "Eavesdown Docks",
"planet": "Persphone",
"phone": "none",
"city": "نامشخص"
}]
}
پاسخ نمونه
{
"title": "خطا در اعتبارسنجی",
"detail": "یک یا چند فیلد با موفقیت اعتبارسنجی نشدهاند",
"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": ""
}
]
}
پیوند پارامترهای URL درخواست
متد ReadQuery
تنها پارامترهای پرس و جو را پیوند میکند و دادههای بدنه درخواست را پیوند نمیکند. برای پیوند دادههای بدنه از ReadForm
استفاده کنید.
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("موفقیت")
}
پیوند دادههای دلخواه
درخواست بدنه را بر اساس نوع محتوای دادهای ارسالی توسط مشتری به "ptr" پیوند کنید، مانند JSON، XML، YAML، MessagePack، Protobuf، Form، و پارامترهای 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("موفقیت")
}
میتوانید با دستور زیر تست کنید:
$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
پیوند پارامترهای مسیر 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")
}
درخواست
$ curl -v http://localhost:8080/kataras/27/iris/web/framework
پیوند پارامترهای درخواست سرآیند
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")
}
درخواست
curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080
پاسخ
{
"RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
"Authentication": "Bearer my-token"
}