protoapi扩展protobuf的一些搞笑过程

总结protobapi扩展protobuf的设计过程, 有点哭笑不得!
应了一句话: 众里寻她千百度, 蓦然回首, 那人也不在灯火处!

辩证评价protobuf二种扩展机制

  • protobuf custom options
  • protobuf comment constraints

从protobuf的扩展机制说起

protobuf custom options

protobuf提供了custom options实现AOP编程思想, 与Java的annotations, 以及golang的tag语法的实质是相同的.
开发者可以基于custom options去扩展业务逻辑, 毕竟protobuf真是一个IDL! 借助现成的IDE工具, 可以帮助完成
相关的语法错误检查, 快速实现跨语言的解决方案! 这本来是一种很优秀的解决框架, 惟一不爽就是custom options
侵入性太强! 为了使用"custom options", 你必须"import descriptor.proto", 直接后果就是通过protoc-gen-go
生成的xxx.pb.go也会自动import相应的package, 对于server端而言小事一件, 但对于client端来说相当困惑!
为了生成xxx.proto相应的调用代码, 还强迫去引用所有custom options的库! 相当地不人道!

举个例子:

  • student.proto
syntax = "proto3";

package api;

import "fasgo/http/annotations.proto";
import "fasgo/sqlx/annotations.proto";

// 定义班级信息
message Clazz {
  int64 cno = 1; // 班级编号
  string name = 2; // 班级名称
  string desc = 3; // 班级描述
}

// 定义学生信息
// +TABLE -name=student -engine=InnoDB -comment=学生测试表
message Student {
  option (sqlx.table) = {name:"student" engine:"InnoDB" comment:"学生测试表"};
  // +COLUMN -name=s_no -comment="学生编号"
  string sno = 1 [(sqlx.column) = {name:"s_no"}]; // 学生编号
  string name = 2; // 学生名称
  uint32 gender = 3; // 性别
  int32  grade = 4; // 排名
  repeated float  score = 5; // 多门评分
  Clazz  clazz = 6; // 班级信息
}
  • student.pb.go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.25.0
// 	protoc        v3.14.0
// source: student.proto

package api

import (
	_ "fasgo/http"
	_ "fasgo/sqlx"
	proto "github.com/golang/protobuf/proto"
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
)

const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
	// Verify that runtime/protoimpl is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

protobuf custom constraints

借鉴golang constraints语法, 设计protobuf constraints的3种用法:

  • +<CONSTRAINT>
  • +<CONSTRAINT> [value]
  • +<CONSTRAINT> -<option>[=value]...

constraints以行为单位, 同一个constraint的配置必须在同一行. 但同一行可以包含多个constraints.

理性分析

protobuf custom options

  1. 官方标配. 大众接收度高, 可以显得B格!
  2. 语法检查. 现有工具与IDE检查支持, 这也得益于官方标配!

protobuf custom constraints

  1. 自己实现. 人各有志, 志各有异, 众口难调!
  2. 基于注释. 没有任何语法检查或安全检查, 与预期效果相悖!

毕竟, 设计初衷就是围绕protobuf为中心, 实现"自动化生成, 自动化测试, 自动化文档"等效果!

合二为一, 皆大欢喜

  1. 二者各有所长, 为甚非要二选一?
  2. 二者都可实现, 为甚非要二选一?

以custom options为主, custom constraints为辅! options可以覆盖constraints即可!

重构设计

  • 描述符:
- github.com/fasgo/include: 包含所有proto描述符
	+ github.com/fasgo/protoapi/http/options.proto
	+ github.com/fasgo/protoapi/sqlx/options.proto
  • 源代码:
- github.com/fasgo/protoapi/http
- github.com/fasgo/protoapi/sqlx
  • 工具箱:
- github.com/fasgo/protoapi/cmd/
	+ protoc-gen-go-http/
	+ protoc-gen-go-sqlx/

- github.com/fasgo/protogen
  • 项目结构:
<workspace>
|__api
|  |__student.proto
|  |__student.pb.go
|  |__student_grpc.pb.go
|  |__student_http.pb.go
|  |__student_sqlx.pb.go
|__biz
|__main.go
|__conf.toml.tpl
|__conf.toml //本地测试

示例DEMO

http

  • constraint short
// +GET /demo/:user_id +JSON
rpc Get(Student) returns (Student);
  • constraint long
// +http.get -path=/demo/:user_id -body=json
rpc Get(Student) returns (Student);
  • options
import "github.com/fasgo/protoapi/http/options.proto";

rpc Get(Student) returns (Student) {
    option (http.get) = {path:"/demo/:user_id" body:json}
}

sqlx

  • constraint short
// +TABLE [name]
message Student {
    // +COLUMN [name] +TYPE VARCHAR +LENGTH 256 +SCALE 0 +AUTO_INCREMENT +...
    string sno = 1;
}
  • constraint long
// +sqlx.table -name=[name] ...
message Student {
    // +sqlx.column -name=[name] -type=VARCHAR -length=255 -scale=0 -auth_increment[=true]
    string sno = 1;
}
  • options
import "github.com/fasgo/protoapi/sqlx/options.proto";

message Student {
    option (sqlx.table) = {name:"xxx"}
    string sno = 1 [(sqlx.column)={name:xxx type:VARCHAR length:255 ...}];
}

现在要做的就是三种声明语法都实现...

posted @ 2020-12-15 11:30  zolo®  阅读(323)  评论(0编辑  收藏  举报