Why use Go-Zero

There can be a third option

  • Golang’s community is small, and there are only a handful of microservices frameworks: there are few alternatives to Go-Micro and Go-Kit. Go-zero offers a third possibility.
  • Go-micro is not friendly to WebAPI support and requires running micro instructions that are difficult to customize

Startups need a framework to support business growth

What kind of framework do we need? We need a framework to support business growth! In the early stages of product operation, such as requirements verification, we don’t need to adopt a microservices architecture because of the high operational costs. A single app will do. As the business grows and microservices become necessary, we want to be flexible and upgrade without too much code work. That’s where go-Zero is valuable

What is the go – zero

https://github.com/tal-tech/go-zero Go-Zero is a web and RPC framework that integrates various engineering practices. It has the following main features:

  • Powerful tool support with as little coding as possible
  • Minimal interface
  • Fully net/ HTTP compatible
  • Support middleware for easy expansion
  • A high performance
  • Fault – oriented programming, resilient design
  • Built-in service discovery and load balancing
  • Built – in current limit, fusing, load reduction, and automatic trigger, automatic recovery
  • Automatic verification of API parameters
  • Timeout cascade control
  • Automatic cache control
  • Link tracking, statistical alarm, etc
  • High concurrent support, stable to ensure the daily flow peak during the epidemic xiao Blackboard

How to use

Before reading this document, upgrade Golang to GO14 or later and enable go Module support. Go14 is only for Gorm support

export GOPROXY=https://goproxy.io,direct
export GO111MODULE=on 
Copy the code

Install goctl

Goctl is a code generator for Go-Zero. After all, most of the time writing code is manual work. Download the source code first!

git clone https://github.com/tal-tech/go-zero
cd go-zero/tools/goctl
go build goctl.go
Copy the code

Copy goctl.exe to $gopath/bin

Goctl command description

Browse the document itself. https://github.com/tal-tech/go-zero/blob/master/tools/goctl/goctl.md

The instructions used in this article are as follows

goctl api      go       -api             open.api            -dir                     .
Copy the code
The code is described belowGoctl API go - the open API. API - dir. | | | | | | | generated API go language API specified template file template file name Specify the generated code repository paths The current folderCopy the code

Create a project

Generate the go.mod file

Create the project with the following instructions

mkdir hello
cd hello
go mod init  hello
Copy the code

Define the hello. API

The API is designed as follows

describe format methods parameter return
User registration /open/register post Mobile: mobile phone number,passwd: password,code: image verification code Id: indicates the user ID. Token: indicates the user token
The user login /open/authorization post Mobile: mobile phone number,passwd: password,code: image verification code Id: indicates the user ID. Token: indicates the user token
Image verification code request /open/verify get Ticket: indicates the ID of the image verification code Data: Base64 format image

According to the above description, the template file for writing the API is as follows


type (
	UserOptReq struct {
		mobile string `json:"mobile"`
		passwd string `json:"passwd"`
		code   string `json:"code"`
	}

	UserOptResp struct {
		id    uint   `json:"id"`
		token string `json:"token"`
	}
	// Image verification code support
	VerifyReq struct {
		ticket string `json:"ticket"`
	}
	// Image verification code support
	VerifyResp struct {
		data string `json:"data"`}) service open-api {@doc(summary: public API function desc: > Register user registration, authorization user login, verify image verification code interface) @server(handler: registerHandler Folder: open ) post /open/register(UserOptReq) returns(UserOptResp) @server( handler: authorizationHandler folder: open ) post /open/authorization(UserOptReq) returns(UserOptResp) @server( handler: verifyHandler folder: open ) post /open/verify(VerifyReq) returns(VerifyResp) }Copy the code

Pay attention to

  • There can only be one service in a file
  • The tool will eventually generate various structures using the model in Type as the template, so the parameters should be consistent with the structure
  • If we need to manage business by folder, we can define the Folder property

The generated code

Use the following instructions to generate the code

goctl api  go   -api   open.api   -dir  .
Copy the code

The final code structure is as follows

#tree /F /A
|   go.mod
|   go.sum
|   hello.api
|   open.go
|
+---etc
|       open-api.yaml
|
\---internal
    +---config
    |       config.go
    |
    +---handler
    |   |   routes.go
    |   |
    |   \---open
    |           authorizationhandler.go
    |           registerhandler.go
    |           verifyhandler.go
    |
    +---logic
    |   \---open
    |           authorizationlogic.go
    |           registerlogic.go
    |           verifylogic.go
    |
    +---svc
    |       servicecontext.go
    |
    \---types
            types.go                                          
Copy the code

Run the

go run open.go
Copy the code

Test the

The curl http://127.0.0.1:8888/open/register - POST - H X"Content-Type: application/json" -d {\"mobile\":\"15367151352\",\"passwd\":\"testpwd\",\"code\":\"asdf\"}
{"id": 0."token":""}
Copy the code

Integrate star product Gorm V2

Gorm V2 integration has been upgraded to test it

The configuration file

The configuration file is in etc/open-api.yaml

Name: open-API Host: 0.0.0.0 Port: 8888 DataSourceName: root:1D007648b4f8@(127.0.0.1:3306)/gozero? charset=utf8Copy the code

In the/etc/open – API. Yaml DataSourceName add parameters, in the internal/config/config. Add DataSourceName go

type Config struct {
	rest.RestConf
	DataSourceName string
}

Copy the code

As for the configuration file, the system has some built-in keywords such as Cache, so there is not much information. You can basically configure it any way you want, and then define variables with the same name in your Conf.

Enable Gorm support

Modify the SVC/Servicecontext. go code as follows

package svc

