go gRPC 字段验证

1,532 阅读2分钟

grpc proto 文件 字段验证

之前已经写了gRPC 和 gRPC gateway
今天把字段进行验证一下
上一篇文章链接

准备工作

  • 安装protoc-gen-validate
  • 引入validate.proto
  • 生成pb.validate.go
  • 调用验证器

安装

这里的安装和之前不太相同,git README 中给出是 go get -d -u 从网络下载,如果本地有了就不下载,然后安装 -d 只下载不安装

# 找到GOPATH
go env | grep GOPATH

# 在 GOPATH 中的 src下面进行go get -d
go get -d github.com/envoyproxy/protoc-gen-validate

引入validate/validate.proto

这个文件的路径在刚才go get -d的文件夹中
具体路径为$GOPATH/src/github.com/envoyproxy/protoc-gen-validate/validate

model.proto

syntax = "proto3";
package services;
option go_package = ".;services";

import "google/protobuf/timestamp.proto"; // 引入时间类型
import "validate/validate.proto"; // validate 三方库

// 商品模型
message ProdModel{
  int32 prod_id = 1;
  string prod_name = 2;
  float prod_price = 3;

}

// 订单信息
message OrderInfo{
  int32 order_id = 1; // 订单id
  int32 order_no = 2; // 订单编号
  int32 order_userId = 3; // 订单用户id
  float order_price = 4 [(validate.rules).float.gt = 1]; // 订单金额,进行限制 大于0
  google.protobuf.Timestamp order_time = 5;// 订单时间
  repeated OrderDetail order_details = 6; // 拆分的一些订单

}
// 拆分订单
message OrderDetail{
  int32 order_detail_id = 1; //拆分订单id
  int32 order_detail_no = 2; //拆分订单号
  int32 order_no = 3; // 主订单no
  int32 order_type = 4; // 订单类型
  int32 order_num = 5; // 订单物品数量
}

修改之前的genPb.sh 生成 pb.validate.go

cd pb \
&& protoc --go_out=../services --go_opt=paths=source_relative \
           --go-grpc_out=../services --go-grpc_opt=paths=source_relative \
           --validate_out=paths=source_relative,lang=go:../services \ # 生成pb.validate.go
           Prod.proto Models.proto Orders.proto \
&& protoc -I . \
       --grpc-gateway_out ../services/Gateway/ \
       --grpc-gateway_opt logtostderr=true \
       --grpc-gateway_opt paths=source_relative \
           Prod.proto Models.proto Orders.proto

在gRPC接口实现中进行验证

// orderService.go
// 创建订单接口实现
func (o *OrderService)NewOrder(ctx context.Context,request *OrderRequest) (*OrderResponse, error){
   req := request.OrderInfo
   log.Println(req.OrderPrice,req.OrderNo,req.OrderId,req.OrderTime,req.OrderUserId)
   // 参数校验
   err := req.Validate()
   if err != nil{
       // 返回订单创建失败
      return &OrderResponse{
         Status: "error",
         Msg: err.Error(),
      },nil
   }
    //打印订单信息
   for _, detail := range req.OrderDetails {
      log.Println("mainOrderId",detail.OrderNo,"detailId:",detail.OrderDetailId,"detailNo:",detail.OrderDetailNo,"num:",detail.OrderNum,"type:",detail.OrderType)
   }
   // 返回订单创建结果
   return &OrderResponse{
      Status: "1",
      Msg: "创建订单成功",
   },nil

}

调用测试

别忘记 重新build grpc 和httpserver

curl --location --request POST 'http://localhost:23333/v1/createOrder' \
--header 'Content-Type: application/json' \
--data-raw '{
    "order_id": 123,
    "order_no": 321,
    "order_userId": 12345,
    "order_price": 0.5,
    "order_time": "2017-01-15T01:30:15.01Z",
    "order_details": [
        {
            "order_detail_id": 1,
            "order_detail_no": 2,
            "order_no": 3,
            "order_type": 4,
            "order_num": 5
        },
        {
            "order_detail_id": 11,
            "order_detail_no": 22,
            "order_no": 33,
            "order_type": 44,
            "order_num": 55
        }
    ]
}'

结果

{
    "status": "error",
    "msg": "invalid OrderInfo.OrderPrice: value must be greater than 1"
}