go-zero 校验proto实战

743 阅读4分钟

最近我在尝试使用go zero进行微服务开发,在尝试的过程中发现这个框架是非常简单易用的,但是也发现了一些额外的问题。比如说要引用googleapis或者一些常用的proto文件,如protovalidate等。

根据官网所述,目前go-zero的rpc是没有办法引入外部文件的,所以我思考了一个方法,在rpc生成代码的时候跳过生成pb.go文件,改成由buf生成,我们对goctl源码做一丢丢修改,然后得到新的goctl

目前需要手动编译然后把goctl替换到自己的目录下,github.com/chaozwn/go-…

查看新的goctl rpc protoc功能

❯ goctl rpc protoc -h
Generate grpc code

Usage:
  goctl rpc protoc [flags]

Examples:
goctl rpc protoc xx.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.

Flags:
      --branch string     The branch of the remote repo, it does work with --remote
  -c, --client            Whether to generate rpc client (default true)
  -h, --help              help for protoc
      --home string       The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priori
ty
  -m, --multiple          Generated in multiple rpc service mode
      --remote string     The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priori
ty
                          The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure
  -s, --skip_pb           Whether to skip generating pb & grpc file
      --style string      The file naming format, see [https://github.com/zeromicro/go-zero/blob/master/tools/goctl/config/readme.md]
  -v, --verbose           Enable log output
      --zrpc_out string   The zrpc output directory

我们可以看到多了一个--skip_pb的选项,因为protoc去编译包含外部链接的proto文件会报错,所以我们用buf-cli托管。

安装buf, 参考官网: buf.build/docs/instal…

go install github.com/bufbuild/buf/cmd/buf@v1.35.0

安装完成运行buf, 出现以下输出就是正常工作。

❯ buf
Usage:
  buf [flags]
  buf [command]

Available Commands:
  beta        Beta commands. Unstable and likely to change
  breaking    Verify no breaking changes have been made
  build       Build Protobuf files into a Buf image
  completion  Generate auto-completion scripts for commonly used shells
  config      Work with configuration files
  convert     Convert a message between binary, text, or JSON
  curl        Invoke an RPC endpoint, a la 'cURL'
  dep         Work with dependencies
  export      Export proto files from one location to another
  format      Format Protobuf files
  generate    Generate code with protoc plugins
  help        Help about any command
  lint        Run linting on Protobuf files
  ls-files    List Protobuf files
  push        Push to a registry
  registry    Manage assets on the Buf Schema Registry

Flags:
      --debug               Turn on debug logging
  -h, --help                help for buf
      --help-tree           Print the entire sub-command tree
      --log-format string   The log format [text,color,json] (default "color")
      --timeout duration    The duration until timing out, setting it to zero means no timeout (default 2m0s)
  -v, --verbose             Turn on verbose mode
      --version             Print the version

Use "buf [command] --help" for more information about a command.

Sub-command required.

确保自己的goctl也可用,下面开启实战

  1. 先创建一个我们用的proto文件
syntax = "proto3";

package greet;
option go_package="./greet";

// 外部proto文件
import "buf/validate/validate.proto";

message Request {
  // 添加校验参数,如果ping的长度小于6,就会报错
  string ping = 1 [(buf.validate.field).string = {
    min_len: 6
  }];
}

message Response {
  string pong = 1;
}

service Greet {
  rpc Ping(Request) returns(Response);
}

image.png

2.创建项目(在pb目录下执行)

goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../ --zrpc_out=../ --style=goZero -s

这是项目的目录结构

image.png

3.初始化buf配置

buf config init
# buf.yaml
version: v2
lint:
  use:
    - DEFAULT
breaking:
  use:
    - FILE

# 添加下面的代码
deps:
  - buf.build/bufbuild/protovalidate

4.安装依赖

buf dep update

目录下会生成buf.lock

# Generated by buf. DO NOT EDIT.
version: v2
deps:
  - name: buf.build/bufbuild/protovalidate
    commit: a6c49f84cc0f4e038680d390392e2ab0
    digest: b5:e968392e88ff7915adcbd1635d670b45bff8836ec2415d81fc559ca5470a695dbdc30030bad8bc5764647c731079e9e7bba0023ea25c4e4a1672a7d2561d4a19
  1. 手动创建buf.gen.yaml文件
version: v2

plugins:
  - remote: buf.build/grpc/go
    # Make sure to generate your grpc-go code to the same
    # directory as protoc-gen-go
    out: ../
  - remote: buf.build/protocolbuffers/go
    out: ../

ok, 一切准备就绪,后面我们全程都会用buf来管理我们的pb文件生成。

  1. buf生成pb文件
buf generate --path ./pb/greet.proto --output ./pb˙

这是最新的目录结构

image.png

  1. 刷新依赖
go mod tidy
  1. 我们对internal/server/greetServer.go稍作修改,后续的规模化更改完全可以通过模板来完成。不要忘记go mod tidy
// Code generated by goctl. DO NOT EDIT.
// Source: greet.proto

package server

import (
	"context"
	"rpc_test/greet"
	"rpc_test/internal/logic"
	"rpc_test/internal/svc"
   // 对应依赖
	"github.com/bufbuild/protovalidate-go"
	"github.com/pkg/errors"
)

type GreetServer struct {
	svcCtx *svc.ServiceContext
	greet.UnimplementedGreetServer
}

func NewGreetServer(svcCtx *svc.ServiceContext) *GreetServer {
	return &GreetServer{
		svcCtx: svcCtx,
	}
}

func (s *GreetServer) Ping(ctx context.Context, in *greet.Request) (*greet.Response, error) {
   // 增加直接校验
	v, _ := protovalidate.New()
	if err := v.Validate(in); err != nil {
		return nil, errors.Cause(err)
	}
	l := logic.NewPingLogic(ctx, s.svcCtx)
	return l.Ping(in)
}
  1. 对系统进行测试, 移除掉greet.yamletcd的配置
Name: greet.rpc
ListenOn: 0.0.0.0:8080

image.png

image.png