This is the 13th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Gin is a standard Web services framework that follows the Restful API specification and its routing library is based on Httproute implementation.

This section describes how to use Gin in various routing scenarios, starting with Gin routing.

The basic routing

Gin supports GET, POST, PUT, PATCH, DELETE, and OPTIONS request types.

Example:

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main(a) {
	route := gin.Default()

	// Set a GET request with a URL of /hello and implement a simple response
	route.GET("/get".func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "this is a get method response!",})})// Implementations can define a separate function
	route.POST("/post", postHandler)

	route.PUT("/put".func(c *gin.Context) {

	})

	route.PATCH("/patch".func(c *gin.Context) {

	})

	route.DELETE("/delete".func(c *gin.Context){})/ /...

	route.Run()
}

func postHandler(c *gin.Context) {
	c.JSON(http.StatusOK, "this is a post method response!")}Copy the code

Processing parameters

The path parameter

The Param function of *gin.Context is used to obtain the parameters in the Path of the request. The parameters in the Path start with:, such as: /user/:name, which matches the Path /user/xx.

Example:

package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

type User struct {
	Username string   `json:"username"`
	Sex      string   `json:"sex"`
	Age      int      `json:"age"`
	Labels   []string `json:"lalels"`
}

func main(a) {
	route := gin.Default()

	users := []User{
		{
			Username: "xcbeyond",
			Sex:      "Male",
			Age:      18,
			Labels:   []string{"Young"."Handsome"}},}// There are parameters in the request path
	route.GET("/user/:name".func(c *gin.Context) {
		// Get the parameters in the request path
		name := c.Param("name")
		for _, user := range users {
			if user.Username == name {
				c.JSON(http.StatusOK, user)
				return
			}
		}
		c.JSON(http.StatusOK, fmt.Errorf("not found user [%s]", name))
	})

	route.Run()
}

Copy the code

Query parameters

You can take arguments from the Query function of *gin.Context, such as: /user? Name = xcbeyond.

Example:

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type User struct {
	Username string   `json:"username"`
	Sex      string   `json:"sex"`
	Age      int      `json:"age"`
	Labels   []string `json:"lalels"`
}

func main(a) {
	route := gin.Default()

	users := []User{
		{
			Username: "xcbeyond",
			Sex:      "Male",
			Age:      18,
			Labels:   []string{"Young"."Handsome"}},}// Query parameters, such as: /user? name=xcbeyond
	route.GET("/user".func(c *gin.Context) {
		// Get the parameters in
		name := c.Query("name")
		for _, user := range users {
			if user.Username == name {
				c.JSON(http.StatusOK, user)
				return
			}
		}
		c.JSON(http.StatusOK, "not found user "+name)
	})

	route.Run()
}

Copy the code

Routing group

Gin provides the capability of grouping routes to facilitate group management. It classifies routes that have the same URL prefix. These routes are grouped in different versions, for example, / API /v1 and/API /v1.

In addition, multi-level grouping is supported.

Example:

package main

import (
	"math/rand"
	"net/http"

	"github.com/gin-gonic/gin"
)

type User struct {
	Username string   `json:"username"`
	Sex      string   `json:"sex"`
	Age      int      `json:"age"`
	Labels   []string `json:"lalels"`
}

func main(a) {
	route := gin.Default()

	users := []User{
		{
			Username: "xcbeyond",
			Sex:      "Male",
			Age:      18,
			Labels:   []string{"Young"."Handsome"},
		},
		{
			Username: "niki",
			Sex:      "Female",
			Age:      16,
			Labels:   []string{"Beautiful"}},}/ / API group
	api := route.Group("/api")
	{
		/ / v1 grouping
		v1 := api.Group("/v1")
		{
			v1.GET("/user/:name".func(c *gin.Context) {
				name := c.Param("name")
				for _, user := range users {
					if user.Username == name {
						c.JSON(http.StatusOK, user)
						return
					}
				}
				c.JSON(http.StatusOK, "not found user :"+name)
			})
		}

		/ / v2 grouping
		v2 := api.Group("/v2")
		{
			v2.GET("/user/:name".func(c *gin.Context) {
				name := c.Param("name")
				for _, user := range users {
					if user.Username == name {
						c.JSON(http.StatusOK, user)
						return}}// If none is found, return one randomly
				user := users[rand.Intn(len(users)- 1)]
				c.JSON(http.StatusOK, "not found user ["+name+"],but user ["+user.Username+"] is exist!")
			})
		}
	}

	route.Run()
}

