Example 6, Build a simple golang e-commerce microservices framework step by step using tool

zhufuyi

zhuyasen

Posted on November 7, 2023

Example 6, Build a simple golang e-commerce microservices framework step by step using tool

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.

Image description

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
Enter fullscreen mode Exit fullscreen mode

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:

Image description

Quickly create an inventory service as shown below:

Image description

Quickly create a product service as shown below:

Image description

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
Enter fullscreen mode Exit fullscreen mode

(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
Enter fullscreen mode Exit fullscreen mode

(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  
Enter fullscreen mode Exit fullscreen mode

(4) Compile and start the comment service

make run
Enter fullscreen mode Exit fullscreen mode

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  
Enter fullscreen mode Exit fullscreen mode

(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
Enter fullscreen mode Exit fullscreen mode

(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   
Enter fullscreen mode Exit fullscreen mode

(4) Compile and start the inventory service

make run
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

(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
Enter fullscreen mode Exit fullscreen mode

(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
Enter fullscreen mode Exit fullscreen mode

(4) Compile and start the product service

make run
Enter fullscreen mode Exit fullscreen mode

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.

Image description

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.

Image description

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
Enter fullscreen mode Exit fullscreen mode

(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: ""
Enter fullscreen mode Exit fullscreen mode

(3) Generate pb.go code, generate registered routing code, generate template code, and generate swagger documentation

make proto
Enter fullscreen mode Exit fullscreen mode

(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
}
Enter fullscreen mode Exit fullscreen mode

(5) Compile and start the shop_gw service

make run
Enter fullscreen mode Exit fullscreen mode

You can test the API interface by opening http://localhost:8080/apis/swagger/index.html in your browser.

Image description

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.

💖 💪 🙅 🚩
zhufuyi
zhuyasen

Posted on November 7, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related