We talked briefly about Go-Zero earlier in go-Zero: A Microservices Framework out of the box. This time, we’ll start with a user module for implementing a Blog project, detailing the use of Go-Zero.
Note that all the materials involved in this article have been uploaded to the Github repository “Kougazhang/Go-zero-demo”. Interested students can download them on their own.
Go-zero Field project: Blog
This article takes the website background of blog as an example to introduce how to use Go-Zero to develop the user module of blog.
User module is a common module of background management system, and its functions are also very familiar. User management involves front-end operations, and user information persistence is inseparable from the database. So the user module can be described as “a sparrow is small all the five organs”. This article will explain in detail how to use Go-Zero to complete user module functions, such as user login, add user, delete user, modify user, query user, etc. (please refer to repository code for complete Api documentation)
Overall Blog architecture
At the top is the API gateway layer. Go-zero requires the API gateway layer to broker the request and forward the request to the corresponding RPC service for processing through gRPC. The business logic that forwards the specific request to the corresponding RPC service needs to be handwritten.
Next comes the RPC service layer. The user in the RPC service above is the next module to be demonstrated. Each RPC service can be deployed separately. When the service is started, the information is registered with ETCD so that ECTD can be used by the API gateway layer to discover the address of the specific service. The business logic for RPC services to handle specific requests needs to be handwritten.
Finally, the Model layer. The Model layer encapsulates the logic associated with database operations. If the operation is related to the query class, the system will check whether the corresponding cache exists in Redis first. Non-query operations directly operate MySQL. Goctl can generate normal CRDU code from SQL files. As mentioned above, goctl is currently only supported by MySQL.
Here’s how to develop a user module for a blog system using Go-Zero.
API gateway layer
Write a blog. API file
- Generate the blog.api file
Run the goctl API -o blog. API command to create the blog.
- The role of API files
For details on the syntax of the API file, see the documentation [go-zero.dev/cn/api-gram…
The API file is used to generate code for the API gateway layer.
- Syntax for API files
The syntax of the API file is very similar to the Golang language, with the type keyword used to define the structure and the service section used to define the API service.
The structure defined by type is used to declare the input parameters and return values of the request, namely request and response.
Service specifies the API services for routing, handler, Request, and response.
For details, please refer to the default generated API file below.
Info (title: // TODO: add title desc: // TODO: add description author: "Zhao. Zhang" email: "[email protected]") // Important configuration // Request is the name of the structure, you can use the type keyword to define new structure type request {// TODO: Add members here and delete this comment // Same syntax as above, but different business meaning. Response is usually used to declare a return value. type response { // TODO: Add members here and delete this comment} // Important configuration // blog-api is a service name @handler GetUser // TODO: Set handler name and delete this comment // /users/id/:userId = url The userId is a variable. // Request is the request defined by type above and is the input to the request. // Response is the response defined by type above and is the return value of the request. get /users/id/:userId(request) returns(response) @handler CreateUser // TODO: set handler name and delete this comment post /users/create(request) }Copy the code
- Write a blog. API file
Please refer to the repository on Gitee for the complete blog. API file. The code generated below is generated from the blog.api file on the repository.
API code
- Generate the relevant code
Run the goctl API go-api blog. api-dir. Command to generate API related code.
- catalogue
├ ─ ─ blog. # API API file ├ ─ ─ blog. Go # program entry documents ├ ─ ─ etc │ └ ─ ─ blog - API. Yaml # API gateway layer configuration file ├ ─ ─. Mod ├ ─ ─. Sum └ ─ ─ internal ├── ├─ ├─ ├─ ├─ ├─ ├─ ├─ ├─ └ Go │ ├─ │ ├─ getusershandler. Go │ ├─ getusershandler ├─ ├─ ├.go │ ├─ ├.go │ ├─ Go │ ├─ Go │ ├─ Go │ ├.Go │ ├─ Deleteuserlogic. Go │ ├ ─ ─ getuserslogic. Go │ ├ ─ ─ loginlogic. Go │ └ ─ ─ updateuserlogic. Go ├ ─ ─ SVC # encapsulation RPC objects, Behind will │ └ ─ ─ servicecontext. Go └ ─ ─ # types. The blog API defined structure mapping as a real golang structure └ ─ ─ types. GoCopy the code
- Call relationships between files
Since RPC services are not involved at this point, the calling relationship between modules in the API is a very simple call relationship between individual applications. Go routers are routes. Requests are sent to the corresponding handler according to the Request Method and URL. The handler will call the corresponding logic.
summary
Api layer related commands:
-
Run the goctl API -o blog. API command to create the blog.
-
Run the goctl API go-api blog. api-dir. Command to generate API related code.
-
Goctl can also generate other language API layer files, such as Java, TS, etc., after trying to find difficult to use, so do not expand.
The RPC service
Write proto files
- Generate the user.proto file
Run goctl RPC template -o user.proto to generate the user.proto file
- The user. Proto file
User. Proto is used to generate RPC service code.
The protobuf syntax is beyond the scope of Go-Zero, so I won’t go into detail here.
- Write the user.proto file
For the length of this article, please refer to the repository on Gitee for the complete User.proto file.
Generate RPC-related code
- Generate user RPC service-related code
Run the goctl RPC proto-src user-proto-dir. Generate the code for the User RPC service.
summary
Commands related to RPC services:
-
Run goctl RPC template -o user.proto to generate the user.proto file
-
Run the goctl RPC proto-src user-proto-dir. Generate the code for the User RPC service.
The API service calls the RPC service
A: Why is this section arranged after the RPC service?
Q: Because the body of the Logic section is to invoke the corresponding User RPC service, we cannot start this section until the user RPC code has been generated.
A: Steps for the API gateway layer to invoke RPC services
Q: If you are not clear about the directory structure, please refer to “API Gateway Layer – API code – Directory introduction”.
- Edit the configuration file etc/blog-api.yaml to configure RPC service information.
Name: blog-API Host: 0.0.0.0 Port: 8888 # add user RPC service Hosts: - localhost:2379 # Key is the Key value of the User. RPC service in the Etcd Key: user.rpcCopy the code
- Edit the file config/config.go
Type Config struct {rest.RestConf // add // RpcClientConf User zrpc.RpcClientConf} to parse the configuration in blog-api.yamlCopy the code
- Edit the file internal/SVC/servicecontext. Go
Type ServiceContext struct {Config config.Config // manually added // users. users is the interface exposed by user RPC service user users. users} func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: MustNewClient(c.User) creates a GRPC client User: users.newusers (zrpc.mustnewClient (c.User)),}}Copy the code
- Edit the logic file, here by internal/logic/loginlogic. Go, for example
Func (l *LoginLogic) Login(req types.requser) (* types.resplogin, error) {// Call user RPC Login method resp, err := l.svcCtx.User.Login(l.ctx, &users.ReqUser{Username: req.Username, Password: req.Password}) if err ! = nil { return nil, err } return &types.RespLogin{Token: resp.Token}, nil }Copy the code
Model layer
Writing SQL files
Write the SQL file user.sql that creates the table and execute it in the database.
CREATE TABLE `user`
(
`id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
`username` varchar(255) NOT NULL UNIQUE COMMENT 'username',
`password` varchar(255) NOT NULL COMMENT 'password',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
Copy the code
Generate model-specific code
Run the goctl model mysql DDL -c -src user.sql -dir. Command to generate CRDU code to operate the database.
Model directory at this point:
├── ├─ user.go # ├─ ├─ vars. Go #Copy the code
Note the code generated by model
-
The Model piece of code uses a concatenated SQL statement, which may have the risk of SQL injection.
-
The code to generate THE CRUD is fairly rudimentary, requiring us to manually edit the userModel.go file and concatenate the SQL required by the business ourselves. See the FindByName method in usermdel.go.
RPC calls code in the Model layer
RPC directory structure
RPC services we only need to focus on the annotated files or directories below.
├─ etc │ ├─ ├─ ├─ Internal │ ├─ config │ ├.go # config.go │ ├─ logic # where to fill in the logics ├── ├.go │ ├─ ├.go │ ├─ ├.go │ ├─ ├.go │ ├── ├.go │ ├.go │ ├── ├.go │ ├.go │ ├── ├─ │ ├─ ├─ ├─ user.pty.go │ ├─ ├─ user.pty.go │ ├─ ├─ user.pty.go ├── heavy exercises ── heavy exercises ── heavy exercisesCopy the code
The steps that RPC calls the Model layer code
- Edit the etc/user.yaml file
Name: user.rpc ListenOn: 127.0.0.1:8080 Etcd: Hosts: -127.0.0.1:2379 Key: user.rpc Root :1234@tcp(localhost:3306)/gozero # Table: user # redis as swap Cache: -host: localhost:6379Copy the code
- Edit internal/config/config. Go file
Type Config struct {// zrpc.RpcServerConf indicates that the configuration of the RPC server is inherited Cache.cacheconf // Manual code}Copy the code
- Edit internal/SVC/servicecontext. Go, such as the model relies on encapsulated.
Type ServiceContext struct {Config config.config Model model.UserModel} func NewServiceContext(c) config.Config) *ServiceContext { return &ServiceContext{ Config: c, Model: Model.newusermodel (sqlx.newmysql (c.datasource), c.ache), // manual code}}Copy the code
- Edit the corresponding logic file, here by internal/logic/loginlogic. Go, for example:
func (l *LoginLogic) Login(in *user.ReqUser) (*user.RespLogin, error) { // todo: add your logic here and delete this line one, err := l.svcCtx.Model.FindByName(in.Username) if err ! = nil { return nil, errors.Wrapf(err, "FindUser %s", in.Username) } if one.Password ! = in.Password { return nil, fmt.Errorf("user or password is invalid") } token := GenTokenByHmac(one.Username, secretKey) return &user.RespLogin{Token: token}, nil }Copy the code
Microservices demo run
We run the entire microservice in a stand-alone environment, and need to start the following services:
-
Redis
-
Mysql
-
Etcd
-
go run blog.go -f etc/blog-api.yaml
-
go run user.go -f etc/user.yaml
In the above services, the RPC service is started first and then the gateway layer.
In the repository I packaged start.sh and stop.sh scripts to run and stop microservices in a stand-alone environment, respectively.
Ok, with the six steps above, the common functions of the blog user module are complete.
In addition to the goctl commands you need to be familiar with, there are also rules to follow in the naming of go-Zero files. Configuration file is in the etc directory yaml file, the yaml file corresponding structure in the interval/config/config. Go. Dependency management generally in the interval/SVC/xxcontext. Go for encapsulation. Where we need to populate the business logic are the files in the interval/ Logic directory.
Recommended reading
Practical notes: Configure the mental path of the monitoring service for NSQ
Go-zero: Out-of-the-box microservices framework