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.
All the materials covered in this article have been uploaded to the Github repository kougazhang/ Go-Zero-demo for those who are interested.
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 files).
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. Goctl supports MySQL, PostgreSQL, and MongoDB.
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
See the documentation go-zero.dev/cn/api-gram for details on the syntax of the API file… This article takes a personal look at the functions and basic syntax of API files.
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:
- Execute the command
goctl api -o blog.api
To create the blog.api file. - Execute the command
goctl api go -api blog.api -dir .
Generate API related code. - Goctl can also be used to generate API layer files of other languages, such as Java, TS, etc., which are not expanded here.
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:
- Using the command
goctl rpc template -o user.proto
To generate the user.proto file - Using the command
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.
User:
Etcd:
# Hosts is the value of the user. RPC service in etCD
Hosts:
- localhost:2379
# Key is the Key value of the user. RPC service in etCD
Key: user.rpc
Copy the code
- Edit the file config/config.go
type Config struct {
rest.RestConf
// Add it manually
// RpcClientConf is the RPC client configuration used to resolve the configuration in blog-api.yaml
User zrpc.RpcClientConf
}
Copy the code
- Edit the file internal/SVC/servicecontext. Go
type ServiceContext struct {
Config config.Config
// Add it manually
Users is the interface exposed by the user RPC service
User users.Users
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
// Add it manually
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) {
// Invoke the login method of user RPC
resp, err := l.svcCtx.User.Login(l.ctx, &users.ReqUser{Username: req.Username, Password: req.Password})
iferr ! =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. 01.: 8080
Etcd:
Hosts:
- 127.0. 01.: 2379
Key: user.rpc
The following configuration is manually added
# mysql configuration
DataSource: root:1234@tcp(localhost:3306)/gozero
# the corresponding table
Table: user
# redis is stored as an exchange
Cache:
- Host: localhost:6379
Copy the code
- Edit internal/config/config. Go file
type Config struct {
// zrpc.RpcServerConf indicates that the configuration of the RPC server is inherited
zrpc.RpcServerConf
DataSource string // Manual code
Cache 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 // Manual code
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
Model: model.NewUserModel(sqlx.NewMysql(c.DataSource), c.Cache), // 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)
iferr ! =nil {
return nil, errors.Wrapf(err, "FindUser %s", in.Username)
}
ifone.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 run demo
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 internal/config/config. Go. Tend to rely on management in internal/SVC/servicecontext. Go for encapsulation. Where we need to populate the business logic are the files in the internal/ Logic directory.
Thank you
Thank you for patting cloud again!
The project address
Github.com/zeromicro/g…
Welcome to Go-Zero and star support us!