Gin Framework – Part 6

Introduction

In the Gin framework, parameters can receive a key by designation and are directly bound to the structure. Let’s explain how it happens:

Binding method

Two types of binding methods exist in the Gin framework, Must bind and Should bind, and the corresponding methods of these two types are as follows:

Function Must bind method Should bind method
  Bind ShouldBind
JSON bind BindJSON ShouldBindJSON
XML bind BindXML ShouldBindXML
GET bind BindQuery ShouldBindQuery
YAML bind BindYAML ShouldBindYAML
  • MustBindWith and ShouldBindWith

Bind* A type’s method is an MustBindWith encapsulation; Should* a type’s method is ShouldBindWith an encapsulation;

  • Binding syntax

Define the bound structure

type StructName struct {
  Xxx  type  `form:"paramName" binding:"required"`
}

Label Description:

  • form:"paramName": paramName is the name of the parameter;
  • binding:"required": means that the field must be bound;

Bind the uri parameter

By using the function BindQuery and ShouldBindQuery, used to bind only GET the parameters in the request uri, such as: /funcName?a=x&b=x.

  • Code
//--------- main.go ---------------
package main

import (
	"fmt"
	"go_use/practise" // Code sample package

	"github.com/gin-gonic/gin" // Import Gin framework
)

func main() {
	engine := gin.Default()
	practise.TestBindQuery(engine)
	_ = engine.Run(":9090")
}

//------ go_use/practise/param_bind.go -------
// define structure
type UriParam struct {
	Name string `form:"name" binding:"required"`
	Age  int    `form:"age"`
	Home string `form:"home"`
}

// bind GET(BindQuery and ShouldBindQuery)
func TestBindQuery(engine *gin.Engine) {
	engine.GET("/bindQuery", func(context *gin.Context) {
		bindType := context.Query("type")
		var uriParam UriParam
		var err error
		if bindType == "1" {
			fmt.Println("BindQuery")
			err = context.BindQuery(&uriParam)
		} else {
			fmt.Println("ShouldBindQuery")
			err = context.ShouldBindQuery(&uriParam)
		}
		if err != nil {
			context.JSON(500, gin.H{"error": err.Error()})
			return
		}
		fmt.Printf("uriParam:%+v\n", uriParam)
		context.JSON(200, gin.H{"result": uriParam})
	})
}
  • Request
# All parameters are passed 
$ curl -X GET http://127.0.0.1:9090/bindQuery?age=25&name=Marsero&home=Mars&type=1
{"result":{"Name":"Marsero","Age":25,"Home":"Mars"}}
$ curl -X GET http://127.0.0.1:9090/bindQuery?age=25&name=Marsero&home=Mars&type=2
{"result":{"Name":"Marsero","Age":25,"Home":"Mars"}}
# If the required parameter name is not filled in, an error will be reported➜ 
curl -X GET http:// 127.0.0.1:9090/bindQuery?age=25&home=Mars&type=2
{"error":"Key: 'UriParam.Name' Error:Field validation for 'Name' failed on the 'required' tag"}

Bind JSON

Use functions BindJSON and ShouldBindJSON to bind submitted JSON parameter information.

  • Code
//--------- main.go ---------------
package main

import (
	"fmt"
	"go_use/practise" // code sample package

	"github.com/gin-gonic/gin" // Import Gin framework
)

func main() {
	engine := gin.Default()
	practise.TestBindJson(engine)
	_ = engine.Run(":9090")
}

//------ go_use/practise/param_bind.go -------
// Define the JSON structure to be bound
type Param struct {
	Name  string   `json:"name"`
	Age   int      ` json:"age"`
	Likes []string `json:"likes"`
}

// Bind the submitted Json data
func TestBindJson(engine *gin.Engine) {
	engine.POST("/bindJson", func(context *gin.Context) {
		var jsonParam Param
		var err error
		bindType := context.Query(" type")
		fmt.Println(bindType)
		if bindType == "1" {
			err = context.BindJSON(&jsonParam)
		} else {
			err = context.ShouldBindJSON(&jsonParam)
		}
		if err != nil {
			context.JSON(500, gin.H{"error": err})
			return
		}
		context.JSON(200, gin.H{"result": jsonParam})
	})
}
  • Request
# raw JSON code in the body
# {
#     "name":"Marsero",
#     "age":"25",
#     "likes":["books","traveling"],
# }

