الأقسام السابقة قد قدمت طريقة قراءة معلمات الطلب مباشرة. إذا كان من الصعب قراءة كل معلمة على حدة، فإن إطار العمل iris يوفر أيضًا آلية ربط المعلمات، والتي يمكن أن ترتبط بمعلمات الطلب إلى هيكل بيانات، وتدعم أيضًا آلية التحقق من صحة معلمة النموذج.
الارتباط بالنماذج والتحقق من الصحة
لربط جسم الطلب بنوع معين، استخدم الارتباط بالنموذج. حاليًا، نحن ندعم أنواع ارتباط مثل "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
، سيقوم Iris بالتحقق من وجود النموذج بناءً على رأس الطلب Content-Type. إذا كنت متأكدًا من النموذج الذي تريد ربطه، يمكنك استخدام الأساليب المحددة ReadXXX
مثل ReadJSON
أو ReadProtobuf
.
ReadBody(ptr interface{}) error
تأتي Iris مع التحقق الذكي المدمج للبيانات. ومع ذلك، يتيح لك إرفاق محقق يتم استدعاؤه تلقائيًا على الأساليب مثل ReadJSON
، ReadXML
، وما إلى ذلك. في هذا المثال، سنتعلم كيفية استخدام go-playground/validator/v10 للتحقق من صحة جسم الطلب.
يرجى ملاحظة أنه يجب عليك ضبط العلامات المقابلة للارتباط على جميع الحقول التي سيتم ربطها. على سبيل المثال، عند الربط من JSON، ضع json:"اسم_الحقل"
.
يمكنك أيضًا تحديد بعض الحقول كحقول مطلوبة. إذا كان لحقل الزينة binding:"مطلوب"
ولم يتم توفير قيمة أثناء الربط، سيتم إرجاع خطأ.
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")
}
// النوع المستخدم لتخزين معلومات المستخدم.
type User struct {
FirstName string `json:"fname" validate:"required"` // الاسم الأول، مطلوب
LastName string `json:"lname" validate:"required"` // الاسم الأخير، مطلوب
Age uint8 `json:"age" validate:"gte=0,lte=130"` // العمر، يتراوح بين 0 و 130
Email string `json:"email" validate:"required,email"` // البريد الإلكتروني، مطلوب
FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` // اللون المفضل، يجب أن يكون قيمة لون سداسي عشري أو RGB أو RGBA صالحة
Addresses []*Address `json:"addresses" validate:"required,dive,required"` // قائمة العناوين، يجب ألا تكون فارغة وكل عنوان مطلوب
}
// تخزين معلومات عنوان المستخدم.
type Address struct {
Street string `json:"street" validate:"required"` // الشارع، مطلوب
City string `json:"city" validate:"required"` // المدينة، مطلوبة
Planet string `json:"planet" validate:"required"` // الكوكب، مطلوب
Phone string `json:"phone" validate:"required"` // الهاتف، مطلوب
}
type validationError struct {
ActualTag string `json:"tag"` // العلامة الفعلية
Namespace string `json:"namespace"` // النطاق
Kind string `json:"kind"` // النوع
Type string `json:"type"` // النوع
Value string `json:"value"` // القيمة
Param string `json:"param"` // المعلمة
}
// تغليف أخطاء التحقق.
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 {
// التعامل مع الأخطاء، الطريقة الصحيحة...
if errs, ok := err.(validator.ValidationErrors); ok {
// تغليف الأخطاء بتنسيق JSON، تقوم المكتبة الأساسية بإرجاع الأخطاء من نوع واجهة.
validationErrors := wrapValidationErrors(errs)
// إرجاع استجابة بتنسيق application/json+problem وإيقاف تنفيذ المعالجات التالية
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("أخطاء التحقق").
Detail("تفشل واحدة أو أكثر من الحقول في التحقق").
Type("/user/validation-errors").
Key("errors", validationErrors))
return
}
// قد تكون خطأ JSON داخليًا، لا توجد معلومات إضافية مقدمة هنا.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "حسنًا"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("يتم استخدام هذه الصفحة لشرح كيفية حل أخطاء التحقق لمطوري الويب أو مستخدمي واجهة برمجة التطبيقات")
}
{
"عنوان": "خطأ في التحقق",
"تفاصيل": "فشلت أحد أو أكثر من الحقول في التحقق",
"نوع": "http://localhost:8080/user/validation-errors",
"الحالة": 400,
"حقول": [
{
"وسم": "مطلوب",
"نطاق": "User.FirstName",
"نوع": "سلسلة",
"نوع": "سلسلة",
"قيمة": "",
"معلمة": ""
},
{
"وسم": "مطلوب",
"نطاق": "User.LastName",
"نوع": "سلسلة",
"نوع": "سلسلة",
"قيمة": "",
"معلمة": ""
}
]
}
ربط معلمات الاستعلام في عنوان 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("الشخص: %#+v", person)
ctx.WriteString("نجاح")
}
ربط بيانات متغيرة
قم بربط جسم الطلب إلى "ptr" استنادًا إلى نوع محتوى البيانات المرسلة بواسطة العميل، مثل JSON، XML، YAML، MessagePack، Protobuf، نموذج، واستعلام 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("الشخص: %#+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"
}