Based on the gin framework, we have developed a user-friendly, simple, and fast development framework for API programming using go1.18+
MIT License
โโโโโโโ โโโโโโโ โโโ โโโโโโโโโโโโโโโ โโโโโโ โโโโ โโโโโโโโโโโโโโโ โโโ โโโโโโโ โโโโโโโ โโโ โโโ
โโโโโโโโ โโโโโโโโ โโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โโโโ
โโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ โโ โโโโโโ โโโโโโโโโโโโโโโโโโ
โโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโ โโโโโโ โโโ โโโ โโโโโโ โโโโโโ โโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ โโโ
โโโโโโโ โโโโโโ โโโโโ โโโ โโโ โโโโโโ โโโโโโ โโโโโโโโโโโ โโโโโโโโ โโโโโโโ โโโ โโโโโโ โโโ
โโโ Dockerfile
โโโ LICENSE
โโโ Makefile # makefile
โโโ README.md
โโโ app # Directory holding modules
โย ย โโโ amqp # Message queue
โย ย โโโ controller # Controller
โย ย โโโ service # Service layer
โโโ bootstrap # Initialization program loading service
โโโ cmd # Command commands
โย ย โโโ admin.go # Generate admin backend account
โย ย โโโ controller.go # Generate controller
โย ย โโโ migrate.go # Generate migrate database migration
โย ย โโโ model.go # Generate model data model
โย ย โโโ service.go # Generate service layer
โโโ config
โย ย โโโ config.go # Map yaml configuration file to structure
โย ย โโโ white_list.go # Whitelist
โย ย โโโ yaml # yaml configuration file directory
โโโ global # Global variables and global methods
โโโ go.mod
โโโ go.sum
โโโ main.go
โโโ middleware # Middleware
โโโ migrations # Migration files
โโโ models # Models
โโโ pkg # Custom common services, JWT, helper functions, etc.
โย ย โโโ auth # jwt
โย ย โโโ lib # Log service, database service, redis service, etc.
โย ย โโโ paginator # Paginator
โย ย โโโ response # Http request returns status and formatting
โย ย โโโ util # Helper function
โย ย โโโ validator # Parameter validator
โโโ router # Route configuration
โโโ runtime # Files produced at runtime, such as logs, etc.
โโโ types # All custom structures
Note that before starting, you need to enable the MySQL and Redis services, and configure the MySQL and Redis settings in the config.dev.yaml file (which defaults to the dev environment).
go mod tidy
go run main.go
# View parameters of main.go.
go run main.go --help
Request๏ผhttp://127.0.0.1:9527/ping
{
"status": 200,
"errcode": 0,
"requestid": "9ac7f4f2-1271-4f87-8df7-599a478af9cb",
"message": "Pong!",
"data": ""
}
go install github.com/cosmtrek/air@latest
Type in the command line: "air" to execute hot update. The code edits will update automatically.
This step is intended for accessing permission for backend interfaces.
go run main.go migrate -s=all
# Please check the specific parameters in the "help" section.
go run main.go migrate -help
/routes
interface.This interface will create a super administrator role based on casbin.
# Viewing the make command line
make help
# Basic packaging to generate executable file (based on the current system)
make build
# Packaging for Windows
make windows
# Packaging for Darwin
make darwin
# Packaging for Linux
make linux
View packaged files in the releases section.
import "github.com/MQEnergy/gin-framework/pkg/paginator"
var memberList = make([]models.GinAdmin, 0)
paginator, err := paginator.NewBuilder().
WithDB(global.DB).
WithModel(models.GinAdmin{}).
WithField([]string{"password", "salt", "updated_at", "_omit"}).
WithCondition("id = ?", 1).
Pagination(memberList, 1, 10)
return paginator, err
Define receiving struct.
type BaseUser models.GinUser
type GinUserInfo models.GinUserInfo
// UserList get user lists.
type UserList struct {
BaseUser
GinUserInfo `gorm:"foreignKey:user_id" json:"user_info"`
}
Usage 1:
var userList = make([]user.UserList, 0)
pagination, err := paginator.NewBuilder().
WithDB(global.DB).
WithModel(models.GinUser{}).
WithFields(models.GinUser{}, models.GinUserTbName, []string{"password", "salt", "_omit"}).
WithFields(models.GinUserInfo{}, models.GinUserInfoTbName, []string{"id", "user_id", "role_ids"}).
WithJoins("left", []paginator.OnJoins{{
LeftTableField: paginator.JoinTableField{Table: models.GinUserTbName, Field: "id"},
RightTableField: paginator.JoinTableField{Table: models.GinUserInfoTbName, Field: "user_id"},
}}).
Pagination(&userList, requestParams.Page, global.Cfg.Server.DefaultPageSize)
return pagination, err
Usage two:
var userList = make([]user.UserList, 0)
multiFields := []paginator.SelectTableField{
{Model: models.GinUser{}, Table: models.GinUserTbName, Field: []string{"password", "salt", "_omit"}},
{Model: models.GinUserInfo{}, Table: models.GinUserInfoTbName, Field: []string{"user_id", "role_ids"}},
}
pagination, err := paginator.NewBuilder().
WithDB(global.DB).
WithModel(models.GinUser{}).
WithMultiFields(multiFields).
WithJoins("left", []paginator.OnJoins{{
LeftTableField: paginator.JoinTableField{Table: models.GinUserTbName, Field: "id"},
RightTableField: paginator.JoinTableField{Table: models.GinUserInfoTbName, Field: "user_id"},
}}).
Pagination(&userList, requestParams.Page, global.Cfg.Server.DefaultPageSize)
return pagination, err
Note:
There is a slight difference between the struct defined by the preload method and the struct defined by the joins query. The name of the struct defined by the preload method must be consistent with the name of the struct for the current table of the model. Also, the name of the struct for the associated table cannot be the same as the name of the struct for the model. For example, the definition of "UserInfo" is as follows:
Definition of receiving a struct.
type BaseUser models.GinUser
type GinUserInfo models.GinUserInfo
type GinUser struct {
BaseUser
UserInfo GinUserInfo `gorm:"foreignKey:user_id" json:"user_info"`
}
Usage instructions as follows:
var userList = make([]user.GinUser, 0)
pagination, err := paginator.NewBuilder().
WithDB(global.DB).
WithModel(models.GinUser{}).
WithPreload("UserInfo").
Pagination(&userList, requestParams.Page, global.Cfg.Server.DefaultPageSize)
return pagination, err
This method does not recommend using WithFields or WithField to query fields. Instead, it is recommended to directly define the query fields specified by the receiving struct.
Visit address: http://127.0.0.1:9527/user/index?page=1 The returned data format is as follows:
{
"status": 200,
"errcode": 0,
"requestid": "9ac7f4f2-1271-4f87-8df7-599a478af9cb",
"message": "Request Success",
"data": {
"list": [],
"current_page": 1,
"total": 2,
"last_page": 1,
"per_page": 10
}
}
entities/user/gin_user.go
app/controller/backend/user.go
app/service/backend/user.go
router/routes/common.go
Must be used in a chained operation.
DB Connection MethodWithDB(db *gorm.DB) *PageBuilder
Must be used in a chained operation.
Model connection method.WithModel(model interface{}) *PageBuilder
Pass the main table model as a parameter for the query, for example: models.GinAdmin. You cannot pass a structure address as a parameter, like &models.GinAdmin.
Not necessary in chained operations.
Single table query or filtering field method.WithField(fields []string) *PageBuilder
The last parameter of "fields" defaults to "_select" (can be omitted), but if "_omit" is passed, it filters out the fields transmitted earlier.
Note:
Usage as follows:
// Indicates filtering of front fields.
WithField([]string{"created_at", "updated_at", "_omit"})
// Indicates the fields to be queried.
WithField([]string{"created_at", "updated_at", "_select"})
WithField([]string{"created_at", "updated_at"})
Not necessary in chain operations.
Multi-table queries or filtering field methods (when using the preload mode, there may be issues with associated table queries, and it is not recommended to use the preload association query method).WithFields(model interface{}, table string, fields []string) *PageBuilder
The last argument for fields is default to "_select" (can be omitted), if "_omit" is passed, it will filter the fields transmitted earlier.
Usage as follows๏ผ
// Indicates filtering the preceding field.
WithFields(models.GinUser{}, models.GinUserTbName, []string{"password", "salt", "_omit"})
// "Indicates the field before the search."
WithFields(models.GinUserInfo{}, models.GinUserInfoTbName, []string{"id", "user_id", "role_ids", "_select"})
WithFields(models.GinUserInfo{}, models.GinUserInfoTbName, []string{"id", "user_id", "role_ids"})
Not necessary in chain operations.
Multiple table and field queries (can replace WithFields method)WithMultiFields(fields []SelectTableField) *PageBuilder
Usage as follows๏ผ
WithMultiFields([]paginator.SelectTableField{
{Model: models.GinUser{}, Table: models.GinUserTbName, Field: []string{"password", "salt", "_omit"}},
{Model: models.GinUserInfo{}, Table: models.GinUserInfoTbName, Field: []string{"id", "user_id", "role_ids"}},
})
Not necessary in chain operations.
Multiple table association query with proactive preloading (conditions not currently supported). WithPreloads(querys []string) *PageBuilder
Usage as follows๏ผ
WithPreloads([]string{"UserInfo", "UserRecord"})
Not necessary in chain operations.
Active preloading of associated queries (can pass conditions, conditions refer to Gorm).WithPreload(query string, args ...interface{}) *PageBuilder
Usage as follows๏ผ
WithPreload("UserInfo", "user_id = ?", "1")
Not necessary in chain operations.
Method for Data Query Conditions.WithCondition(query interface{}, args ...interface{}) *PageBuilder
Pass in query conditions that support the querying format used in the 'where' conditions in GORM (non-struct format). The 'query' and 'args' parameters should follow the same method of passing in 'where' conditions as in GORM.
Not necessary in chain operations.
Method for Data Query Conditions.WithJoins(joinType string, joinFields []OnJoins) *PageBuilder
joinType: Type of join. It can be left, right or inner. joinFields structure: LeftTableField, such as the main table's ID, and RightTableField, such as the related table's main table ID.
Usage as follows๏ผ
WithJoins("left", []paginator.OnJoins{{
LeftTableField: paginator.JoinTableField{Table: models.GinUserTbName, Field: "id"},
RightTableField: paginator.JoinTableField{Table: models.GinUserInfoTbName, Field: "user_id"},
}})
The last link must be in the chain operation.
Page return method.Pagination(dst interface{}, currentPage, pageSize int) (Page, error)
"dst" is a "struct" structure that receives incoming data. Note: It must be passed in application mode, such as "&userList". "model" and "currentPage" represent the current page number, and "pageSize" represents the number of queries per page.
Not necessary in chain operations.
Connecting with native query method. NewDB() *gorm.DB
After using this method, all methods inside the pagination for chained operations are unavailable. You can continue using the native methods of GORM afterwards.
Usage as follows๏ผ
NewDB().Where("id = ?", id).First(&userList)
paginator.CurrentPage
paginator.List
paginator.Total
paginator.LastPage
paginator.PerPage
UploadFile(path string, r *gin.Context) (*FileHeader, error)
By default, the files are stored in the "upload" directory of the project. If it does not exist, it will be created automatically. The path will be "upload" directory module directory, such as "user". The directory structure will be "upload/user/{yyyy-mm-dd}/...".
Usage as follows๏ผ
app/controller/backend/attachment.go
pkg/util/upload.go
router/routes/common.go
Configure the amqp parameters in the yaml configuration file.
Test case
go run command/test/consumer.go
Test case
go run command/test/producer.go
Running "go run main.go --help" will display the following command set.
COMMANDS:
migrate Create a migration command
account Create a new admin account
model Create a new model class
controller Create a new controller class
service Create a new service class
help, h Shows a list of commands or help for one command
# Install migrate cli tool.
curl -L https://github.com/golang-migrate/migrate/releases/download/$version/migrate.$platform-amd64.tar.gz | tar xvz
# MacOS Installation
brew install golang-migrate
# Install Window with scoop https://scoop.sh/
scoop install migrate
# "Creating migration file syntax, for example:"
migrate create -ext sql -dir migrations -seq create_users_table
# The first way to execute migration.
# Carrying out migration operation:
migrate -database 'mysql://root:123456@tcp(127.0.0.1:3306)/gin_framework' -path ./migrations up
# Performing rollback operation:
migrate -database 'mysql://root:123456@tcp(127.0.0.1:3306)/gin_framework' -path ./migrations down
# The second way to perform migration.
# View help command.
go run main.go migrate --help
# The format is as follows๏ผ
go run main.go migrate -s {step} -e {env}
# env: Keep consistent with the config.*.yaml file among dev, test, and prod. The default is dev.
# step: The number of migration files to be executed (or rolled back), for example, 1, 2, 3... If you want to execute all, use "all".
# Perform all migration operations:
go run main.go migrate -s all
# Perform partial migration operations๏ผ
# eg.๏ผgo run main.go migrate -s 1
# Performing rollback operation๏ผ
# eg.๏ผgo run main.go migrate -s -1
# Execute the command to generate all models.
go run main.go model -tb=all {env}
# Please refer to the help for specific parameters.
go run main.go model -help
go run main.go controller -c={controller name} -m={module name}
# eg.๏ผgo run main.go controller -c=admin -m=backend
# Please refer to the help for specific parameters.
go run main.go controller -help
go run main.go service -s={service name} -m={module name}
# The module name is the module named "name" located in the app/controller directory.
# eg.๏ผgo run main.go service -s=admin -m=backend
# Please refer to the help for specific parameters.
go run main.go service -help
go run main.go account -c={account name} -p={password}
# Check the specific parameters in the help documentation.
go run main.go account -help