Example 6, Build a simple golang e-commerce microservices framework step by step using tool
zhuyasen
Posted on November 7, 2023
By taking a simple e-commerce microservice cluster as an example, the product details page contains product information, inventory information, and product evaluation information. These data are scattered in different microservices. The grpc gateway service assembles the required data and returns it to the product details page, as shown in the following figure. Click to see the full microservice cluster code micro-cluster-demo.
Dependencies
- Prepare a proto files:
- The comment.proto file defines grpc methods to obtain comment data based on the product ID and is used to generate the comment grpc service code.
- The inventory.proto file defines grpc methods to obtain inventory data based on the product ID and is used to generate the inventory grpc service code.
- The product.proto file defines grpc methods to obtain product details based on the product ID and is used to generate the product grpc service code.
- The shop_gw.proto file defines grpc methods to assemble the data required by the product details page based on the product ID and is used to generate the shop grpc gateway service code.
- Install the tool sponge.
After installing the "sponge" tool, execute the following command to open the UI interface:
sponge run
Quickly generate and start comment, inventory, and product microservices
Generate comment, inventory, and product microservice code
Enter the Sponge UI interface, click the left menu bar 【Protobuf】-->【create microservice project】, fill in the respective parameters of the comment, inventory, and product, and generate the comment, inventory, and product service code respectively.
The microservice framework uses grpc and also contains common service governance function codes, build deployment scripts, etc.
Quickly create a comment service as shown below:
Quickly create an inventory service as shown below:
Quickly create a product service as shown below:
Open three terminals, one for each of the comment, inventory, and product services.
Start the comment service
Switch to the comment directory and perform the following steps:
(1) Generate api interface code (internal/service directory), grpc client test code (internal/service directory), api interface error code (internal/ecode directory), generate pb.go code (api/comment/v1 directory)
make proto
(2) Open internal/service/comment.go
, which is the generated template code. There is a line of panic code prompting you to fill in the business logic code. Fill in the business logic here, for example, fill in the return value:
return &commentV1.ListByProductIDReply{
Total: 11,
ProductID: 1,
CommentDetails: []*commentV1.CommentDetail{
{
Id: 1,
Username: "Mr Zhang",
Content: "good",
},
{
Id: 2,
Username: "Mr Li",
Content: "good",
},
{
Id: 3,
Username: "Mr Wang",
Content: "not good",
},
},
}, nil
(3) Open the configs/comment.yml
configuration file, find grpc, and modify the port and httpPort values under it:
grpc:
port: 18203 # listen port
httpPort: 18213 # profile and metrics ports
(4) Compile and start the comment service
make run
Start the inventory service
Switch to the inventory directory and perform the same steps as for the comment:
(1) Generate api interface code (internal/service directory), grpc client test code (internal/service directory), api interface error code (internal/ecode directory), generate pb.go code (api/inventory/v1 directory)
make proto
(2) Open internal/service/inventory.go
, which is the generated template code. There is a line of panic code prompting you to fill in the business logic code. Fill in the business logic here, for example, fill in the return value:
return &inventoryV1.GetByIDReply{
InventoryDetail: &inventoryV1.InventoryDetail{
Id: 1,
Num: 999,
SoldNum: 111,
},
}, nil
(3) Open the configs/inventory.yml
configuration file, find grpc, and modify the port and httpPort values under it:
grpc:
port: 28203 # listen port
httpPort: 28213 # profile and metrics ports
(4) Compile and start the inventory service
make run
Start the product service
Switch to the product directory and perform the same steps as for the comment:
(1) Generate api interface code (internal/service directory), grpc client test code (internal/service directory), api interface error code (internal/ecode directory), generate pb.go code (api/product/v1 directory)
make proto
(2) Open internal/service/product.go
, which is the generated template code. There is a line of panic code prompting you to fill in the business logic code. Fill in the business logic here, for example, fill in the return value:
return &productV1.GetByIDReply{
ProductDetail: &productV1.ProductDetail{
Id: 1,
Name: "Data cable",
Price: 10,
Description: "Android type c data cable",
},
InventoryID: 1,
}, nil
(3) Open the configs/product.yml
configuration file, find grpc, and modify the port and httpPort values under it:
grpc:
port: 38203 # listen port
httpPort: 38213 # profile and metrics ports
(4) Compile and start the product service
make run
After the comment, inventory, and product microservices have started successfully, you can now generate and start the gateway service.
Quickly generate and start the grpc gateway service
Enter the Sponge UI interface, click the left menu bar 【Protobuf】-->【create grpc gateway project】, fill in some parameters to generate the grpc gateway project code.
The web framework uses gin, which also contains swagger documentation, common service governance function codes, build deployment scripts, etc.
In order to connect to the comment, inventory, and product grpc services, you need to generate additional connection grpc service codes. Click the left menu bar 【Public】--> 【generate grpc connection code】, fill in the parameters to generate the code, and then move the generated connection grpc service code to the grpc gateway project code directory.
In order to call the methods of the grpc services in the grpc gateway service, you need to copy the proto files of the comment, inventory, and product grpc services to the api/shop_gw/v1 directory of the grpc gateway service.
Switch to the shop_gw directory and perform the following steps:
(1) Copy proto file from grpc services comment,inventory,product.
make copy-proto SERVER=../comment,../inventory,../product
(2) Open the configs/shop_gw.yml
configuration file, find grpcClient, and add the addresses of the comment, inventory, and product grpc services:
grpcClient:
- name: "comment"
host: "127.0.0.1"
port: 18282
registryDiscoveryType: ""
- name: "inventory"
host: "127.0.0.1"
port: 28282
registryDiscoveryType: ""
- name: "product"
host: "127.0.0.1"
port: 38282
registryDiscoveryType: ""
(3) Generate pb.go code, generate registered routing code, generate template code, and generate swagger documentation
make proto
(4) Open internal/service/shop_gw.go
, which is the generated API interface code. Fill in the business logic code here, fill in the following simple business logic code:
package service
import (
"context"
commentV1 "shop_gw/api/comment/v1"
inventoryV1 "shop_gw/api/inventory/v1"
productV1 "shop_gw/api/product/v1"
shop_gwV1 "shop_gw/api/shop_gw/v1"
"shop_gw/internal/ecode"
"shop_gw/internal/rpcclient"
"github.com/zhufuyi/sponge/pkg/grpc/interceptor"
"github.com/zhufuyi/sponge/pkg/logger"
)
var _ shop_gwV1.ShopGwLogicer = (*shopGwClient)(nil)
type shopGwClient struct {
commentCli commentV1.CommentClient
inventoryCli inventoryV1.InventoryClient
productCli productV1.ProductClient
}
// NewShopGwClient create a client
func NewShopGwClient() shop_gwV1.ShopGwLogicer {
return &shopGwClient{
commentCli: commentV1.NewCommentClient(rpcclient.GetCommentRPCConn()),
inventoryCli: inventoryV1.NewInventoryClient(rpcclient.GetInventoryRPCConn()),
productCli: productV1.NewProductClient(rpcclient.GetProductRPCConn()),
}
}
// GetDetailsByProductID get page detail by product id
func (c *shopGwClient) GetDetailsByProductID(ctx context.Context, req *shop_gwV1.GetDetailsByProductIDRequest) (*shop_gwV1.GetDetailsByProductIDReply, error) {
err := req.Validate()
if err != nil {
logger.Warn("req.Validate error", logger.Err(err), logger.Any("req", req), interceptor.CtxRequestIDField(ctx))
return nil, ecode.StatusInvalidParams.Err()
}
// fill in the business logic code here
productReply, err := c.productCli.GetByID(ctx, &productV1.GetByIDRequest{
Id: req.ProductID,
})
if err != nil {
return nil, err
}
logger.Info("get product info successfully", interceptor.CtxRequestIDField(ctx))
inventoryReply, err := c.inventoryCli.GetByID(ctx, &inventoryV1.GetByIDRequest{
Id: productReply.InventoryID,
})
if err != nil {
return nil, err
}
logger.Info("get inventory info successfully", interceptor.CtxRequestIDField(ctx))
commentReply, err := c.commentCli.ListByProductID(ctx, &commentV1.ListByProductIDRequest{
ProductID: req.ProductID,
})
if err != nil {
return nil, err
}
logger.Info("list comments info successfully", interceptor.CtxRequestIDField(ctx))
return &shop_gwV1.GetDetailsByProductIDReply{
ProductDetail: productReply.ProductDetail,
InventoryDetail: inventoryReply.InventoryDetail,
CommentDetails: commentReply.CommentDetails,
}, nil
}
(5) Compile and start the shop_gw service
make run
You can test the API interface by opening http://localhost:8080/apis/swagger/index.html in your browser.
Summary
Using the Sponge tool, it is easy to build a microservice cluster. The common service governance functions of each microservice in the cluster are also available, such as service registration and discovery, throttling, circuit breaking, link tracking, monitoring, performance analysis, resource statistics, CICD, etc. These functions are enabled or disabled in the YML configuration file. As long as the grpc methods are defined well in the proto file, the subsequent development is basically filling in the business logic code in the generated template code and verifying the business logic in the generated test code, making development simplified, improving development efficiency and saving development time.
Posted on November 7, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.