Gin framework introduction and use of
Gin
Go is a language with a web framework. It is a similar martini
but API framework has better performance, due to the use httprouter
, speed of nearly 40 times. If you are the performance and efficiency of suitors, you'll love Gin
.
Gin framework introduced
Go world's most popular Web framework, Github have the 32K+
star. Based httprouter Web development framework. Chinese documents complete, easy to use lightweight frame.
Installation and use of the frame Gin
installation
Download and install Gin
:
$ go get -u github.com/gin-gonic/gin
Gin first example:
main Package Import ( "github.com/gin-gonic/gin" ) FUNC main () { // create a default routing engine R & lt: gin.Default = () // the GET: Request embodiment; / hello: route request // when a client request method GET / hello path, anonymous function is executed later r.get ( "/ hello", FUNC (gin.Context * c) { // c.JSON: returns JSON format data c .json (200, gin.H { "the Message": "! the Hello world", }) }) // start the HTTP service, default in 0.0.0.0:8080 start the service r.Run () }
Save the above code and compile execute, and then use the browser to open 127.0.0.1:8080/hello
you can see a bunch of JSON string.
RESTful API
REST has nothing to do with technology, represent a style of software architecture, REST is Representational State Transfer abbreviation , the Chinese translation for "characterize the state transfer" or "presentation layer state transformation."
Recommended reading Ruan Yifeng understand RESTful architecture
Simply put, REST is the meaning when the interworking between the client and the Web server, using different protocols HTTP request methods of four representatives of the action.
GET
For access to resourcesPOST
New Resource forPUT
Used to update the resourceDELETE
To delete the resource.
As long as the program follows the REST-style API, you can call RESTful API. Separating the rear end of the current architecture front to front and rear ends are substantially interact through RESTful API.
For example, we now want to write a book management system, we can search for a book to query, create, update and delete operations, we will design the client browser when writing programs interact with our Web server's ways and paths. According to our experience usually designed to the following pattern:
Request method | URL | meaning |
---|---|---|
GET | /book | Information inquiry book |
POST | /create_book | Creating record books |
POST | /update_book | Update books information |
POST | /delete_book | Delete book information |
Also according to the needs of our RESTful API design are as follows:
Request method | URL | meaning |
---|---|---|
GET | /book | Information inquiry book |
POST | /book | Creating record books |
PUT | /book | Update books information |
DELETE | /book | Delete book information |
Gin development framework to support the development of RESTful API.
func main() { r := gin.Default() r.GET("/book", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "GET", }) }) r.POST("/book", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "POST", }) }) r.PUT("/book", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "PUT", }) }) r.DELETE("/book", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "DELETE", }) }) }
Development of RESTful API's when we typically use Postman as a client test tool.
Gin rendering
HTML rendering
We first define a template file storage templates
folder, then in its internal operations are defined in accordance with a posts
folder and a users
folder. posts/index.html
Contents of the file are as follows:
{{define "posts/index.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>posts/index</title> </head> <body> {{.title}} </body> </html> {{end}}
users/index.html
Contents of the file are as follows:
{{define "users/index.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>users/index</title> </head> <body> {{.title}} </body> </html> {{end}}
Gin used in the framework LoadHTMLGlob()
orLoadHTMLFiles()
methods to render HTML template.
func main() { r := gin.Default() r.LoadHTMLGlob("templates/**/*") //r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html") r.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.html", gin.H{ "title": "posts/index", }) }) r.GET("users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.html", gin.H{ "title": "users/index", }) }) r.Run(":8080") }
Static file handling
When we render HTML file references static files, we only need to call in the following manner before rendering the page gin.Static
methods can be.
func main() { r := gin.Default() r.Static("/static", "./static") r.LoadHTMLGlob("templates/**/*") // ... r.Run(":8080") }
Supplement path processing
About path to the template files and static files, we need to be set according to the company / project. You can use the following function to get the current execution path of the program.
func getCurrentPath() string { if ex, err := os.Executable(); err == nil { return filepath.Dir(ex) } return "./" }
Rendering JSON
main FUNC () { R & lt: gin.Default = () // gin.H a map [string] interface {} Abbreviation r.get ( "/ someJSON", FUNC (C * gin.Context) { // a manner : their splicing the JSON c.JSON (http.StatusOK, gin.H { "Message": "! the Hello World"}) }) r.get ( "/ moreJSON", FUNC (C * gin.Context) { // method II: use structure var struct {MSG the Name String JSON `:" User "` the Message String Age int } MSG.NAME = "prince" msg.Message = "the Hello World!" msg.Age = 18 is c.JSON (HTTP .StatusOK, MSG) }) r.Run ( ": 8080") }
XML Rendering
Attention to the need to use the type of structure to be named.
main FUNC () { R & lt: gin.Default = () // gin.H a map [string] interface {} Abbreviation r.get ( "/ someXML", FUNC (C * gin.Context) { // a manner : their splicing the JSON c.XML (http.StatusOK, gin.H { "Message": "! the Hello World"}) }) r.get ( "/ moreXML", FUNC (C * gin.Context) { // method II: use structure type struct {MessageRecord the Name String the Message String Age int } var MSG MessageRecord MSG.NAME = "prince" msg.Message = "the Hello World!" msg.Age = 18 is c.XML (http.StatusOK, MSG ) }) r.Run ( ": 8080") }
YMAL rendering
r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{"message": "ok", "status": http.StatusOK}) })
protobuf rendering
r.get ( "/ someProtoBuf", FUNC (C * gin.Context) { reps: = [] {Int64 Int64 (. 1), Int64 (2)} label: = "Test" // Protobuf specific definition written in testdata / protoexample file. data: = {& protoexample.Test the label: & label, reps: reps, } // Note that the data in the response binary data becomes // will be protoexample.Test protobuf output data sequence of the c. protobuf (http.StatusOK, Data) })
Acquisition parameters
Get querystring parameters
querystring
It refers to the URL ?
carried behind parameters, such as: /user/search?username=小王子&address=沙河
. The method of obtaining the requested querystring parameters as follows:
main FUNC () { // return a default the Default Routing Engine R & lt: = gin.Default () r.get ( "/ User / Search", FUNC (C * gin.Context) { username: = c.DefaultQuery ( " username "," The little Prince ") // username: = c.Query (" username ") address: = c.Query (" address ") // output json results to the caller c.JSON (http.StatusOK, gin. {H "Message": "OK", "username": username, "address": address, }) }) r.Run () }
Get the form parameters
Data request to submit a form by the form, for example, to /user/search
send a POST request, the request data acquisition mode as follows:
main FUNC () { // the Default Routing Engine returns a default = gin.Default (): R & lt r.POST ( "/ User / Search", FUNC (C * gin.Context) { while fail to values // DefaultPostForm returns the default value specified // username: = c.DefaultPostForm ( "username ", " the little Prince") username: = c.PostForm ( "username") address: = c.PostForm ( "address") // output json result to the caller c.JSON (http.StatusOK, gin.H { "Message": "OK", "username": username, "address": address, }) }) r.Run ( ": 8080") }
Gets the path parameter
Parameter request URL path passing through, for example: /user/search/小王子/沙河
. Acquisition parameters in the request URL path as follows.
main FUNC () { // return a default the Default Routing Engine R & lt: = gin.Default () r.get ( "/ User / Search /: username /: address", FUNC (C * gin.Context) { username: c.Param = ( "username") address: = c.Param ( "address") // outputs the result to the caller json c.JSON (http.StatusOK, gin.H { "Message": "OK", "username ": username, " address ": address, }) }) r.Run (": 8080 ") }
Parameter binding
In order to more easily access request relevant parameters, to improve development efficiency, we can request based on Content-Type
request identification data types and automatically extracts the request using reflection QueryString
, form表单
, JSON
, XML
and other parameters of the structure. The following sample code demonstrates the .ShouldBind()
powerful, it can be automatically extracted based on a request JSON
, form表单
and the QueryString
type of data, and the value of the structure bound to the specified object.
// Binding from JSON type Login struct { User string `form:"user" json:"user" binding:"required"` Password string `form:"password" json:"password" binding:"required"` } func main() { router := gin.Default() // 绑定JSON的示例 ({"user": "q1mi", "password": "123456"}) router.POST("/loginJSON", func(c *gin.Context) { var login Login if err := c.ShouldBind(&login); err == nil { fmt.Printf("login info:%#v\n", login) c.JSON(http.StatusOK, gin.H{ "user": login.User, "password": login.Password, }) } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) if err: = c.ShouldBind(&login); err == nil { // form form exemplary binding (User password = & q1mi = 123456) router.POST ( "/ loginForm", FUNC (C * gin.Context) { var the Login Login // ShouldBind () will be selected according to self-tie Content-Type request Tuner IF ERR: = c.ShouldBind (& Login); ERR == nil { c.JSON (http.StatusOK, gin.H { "User": login.User, "password": login.Password, }) } the else { c.JSON (http.StatusBadRequest, gin.H { "error": err.Error ()}) } }) // QueryString exemplary binding (/ = q1mi & loginQuery User password = 123456)? router.GET ( "/ loginForm ", FUNC (C * gin.Context) { var the Login Login // ShouldBind () will be selected according to bind request itself Content-Type c.JSON (http.StatusOK, gin.H{ "user": login.User, "password": login.Password, }) } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) // Listen and serve on 0.0.0.0:8080 router.Run(":8080") }
ShouldBind
Will complete the binding sequence resolution request according to the data below: 1. If a GET
request, using only Form
the binding engine ( query
). 2. If a POST
request checks content-type
whether JSON
or XML
before use Form
( form-data
).
File Upload
Single File Upload
main FUNC () { Router: gin.Default = () // Default processing multipart forms when memory limits are submissions MiB 32 // can be modified in the following manner // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST ( "/ Upload", FUNC (C * gin.Context) { // single file file, ERR: = c.FormFile ( "file") IF ERR = nil {! c.JSON (http.StatusInternalServerError, Gin {.H "Message": err.Error (), }) return } log.Println (file.Filename) DST: fmt.Sprintf = ( "C: / tmp /% S", file.Filename) // uploaded to the specified directory c.SaveUploadedFile (File, DST) c.JSON (http.StatusOK, gin.H { "Message": fmt.Sprintf ( " '% S' uploaded the!", File.Filename),Filename), }) }) router.Run() }
Upload multiple files
main FUNC () { Router: gin.Default = () // Default processing multipart forms when memory limits are submissions MiB 32 // can be modified in the following manner // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST ( "/ Upload", FUNC (C * gin.Context) { // form Multipart form, _: = c.MultipartForm () Files: form.File = [ "File"] for index, File: = Range {files log.Println (file.Filename) DST: fmt.Sprintf = ( "C: / tmp / S_% D%", file.Filename, index) // upload the file to the specified directory c.SaveUploadedFile (file, dst ) } c.JSON (http.StatusOK, gin.H { "Message": fmt.Sprintf ( "!% Files uploaded The D", len (Files)), }) }) Router.Run() }
Gin Middleware
Gin framework allows developers in processing request, the user's own added hook (Hook) function . The hook function is called middleware, middleware for dealing with some common business logic, such as login verification, log printing, time-consuming statistics.
Gin in the middleware must be a gin.HandlerFunc
type . For example, we define as a middleware like the following code.
// StatCost is a statistical time-consuming request time-consuming middleware FUNC StatCost () {gin.HandlerFunc return FUNC (c * gin.Context) { Start: = Time.now () c.Set ( "name", "small Prince ") // perform other middleware c.Next () // Processed calculated cost: time.Since = (Start) log.Println (cost) } }
Then the time of registration middleware, can be registered globally.
main FUNC () { // create a default without any intermediate route R & lt: gin.New = () // a global register middleware r.Use (StatCost ()) r.get ( "/ Test", FUNC ( * gin.Context C) { name:. = c.MustGet ( "name") (String) log.Println (name) c.JSON (http.StatusOK, gin.H { "Message": "the Hello World!", }) }) r.Run () }
Middleware can also be individually registered to a route.
// a / test2 registered route separate piece (can register multiple) r.get ( "/ test2", StatCost (), FUNC (C * gin.Context) { name: = c.MustGet ( "name"). (String) log.Println (name) c.JSON (http.StatusOK, gin.H { "Message": "the Hello World!", }) })
Redirect
HTTP redirection
HTTP redirects is easy. Internal, external redirect support.
r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/") })
Route Redirection
Routing redirection, use HandleContext
:
r.GET("/test", func(c *gin.Context) { // 指定重定向的URL c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"hello": "world"}) })
Gin route
Normal routing
r.GET("/index", func(c *gin.Context) {...}) r.GET("/login", func(c *gin.Context) {...}) r.POST("/login", func(c *gin.Context) {...})
In addition, there is a request to match all of the methods Any
as follows:
r.Any("/test", func(c *gin.Context) {...})
Is not configured to add the routing processing function handler 404 by default it returns the code, the following code is not matched to the routing request return views/404.html
page.
r.NoRoute(func(c *gin.Context) { c.HTML(http.StatusNotFound, "views/404.html", nil) })
Routing Group
We can have a common URL prefix routed into one routing group. Habitual one pair {}
routing parcel of the same group, just to look at clarity, do you need {}
no difference to the package features.
func main() { r := gin.Default() userGroup := r.Group("/user") { userGroup.GET("/index", func(c *gin.Context) {...}) userGroup.GET("/login", func(c *gin.Context) {...}) userGroup.POST("/login", func(c *gin.Context) {...}) } shopGroup := r.Group("/shop") { shopGroup.GET("/index", func(c *gin.Context) {...}) shopGroup.GET("/cart", func(c *gin.Context) {...}) shopGroup.POST("/checkout", func(c *gin.Context) {...}) } r.Run() }
Usually we will use to route packets when divided or partitioned business logic API version.
Routing principles
Gin frame routing using httprouter this library.
The basic principle is that a routing address prefix tree structure.