Copy the code

Routing split

In the routing examples above, all routing information is written in the same source file, function, but in a real project involving a large number of interfaces, it is not appropriate to write together.

In a real project, we would prefer to split the routing code into separate packages, multiple routing source files, and so on.

According to the size of the actual project, it can be divided into different granularity.

(The following route split is for reference only and can be flexibly adjusted according to specific projects!)

Routes are split into individual source files or packets

Separating the routing implementation into a separate package makes the project structure clearer. The project structure is as follows:

.├ ─ main.go ├── routes.goCopy the code

Example complete source code: route-split-v1

Implement and register routing information in the /routes/routes.go file:

package routes

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type User struct {
	Username string   `json:"username"`
	Sex      string   `json:"sex"`
	Age      int      `json:"age"`
	Labels   []string `json:"lalels"`
}

var users []User

// For testing purposes, the value is assigned directly in init mode. In actual projects, data is usually obtained through other methods such as database query.
func init(a) {
	users = []User{
		{
			Username: "xcbeyond",
			Sex:      "Male",
			Age:      18,
			Labels:   []string{"Young"."Handsome"},
		},
		{
			Username: "niki",
			Sex:      "Female",
			Age:      16,
			Labels:   []string{"Beautiful"}},}}// SetupRouter Configures routes
func SetupRouter(a) *gin.Engine {
	route := gin.Default()

	route.GET("/user/:name", querUserHandler)
	// More routes

	return route
}

// handler
func querUserHandler(c *gin.Context) {
	name := c.Param("name")
	for _, user := range users {
		if user.Username == name {
			c.JSON(http.StatusOK, user)
			return
		}
	}
	c.JSON(http.StatusOK, "not found user :"+name)
}

Copy the code

Call SetupRouter in main.go:

func main(a) {
	route := routes.SetupRouter()
	iferr := route.Run(); err ! =nil {
		fmt.Printf("startup server failed,err: %v", err)
	}
}
Copy the code

The route is split into multiple source files

As the service functions of the project become rich and the volume becomes larger, all routes are written in a routes.go source file, resulting in more and more bloated source file, which is not easy to maintain and read in the later period.

Therefore, it can be split into multiple routing files according to a certain dimension to achieve different business functions. The project structure is as follows:

. ├ ─ ─ main. Go └ ─ ─ routes ├ ─ ─ auth. Go ├ ─ ─ routes. Go └ ─ ─ user. GoCopy the code

Example complete source code: route-split-V2

The Routes package is divided into multiple routing implementation files based on certain dimensions. For example, the routes can be divided into authentication module (auth.go) and user module (user.go) based on service modules. The routes file implements specific service functions and implements route registration.

For example, authentication module auth.go:

package routes

import (
	"github.com/gin-gonic/gin"
)

// AuthRegister route register
func AuthRegister(e *gin.Engine) {
	e.GET("/auth/login", loginHandler)
	e.POST("/auth/logout", logoutUserHanler)
	/ /...
}

// loginHandler
func loginHandler(c *gin.Context){}// logoutUserHanler
func logoutUserHanler(c *gin.Context){}Copy the code

The AuthRegister function is defined to register all routes under the module. Note that this function starts with an uppercase letter and can be called as a global function outside the package main.go.

In routes/routes. Go, configure routes and register routes for all modules.

package routes

import (
	"github.com/gin-gonic/gin"
)

// SetupRouter Configures routes
func SetupRouter(a) *gin.Engine {
	route := gin.Default()

	// other config

	// register all route.
	UserRegister(route)
	AuthRegister(route)
	/ /...

	return route
}

Copy the code

Main. go, as in the previous version, serves as an entry point for programs and so on:

func main(a) {
	route := routes.SetupRouter()
	iferr := route.Run(); err ! =nil {
		fmt.Printf("startup server failed,err: %v", err)
	}
}
Copy the code

References:

  1. api-examples
  2. Gin framework route splitting and registration