SoFunction
Updated on 2025-03-05

Accelerating development: A powerful tool for building web projects using Go and Gin frameworks

Save time and energy, and create a stable and reliable web project more efficiently: a complete web project skeleton based on Go language and Gin framework. No need to start from scratch, use this skeleton to quickly build a fully functional and excellent performance Web application. Give full play to the advantages of the Go language and Gin framework to easily handle high-concurrency and large-traffic requests. Build a code architecture that is highly scalable and easy to maintain to ensure the long-term and stable operation of the project. At the same time, by integrating common functional modules and best practices, you can reduce tedious development work and focus on the implementation of business logic.

The skeleton can be used separately between each component, loosely coupled between components, and high cohesion, and the implementation of the component is based on the packaging of other three-party dependencies.
Currently this skeleton implements most components, such asevent,middleware,log,Configuration,Parameter verification,Command line,Timing tasksFunctions such as this can meet most development needs at present, and update functions will be continuously maintained in the future.

github address: /czx-lab/skeleton

Set environment variables and download project dependencies

go env -w GO111MODULE=on
go env -w GOPROXY=,direct
go mod download

Run the project

go run ./cmd/

Project compilation, packaging and running

go build ./cmd/
// Compilemake build
// Runmake run
// Compile and runmake
// Run the project./main

Project directory structure description

├─app
│  ├─command ---> Command line
│  ├─controller
│  │    └─ ---> BaseController,Mainly definedrequestParameter Verifiervalidator
│  ├─event
│  │  ├─entity ---> Event Entity Directory
│  │  ├─listen ---> Event listening execution script directory
│  │  └─ ---> Event registration code
│  │       
│  ├─middleware ---> Middleware code directory
│  ├─request ---> Request parameter verification code directory
│  │   └─ ---> Parameter Verifier
│  └─task ---> Timed task code directory
│     └─ ---> Register a timed task script
├─cmd ---> Project entrance directory
│  └─cli ---> 项目Command line模式入口目录
├─config
│  └─ ---> Configuration File
├─internal ---> Encapsulation containing third-party packages
├─router ---> Routing Directory
│  └─
├─storage ---> log、Resource storage directory
│  └─logs
└─test ---> Unit Test Directory

Basic functions

routing

The web framework of this skeleton is gin, so the routing definition can directly read the documentation of the Gin framework.

Defining the registration route in this skeleton requiresrouterUnder the folderIn the filefunc (*AppRouter) Add(server *)Method definition registration:

("/foo", func(ctx *) {
    (, "hello word!")
})

You can also register by defining the route yourself, just implementing it/czx-lab/skeleton/internal/server/routerThe followingInterfaceinterface. The following example:
Define aCustomRouterStructure, this structure implementsInterfaceinterface

package router
import (
    "net/http"
    "skeleton/internal/server"
    "/gin-gonic/gin"
)
type CustomRouter struct {
    server 
}
func NewCustom(srv ) *CustomRouter {
    return &CustomRouter{
        srv,
    }
}
func (*CustomRouter) Add(srv *) {
    ("/custom", func(ctx *) {
        (, "custom router")
    })
}

It should be noted that if it is a custom routing registration, the project needs to be modified.cmdUnder the folderEntry file, via((http))Register togin

middleware

Define middleware andginLike the framework, this estimate implements the middleware for panic exceptions by default, you can view itinternal/server/middlewareIn the folderdocument.

If you need to define other middleware and load registration, you can use the defined middleware to passInterfaceSetMiddleware(middlewares ...)Method registration loading,
For example, we implement the following custom global middlewaremiddleware/

type Custom struct{}
func (c *Custom) Handle()  {
    return func(ctx *) {
        ("Custom middleware exec...")
    }
}

Then use it where the route is defined(&{})Register middleware.
Defining global routing middleware can refer torouter/In-houseNewmethod.

If it is a local middleware, you can directly register it on the specific route. Refer to the usage of gin routing middleware

log

The logs in this skeleton are direct/zapEncapsulation, when used, directly passes global variablesAccess to the write logs, you can directly use all methods supported by zap.

package demo
import "skeleton/internal/variable"
func Demo() {
    ("info message")
}

The log file defaults tojsonFormat write tostorage/logs/in

Configuration

The configuration item definition is directly inconfig/The file is defined and configured to read and write is encapsulated/spf13/viperImplementation, in this skeleton, only the following methods for obtaining configuration are provided:

type ConfigInterface interface {
	Get(key string) any
	GetString(key string) string
	GetBool(key string) bool
	GetInt(key string) int
	GetInt32(key string) int32
	GetInt64(key string) int64
	GetFloat64(key string) float64
	GetDuration(key string) 
	GetStringSlice(key string) []string
}

It should be noted that the acquisition of configuration items is cached in the skeleton. The first load is to obtain it in the file, and every time I go back, it iscacheGet it nowcacheOnly supported by defaultmemory, customization is also supported in the skeletoncacheThe method only needs to be implementedThe interface is fine, for example, if you need to use itredisAs a configuration cache, it can be handled in the following ways:

type ConfigRedisCache struct {}
var _  = (*ConfigRedisCache)(nil)
func (c *ConfigRedisCache) Get(key string) any {
    return nil
}
func (c *ConfigRedisCache) Set(key string, value any) bool {
    return true
}
func (c *ConfigRedisCache) Has(key string) bool {
    return true
}
func (c *ConfigRedisCache) FuzzyDelete(key string) {
}

ThenConfigRedisCacheStructure configuration toIn, as shown below, modifyinternal/bootstrap/Methods to initialize configuration:

, err := ((), {
	BasePath: './',
    Cache: &ConfigRedisCache{}
})

