问题描述
我对 protobuf 很陌生,所以请多多指教。
我注意到在 protobuf 消息类型中具有唯一标识符是很常见的,如下所示:
message ToDo {
int64 id = 1; // unique id
string title = 2;
string description = 3;
google.protobuf.Timestamp reminder = 4;
}
然后可以在服务中使用消息类型来创建请求,例如
service ToDoService {
rpc Create(Todo) returns (CreateResponse) {}
}
我的预期行为是使用插入数据库时生成的 id
处理请求。但是,这意味着 id
仍然可以在请求负载中传递,但实际上会被忽略,因为 id
中的 ToDo
字段仅与读取响应相关。
例如,在下面的 todo.Id
方法中根本没有引用 Create
。
func (s *toDoServiceServer) Create(ctx context.Context,todo *v1.ToDo) (*v1.CreateResponse,error) {
// ... not relevant
// insert ToDo entity data
res,err := c.ExecContext(ctx,"INSERT INTO ToDo(`Title`,`Description`,`Reminder`) VALUES(?,?,?)",todo.ToDo.Title,todo.ToDo.Description,reminder)
if err != nil {
return nil,status.Error(codes.Unknown,"failed to insert into ToDo-> "+err.Error())
}
// get ID of creates ToDo
id,err := res.LastInsertId()
if err != nil {
return nil,"failed to retrieve id for created ToDo-> "+err.Error())
}
return &v1.CreateResponse{
Id: id,},nil
}
在我看来,这在向服务发出请求时有点令人困惑,因为可以假设应该提供 id
,但实际上不应该提供。由于 protobuf 中没有 readonly 字段,是否是为 ToDo
提供两种不同消息类型的唯一选择,其中 id
仅出现在一种中?例如
message ToDoRequest {
// no id
string title = 1;
string description = 2;
google.protobuf.Timestamp reminder = 3;
}
message ToDo {
int64 id = 1; // unique id
string title = 2;
string description = 3;
google.protobuf.Timestamp reminder = 4;
}
那样 ToDoRequest
仅用于创建/更新请求,而 ToDo
仅用于读取响应。我唯一的问题是,仅仅为了使 id
成为“只读”而将所有其他字段定义两次似乎很乏味。
解决方法
您也可以撰写消息
syntax = "proto3";
package todo;
import "google/protobuf/timestamp.proto";
message ToDo {
string title = 1;
string description = 2;
google.protobuf.Timestamp reminder = 3;
}
message ToDoEntity {
int64 id = 1;
ToDo todo = 2;
}
message ToDoRequest {
ToDo todo = 1;
}