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 commandgoctl api -o blog.apiTo create the blog.api file.
  • Execute the commandgoctl 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 commandgoctl rpc template -o user.protoTo generate the user.proto file
  • Using the commandgoctl 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!