import (
	"hello/internal/config"
	"hello/internal/models"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

type ServiceContext struct {
	Config  config.Config
	DbEngin *gorm.DB
}

func NewServiceContext(c config.Config) *ServiceContext {
    // Enable Gorm support
	db, err := gorm.Open(mysql.Open(c.DataSourceName), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   "tech_".// Table name prefix, 'User' table name should be 't_users'
			SingularTable: true.// Use singular table names. In this case, the table name of 'User' should be 't_user'}})// If there is an error, GameOver is used
	iferr ! =nil {
		panic(err)
    }
    // Automatically update the table structure, do not create a table
	db.AutoMigrate(&models.User{})

	return &ServiceContext{Config: c, DbEngin: db}
}

Copy the code

New Model file

Create a new models\models.go file

/ / models \ models go file
package models

import (
	"errors"
	"hello/internal/utils"

	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Mobile string `gorm:"index:mobile; type:varchar(13)"`
	Passwd string `gorm:"type:varchar(64)"`
}
// Verify that the password is valid before creation
func (u *User) BeforeCreate(db *gorm.DB) error {
	if len(u.Passwd) < 6 {
		return errors.New("The password is too simple.")}// Encrypt the password for storage
	u.Passwd = utils.Password(u.Passwd)
	return nil
}
Copy the code

Utils.password is the toolkit we wrote, and the code is as follows

package utils

import (
	"fmt"

	"golang.org/x/crypto/bcrypt"
)

// Password encryption
func Password(plainpwd string) string {
    // Google encrypted package
	hash, err := bcrypt.GenerateFromPassword([]byte(plainpwd), bcrypt.DefaultCost) // Encrypt
	iferr ! =nil {
		fmt.Println(err)
	}
	encodePWD := string(hash) // The password saved in the database, although each generation is different, only need to save a copy
	return encodePWD
}
// Verify the password
func CheckPassword(plainpwd, cryptedpwd string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(cryptedpwd), []byte(plainpwd)) // Verify (compare)
	return err == nil
}

Copy the code

Implementing business logic

Change the code in logic\open\registerlogic.go as follows

package logic

import (
	"context"

	"hello/internal/models"
	"hello/internal/svc"
	"hello/internal/types"

	"github.com/tal-tech/go-zero/core/logx"
)

type RegisterLogic struct {
	ctx context.Context
	logx.Logger
	svcCtx *svc.ServiceContext
}

func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) RegisterLogic {
	return RegisterLogic{
		ctx:    ctx,
		Logger: logx.WithContext(ctx),
		svcCtx: svcCtx,
	}
}

func (l *RegisterLogic) Register(req types.UserOptReq) (*types.UserOptResp, error) {
	user := models.User{
		Mobile: req.Mobile,
		Passwd: req.Passwd,
	}
	result := l.svcCtx.DbEngin.Create(&user)
	return &types.UserOptResp{
		Id: user.ID,
	}, result.Error
}

Copy the code
  • Add svcCtx *svc.ServiceContext to RegisterLogic because DbEngin is needed
  • NewRegisterLogic configuration svcCtx
  • Implement the logic in the Register functionresult := l.svcCtx.DbEngin.Create(&user)

Test the

> curl http://127.0.0.1:8888/open/register - POST - H X"Content-Type: application/json" -d {\"mobile\":\"15367151352\",\"passwd\":\"testpwd\"}
{"id": 3."token":""}
Copy the code

Look forward to updated feature points

go-zero

The interface definition expects to support multiple Content-Types

UserOptReq struct {
	mobile string `json:"mobile" form:"mobile" xml:"mobile"`
	passwd string `json:"passwd" form:"passwd" xml:"passwd"`
	code   string `json:"code" form:"code" xml:"code"`
}
Copy the code

One possible solution is to modify the Parse github.com/tal-tech/go-zero/rest/httpx/requests.go into this model

func Parse(r *http.Request, v interface{}) error {
	iferr := ParsePath(r, v); err ! =nil {
		return err
	}
	if strings.Contains(r.Header.Get(ContentType), multipartFormData) {
		return ParseForm(r, v)
	} else if strings.Contains(r.Header.Get(ContentType), urlencodeformdata) {
		return ParseForm(r, v)
	} else if strings.Contains(r.Header.Get(ContentType), applicationjson) {
		return ParseJsonBody(r, v)
	} else {
		return errors.New("Unsupported request type")}}Copy the code

Support multiple methods in a file

For example, two methods are generated in the verifyHandler.go file

	@server(
		handler: verifyHandler
		folder: open
	)
	post /open/verify(VerifyReq) returns(VerifyResp)
    post /open/authorization(UserOptReq) returns(UserOptResp)
Copy the code

gorm v2

Suggest the defaultSingularTableProperties fortrue

NamingStrategy: schema.NamingStrategy{
			TablePrefix:   "tech_".// Table name prefix, 'User' table name should be 't_users'
			SingularTable: true.// Use singular table names. In this case, the table name of 'User' should be 't_user'
		},
Copy the code

You are advised to enhance the cache function

It is recommended to support cache such as Redis, memcache, and memory cache

Code acquisition for this article

Follow the public account Betaidea type goZero or gormv2 to obtain

Spread the word

Send benefits to uniAPP users Gospel is coming! After hundreds of thousands of users, our customer service system is finally available. Are you still worried about mall access to customer service? Just one line of code to access!! Just one line of code!!!!

/*kefu.vue*/
<template>
	<view>
		<IdeaKefu :siteid="siteId"  ></IdeaKefu>
	</view>
</template>

<script>
	import IdeaKefu from "@/components/idea-kefu/idea-kefu.vue"
    export default {
		components:{
			IdeaKefu
		},
		data() {
			return {
				siteId:2}}}Copy the code

The effect is great

Address kefu.techidea8.com/html/wiki/ development document