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
- 官方标配. 大众接收度高, 可以显得B格!
- 语法检查. 现有工具与IDE检查支持, 这也得益于官方标配!
protobuf custom constraints
- 自己实现. 人各有志, 志各有异, 众口难调!
- 基于注释. 没有任何语法检查或安全检查, 与预期效果相悖!
毕竟, 设计初衷就是围绕protobuf为中心, 实现"自动化生成, 自动化测试, 自动化文档"等效果!
合二为一, 皆大欢喜
- 二者各有所长, 为甚非要二选一?
- 二者都可实现, 为甚非要二选一?
以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 ...}];
}
现在要做的就是三种声明语法都实现...