The basic configuration is as follows:

# http configurationHttpServer:
  Port: ":8888"
  # The service mode, the value of gin is the same  Mode: "debug"
# socket configurationWebsocket:
  WriteReadBufferSize: 2048
  HeartbeatFailMaxTimes: 4
  PingPeriod: 20
  ReadDeadline: 100
  WriteDeadline: 35
  PingMsg: "ping"
# Database configurationDatabase:
  # You can view GORM-related configuration options  Mysql:
    SlowThreshold: 5
    LogLevel: 4
    ConnMaxLifetime: 1
    MaxIdleConn: 2
    MaxOpenConn: 2
    ConnMaxIdleTime: 12
    Reade:
      - "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True"
    Write: "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True"
  #Basic configuration of mongo database  Mongo:
    Enable: false
    Uri:
    MinPoolSize: 10
    MaxPoolSize: 20
Redis:
  Disabled: false
  Addr: "192.168.1.4:6379"
  Pwd: ""
  Db: 0
  PoolSize: 20
  MaxIdleConn: 30
  MinIdleConn: 10
  # Unit (seconds)  MaxLifeTime: 60
  # Unit (points)  MaxIdleTime: 30
# Timing tasksCrontab:
  Enable: true
# Message queue, use rocketmqMQ:
  Enable: false
  Servers:
    - "127.0.0.1:9876"
  ConsumptionSize: 1
  Retries: 1

Event mechanism

  • Define event entities

    existapp/event/entityDefine an event entity in the directory, which implementsinterface:

    package entity
    type DemoEvent struct {}
    func (d *DemoEvent) EventName() string {
        return "demo-event"
    }
    func (d *DemoEvent) GetData() any {
        return "demo param"
    }
  • Define event listening

    existapp/event/listenDefine a directoryDemoEventListenEvent listening, andDemoEventListenThe structure must be implementedinterface:

    package listen
    import (
    	"fmt"
    	event2 "skeleton/app/event/entity"
    	"skeleton/internal/event"
    )
    type DemoEventListen struct {
    }
    func (*DemoEventListen) Listen()  {
    	return &{}
    }
    func (*DemoEventListen) Process(data any) (any, error) {
    	return ("%v --> %s", data, "exec "), nil
    }
  • Finally, the event needs to be registered,app/event/In the fileInitExecute within the method:

    (&{})
  • Call event execution

    (&{})

Verifier

The gin framework itself is built-invalidatorVerification, the skeleton only provides a unified verification entry for the verification of its parameters.

The parameters are checked by the following methods and set the Chinese error prompt:

type Param struct {
    Name  int    `binding:"required" form:"name" query:"name" json:"name"`
}
appRequest, err := ("zh")
if err != nil {
    return
}
var data Param
errMap := (ctx, &data)
(errMap)

The default parameter verification has been implemented in the skeleton, and it can beapp/request/View in the file. And incontrollerIn the directoryThere is oneValidate(ctx *, param any)Method, when you want to perform parameter verification in other controllers, you only need to inherit.baseStructure, then callValidatemethod.

package controller
import "/gin-gonic/gin"
type DemoController struct {
    base
}
type DemoRequest struct {
    Id int `binding:"required" form:"id" query:"id" json:"id"`
}
func (d *DemoController) Index(ctx *) {
    var param DemoRequest
    if err := (ctx, &param); err == nil {
		(, {"data": param})
	} else {
		(, {"message": err})
	}
}

Verification specification reference/go-playground/validatorOfficial Documentation

Command line

based on/spf13/cobraPackage

  • Define commands

    existapp/commandDefine your own command in the directory, such as customizing an outputsuccess okCommand

    package command
    import (
        "fmt"
        "/spf13/cobra"
    )
    type FooCommand struct {}
    func (f *FooCommand) Command() * {
        return &{
    		Use:   "foo",
    		Short: "Introduction to Command Usage.",
    		Long: `Command introduction.`,
    		Run: func(cmd *, args []string) {
    			str, _ := ().GetString("name")
                 ("success, %s", str)
    		},
    	}
    }
    func (f *FooCommand) Flags(root *) {
    	().String("name", "", "Command parameters")
    }
  • Registration command

    Need to be incmd/cli/In-housemainRegister custom commands within the method.

  • Execute the command

    go run cmd/cli/ foo --name ok
  • View command information

    go run cmd/cli/ help
    // orgo run cmd/cli/ foo --help

Timing tasks

Timing is through packaging/robfig/cron/v3accomplish

  • Define timing task methods

    existapp/taskDefine execution methods in the directory, such as printing every minutesuccesscharacter

    package task
    import "fmt"
    type SuccessTask struct {
    }
    // Time rulesfunc (s *SuccessTask) Rule() string {
    	return "* * * * *"
    }
    func (s *SuccessTask) Execute() func() {
    	return func() {
    		("success")
    	}
    }
  • Loading timing tasks

    Need to be inapp/task/In the fileTasksIn the method, load custom tasks, refer to the task directorydocument

The Go language and Gin framework are ideal for developing high-performance web projects. Go is known for its simplicity, efficiency and concurrency, enabling developers to write reliable and high-performance code. The Gin framework is a lightweight web framework with fast routing capabilities and rich middleware support, allowing developers to quickly build flexible and scalable web applications. Using the Go language and Gin framework, developers can enjoy efficient development processes and excellent performance. Whether building small projects or large applications, the Go language and Gin framework provide developers with powerful tools and optimized performance, making the development process more efficient and enjoyable.

This is the article about accelerating development: a powerful tool for building web projects using Go and Gin frameworks. For more related web project skeletons based on the go language gin framework, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!