$ curl -X POST http://127.0.0.1:9090/bindJSON?type=1
{"result":{"name":"Marsero","age":25,"likes":["books","traveling"]}}

Binding XML

Use functions BindXML and ShouldBindXML to bind submitted XML parameter information.

  • Code
//--------- main.go ---------------
package main

import (
	"go_use/practise" // code sample package

	"github.com/gin-gonic/gin" // Import Gin framework
)

func main() {
	engine := gin.Default()
	practise.TestBindXml(engine)
	_ = engine.Run(":9090")
}

//------ go_use/practise/param_bind.go -------
// Modify the JSON structure to be bound, add XML tag
type Param struct {
	Name  string   `json:"name" xml:"name"`
	Age   int      `json:"age" xml:"age"`
	Likes []string `json:"likes" xml:"likes"`
}

// Bind Xml information
func TestBindXml(engine *gin.Engine) {
	engine.POST("/bindXml", func(context *gin.Context) {
		var param Param
		var err error
		bindType := context.Query("type")
		if bindType == "1" {
			err = context.BindXML(&param)
		} else {
			err = context.ShouldBindXML(&param)
		}
		if err != nil {
			context.JSON(500, gin.H{"error": err})
			return
		}
		context.JSON(200, gin.H{"result": param})
	})
}
  • Request
# raw XML code in the body
# <?xml version="1.0" encoding="UTF-8"?>
# <root>
#     <name>Marsero</name>
#     <name>25</name>
#     <likes>books</likes>
#     <likes>traveling</likes>
# </root>

$ curl -X POST http://127.0.0.1:9090/bindXML?type=2
{"result":{"name":"Marsero","age":25,"likes":["books","traveling"]}}

Binding request.Body

c.Request.Body Cannot be called multiple times, after the first binding c.Request.Body will be set to EOF.

  • Error example
//--------- main.go ---------------
package main

import (
	"go_use/practise" // code sample package

	"github.com/gin-gonic/gin" // Import Gin framework
)

func main() {
	engine := gin.Default()
	practise.TestBindXml(engine)
	_ = engine.Run(":9090")
}

//------ go_use/practise/param_bind.go -------
type BodyAParam struct {
	Name string `json:"name"`
}
type BodyBParam struct {
	Home string `json:"home"`
}

// Repeat binding request.Body (error example)
func TestBindBody(engine *gin.Engine) {
	engine.POST("/body", func(context *gin.Context) {
		paramA := BodyAParam{}
		paramB := BodyBParam{}
		// c.ShouldBind uses c.Request.Body, which is not reusable.
		_ = context.ShouldBindJSON(&paramA)
		// Since c.Request.Body is EOF now, an error will be reported here.
		_ = context.ShouldBindJSON(&paramB)
		context.JSON(200, gin.H{"paramA": paramA, "paramB": paramB})
	})
}
  • Request to return
# Found that only paramA was successfully bound 
$ curl -X POST http://127.0.0.1:9090/body -d '{"name":"Marsero","home":"Mars"}'
{"paramA":{"name":"Marsero"},"paramB":{"home":"Mars"}}
  • Correct example
//--------- main.go ---------------
package main

import (
	"go_use/practise" // code sample package

	"github.com/gin-gonic/gin" // Import Gin framework
)

func main() {
	engine := gin.Default()
	practise.TestBindXml(engine)
	_ = engine.Run(":9090")
}

//------ go_use/practise/param_bind.go -------
type BodyAParam struct {
	Name string `json:"name"`
}
type BodyBParam struct {
	Home string `json:"home"`
}

// Repeat binding request.Body (correct example)
func TestBindBody2(engine *gin.Engine) {
	engine.POST("/body2", func(context *gin.Context) {
		paramA := BodyAParam{}
		paramB := BodyBParam{}
		// Read c.Request.Body and store the result in the context.
		_ = context.ShouldBindBodyWith(&paramA, binding.JSON)
		// At this time, reuse the body stored in the context.
		_ = context.ShouldBindBodyWith(&paramB, binding.JSON)
		context.JSON(200, gin.H{"paramA": paramA, "paramB": paramB})
	})
}
  • Request to return
# Both paramA and paramB are successfully bound 
$ curl -X POST http://127.0.0.1:9090/body2 -d '{"name":"Marsero","home":"Mars"}'
{"paramA":{"name":"Marsero"},"paramB":{"home":"Mars"}}