Önceki bölümler, istek parametrelerini doğrudan okumanın yöntemini tanıttı. Her bir parametreyi ayrı ayrı okumak zorluysa, iris çerçevesi ayrıca bir parametre bağlama mekanizması da sağlar, bu mekanizma istek parametrelerini bir yapıya bağlayabilir ve ayrıca bir form parametre doğrulama mekanizmasını da destekler.

Model Bağlama ve Doğrulama

İsteği bir türe bağlamak için model bağlama kullanılır. Şu anda, JSON, JSONProtobuf, Protobuf, MsgPack, XML, YAML ve standart form değerleri (foo=bar&boo=baz) gibi tipleri bağlama desteği sunmaktayız.

// Aşağıda, çeşitli formatlardaki istek parametrelerini bir yapıya bağlamak için işlev tanımlamaları bulunmaktadır
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 kullanırken, Iris, Content-Type başlığına dayalı bağlayıcıyı çıkaracaktır. Bağlamak istediğiniz içeriği kesin olarak biliyorsanız, belirli ReadXXX yöntemlerini, örneğin ReadJSON veya ReadProtobuf kullanabilirsiniz.

ReadBody(ptr interface{}) error

Iris, akıllı yerleşik veri doğrulamayla birlikte gelir. Bununla birlikte, ReadJSON, ReadXML vb. gibi yöntemlerde otomatik olarak çağrılacak bir doğrulayıcı eklemenize izin verir. Bu örnekte, isteği doğrulamak için go-playground/validator/v10 kullanımını öğreneceğiz.

Lütfen dikkat edin, bağlanacak tüm alanlara karşılık gelen bağlama etiketlerini ayarlamanız gerekmektedir. Örneğin, JSON'dan bağlarken, json:"alanadı" şeklinde ayarlayın.

Ayrıca belirli alanları zorunlu alanlar olarak belirtebilirsiniz. Bir alanın binding:"required" dekorasyonuna sahip olması ve bağlanırken bir değer sağlanmaması durumunda bir hata döndürülecektir.

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("/kullanıcı")
	{
		userRouter.Get("/doğrulama-hataları", resolveErrorsDocumentation)
		userRouter.Post("/", postUser)
	}
	app.Listen(":8080")
}

// User contains user information.
type User struct {
	FirstName      string     `json:"ad" validate:"required"` // İsim, gerekli
	LastName       string     `json:"soyad" validate:"required"` // Soyisim, gerekli
	Age            uint8      `json:"yaş" validate:"gte=0,lte=130"` // Yaş, 0 ile 130 arasında bir değer olmalı
	Email          string     `json:"e-posta" validate:"required,email"` // E-posta, gerekli
	FavouriteColor string     `json:"sevilenRenk" validate:"hexcolor|rgb|rgba"` // Favori renk, geçerli bir onaltılık, RGB veya RGBA renk değeri olmalı
	Addresses      []*Address `json:"adresler" validate:"required,dive,required"` // Adres listesi, boş olmamalı ve her adres ögesi gerekli
}

// Address stores user address information.
type Address struct {
	Street string `json:"sokak" validate:"required"` // Sokak, gerekli
	City   string `json:"şehir" validate:"required"` // Şehir, gerekli
	Planet string `json:"gezegen" validate:"required"` // Gezegen, gerekli
	Phone  string `json:"telefon" validate:"required"` // Telefon, gerekli
}

type validationError struct {
	ActualTag string `json:"etiket"` // Gerçek etiket
	Namespace string `json:"adAlanı"` // Ad alanı
	Kind      string `json:"tür"` // Tür
	Type      string `json:"tür"` // Tür
	Value     string `json:"değer"` // Değer
	Param     string `json:"parametre"` // Parametre
}

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 {
		// Hataları ele al, aşağıdaki doğru yolu...

		if errs, ok := err.(validator.ValidationErrors); ok {
			// Hataları JSON biçiminde paketle, alttaki kütüphane hataları arayüz türünde döndürür.
			validationErrors := wrapValidationErrors(errs)

			// Bir application/json+problem yanıtı döndür ve sonraki işlemleri durdur
			ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
				Title("Doğrulama Hataları").
				Detail("Bir veya daha fazla alan doğrulamayı geçemedi").
				Type("/user/doğrulama-hataları").
				Key("hatalar", validationErrors))

			return
		}

		// İçsel bir JSON hatası olabilir, burada daha fazla bilgi sağlanmamıştır.
		ctx.StopWithStatus(iris.StatusInternalServerError)
		return
	}

	ctx.JSON(iris.Map{"mesaj": "OK"})
}

func resolveErrorsDocumentation(ctx iris.Context) {
	ctx.WriteString("Bu sayfa doğrulama hatalarını web geliştiricilere veya API kullanıcılarına nasıl çözeceklerini açıklamak için kullanılır")
}
{
    "fname": "",
    "lname": "",
    "age": 45,
    "email": "[email protected]",
    "favColor": "#000",
    "addresses": [{
        "street": "Eavesdown Docks",
        "planet": "Persphone",
        "phone": "none",
        "city": "Unknown"
    }]
}

Örnek Yanıt

{
    "title": "Doğrulama Hatası",
    "detail": "Bir veya daha fazla alan doğrulamayı geçemedi",
    "type": "http://localhost:8080/kullanıcı/doğrulama-hataları",
    "status": 400,
    "fields": [
        {
            "tag": "gerekli",
            "namespace": "Kullanıcı.Adı",
            "kind": "dize",
            "type": "dize",
            "value": "",
            "param": ""
        },
        {
            "tag": "gerekli",
            "namespace": "Kullanıcı.Soyadı",
            "kind": "dize",
            "type": "dize",
            "value": "",
            "param": ""
        }
    ]
}

URL sorgu parametrelerini bağlama

ReadQuery yöntemi, sadece sorgu parametrelerini bağlar, istek gövde verilerini bağlamaz. İstek gövde verilerini bağlamak için ReadForm yöntemini kullanın.

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("Başarılı")
}

Keyfi veri bağlama

İstemci tarafından gönderilen verinin içerik türüne bağlı olarak istek gövdesini "ptr" ile bağlayın, örneğin JSON, XML, YAML, MessagePack, Protobuf, Form ve URL sorgusu.

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("Başarılı")
}

Aşağıdaki komutla test edebilirsiniz:

$ curl -X GET "localhost:8085/testing?name=kataras&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"

URL yol parametrelerini bağlama

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")
}

İstek

$ curl -v http://localhost:8080/kataras/27/iris/web/framework

Başlık istek parametrelerini bağlama

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")
}

İstek

curl -H "x-request-id:373713f0-6b4b-42ea-ab9f-e2e04bc38e73" -H "authentication: Bearer my-token" \
http://localhost:8080

Yanıt

{
  "RequestID": "373713f0-6b4b-42ea-ab9f-e2e04bc38e73",
  "Authentication": "Bearer my-token"
}