【问题标题】:Should a Database Table Use the Identical Struct as Defined in the API?数据库表是否应该使用 API 中定义的相同结构?
【发布时间】:2021-04-10 09:47:31
【问题描述】:

假设我有一个 grpc 服务,并且有一个 API 可以像这样创建新用户:

 service UserService{
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
}

message User {
  string userId = 1;
  string firstName = 2;
  string lastName = 3;
  string password = 4;
}
message CreateUserRequest {
  user User = 1;
}

message CreateUserResponse {
  user User = 1;
}

该服务将用户数据保存到 PostgresDb 中的 users_table 中,如下所示:

user1 := NewUser() // instantiating the User object as defined in the proto file.
// user2 := NewMyUser() // instantiating the MyUser object as defined separately in the service.
result := s.db.Table(UsersTable).Create(user1) 

另外,我正在使用 proto buffer 根据上面的 api proto 文件生成服务器和客户端代码。 我的问题是:实例化用户对象时,用户应该是原型定义中定义的生成的用户结构吗?还是应该像这样在 postgresDb 专用服务中定义另一个 User 结构作为模型?

struct MyUser {
      userId string
      firstName string 
      lastName  string 
      password string 
      createdAtMs int64 // an extra field not available in the api
}

后续问题: 每种方法的优缺点是什么?它的最佳设计原则是什么?

【问题讨论】:

    标签: database api go architecture grpc


    【解决方案1】:

    这两种方式在实践中都会发生。这可能主要取决于您的服务有多少逻辑;具有很少逻辑的服务(例如,围绕数据库的小包装器)更有可能将原型直接存储在数据库中。拥有相似但略有不同的原型是很常见的,其中数据在通过系统时在每一步都被复制。

    如果您将 proto 直接存储在数据库中,然后意识到自己犯了错误,您可以通过创建一个与旧消息兼容的新消息来“分叉”proto 消息(一个新名称,但所有字段都相同)具有相同的 ID)。您有将代码迁移到新消息的痛苦(将旧消息留在您的服务中),但使用这种方法,您不必在切换到新消息类型之前重新编码数据库中的所有数据。

    如果您选择在数据库中使用相同的消息,您应该确保在存储之前去除未知字段。否则,当您将来添加新字段时,您可能会发现已损坏/恶意客户端已在该字段中存储数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      相关资源
      最近更新 更多