如何使 Protobuf 3 字段成为强制性字段?
How to make Protobuf 3 fields mandatory?
我正在使用 GRPC/proto-buffers 在 GoLang 中编写我的第一个 API 端点。我对 GoLang 很陌生。
下面是我正在为我的测试用例编写的文件
package my_package
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
"github.com/MyTeam/myproject/cmd/eventstream/setup"
v1handler "github.com/MyTeam/myproject/internal/handlers/myproject/v1"
v1interface "github.com/MyTeam/myproject/proto/.gen/go/myteam/myproject/v1"
)
func TestEndpoint(t *testing.T) {
conf := &setup.Config{}
// Initialize our API handlers
myhandler := v1handler.New(&v1handler.Config{})
t.Run("Success", func(t *testing.T) {
res, err := myhandler.Endpoint(context.Background(), &v1interface.EndpointRequest{
A: "S",
B: &structpb.Struct{
Fields: map[string]*structpb.Value{
"T": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "U",
},
},
"V": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "W",
},
},
},
},
C: ×tamppb.Timestamp{Seconds: 1590179525, Nanos: 0},
})
require.Nil(t, err)
// Assert we got what we want.
require.Equal(t, "Ok", res.Text)
})
}
这是 EndpointRequest
对象在上面包含的 v1.go
文件中的定义方式:
// An v1 interface Endpoint Request object.
message EndpointRequest {
// a is something.
string a = 1 [(validate.rules).string.min_len = 1];
// b can be a complex object.
google.protobuf.Struct b = 2;
// c is a timestamp.
google.protobuf.Timestamp c = 3;
}
上面的测试用例似乎工作正常。
我制定了有效地使参数 a
成为必需参数的验证规则,因为它要求 a
是一个至少包含一个的字符串。因此,如果您省略 a
,则端点 returns 为 400。
但现在我想确保端点 returns 400 if c
或 b
被省略。我怎样才能做到这一点?在 Protobufs 3 中,他们去掉了 required
关键字。那么如何检查是否传入了非字符串参数并做出相应的反应?
已在 proto3
中删除必填字段。 Here is github issue 您可以在其中阅读详细解释为什么这样做。以下是摘录:
We dropped required fields in proto3 because required fields are generally considered harmful and violating protobuf's compatibility semantics. The whole idea of using protobuf is that it allows you to add/remove fields from your protocol definition while still being fully forward/backward compatible with newer/older binaries. Required fields break this though. You can never safely add a required field to a .proto definition, nor can you safely remove an existing required field because both of these actions break wire compatibility
IMO,这是一个有问题的决定,显然我并不孤单,谁在想。最终决定应该留给开发者。
简短版本:你不能。
required
被删除主要是因为它使更改向后不兼容。尝试使用验证选项重新实现它并没有那么激烈(更改更容易),但如您所见,运行 会出现缺点。
相反,将验证保留在原型定义之外,并将其移至应用程序本身。任何时候你收到一条消息,无论如何你都应该检查它的内容(当 required
成为现实时也是如此)。在极少数情况下,选项或 required
提供的简单验证就足够了。
我正在使用 GRPC/proto-buffers 在 GoLang 中编写我的第一个 API 端点。我对 GoLang 很陌生。 下面是我正在为我的测试用例编写的文件
package my_package
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
"github.com/MyTeam/myproject/cmd/eventstream/setup"
v1handler "github.com/MyTeam/myproject/internal/handlers/myproject/v1"
v1interface "github.com/MyTeam/myproject/proto/.gen/go/myteam/myproject/v1"
)
func TestEndpoint(t *testing.T) {
conf := &setup.Config{}
// Initialize our API handlers
myhandler := v1handler.New(&v1handler.Config{})
t.Run("Success", func(t *testing.T) {
res, err := myhandler.Endpoint(context.Background(), &v1interface.EndpointRequest{
A: "S",
B: &structpb.Struct{
Fields: map[string]*structpb.Value{
"T": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "U",
},
},
"V": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "W",
},
},
},
},
C: ×tamppb.Timestamp{Seconds: 1590179525, Nanos: 0},
})
require.Nil(t, err)
// Assert we got what we want.
require.Equal(t, "Ok", res.Text)
})
}
这是 EndpointRequest
对象在上面包含的 v1.go
文件中的定义方式:
// An v1 interface Endpoint Request object.
message EndpointRequest {
// a is something.
string a = 1 [(validate.rules).string.min_len = 1];
// b can be a complex object.
google.protobuf.Struct b = 2;
// c is a timestamp.
google.protobuf.Timestamp c = 3;
}
上面的测试用例似乎工作正常。
我制定了有效地使参数 a
成为必需参数的验证规则,因为它要求 a
是一个至少包含一个的字符串。因此,如果您省略 a
,则端点 returns 为 400。
但现在我想确保端点 returns 400 if c
或 b
被省略。我怎样才能做到这一点?在 Protobufs 3 中,他们去掉了 required
关键字。那么如何检查是否传入了非字符串参数并做出相应的反应?
已在 proto3
中删除必填字段。 Here is github issue 您可以在其中阅读详细解释为什么这样做。以下是摘录:
We dropped required fields in proto3 because required fields are generally considered harmful and violating protobuf's compatibility semantics. The whole idea of using protobuf is that it allows you to add/remove fields from your protocol definition while still being fully forward/backward compatible with newer/older binaries. Required fields break this though. You can never safely add a required field to a .proto definition, nor can you safely remove an existing required field because both of these actions break wire compatibility
IMO,这是一个有问题的决定,显然我并不孤单,谁在想。最终决定应该留给开发者。
简短版本:你不能。
required
被删除主要是因为它使更改向后不兼容。尝试使用验证选项重新实现它并没有那么激烈(更改更容易),但如您所见,运行 会出现缺点。
相反,将验证保留在原型定义之外,并将其移至应用程序本身。任何时候你收到一条消息,无论如何你都应该检查它的内容(当 required
成为现实时也是如此)。在极少数情况下,选项或 required
提供的简单验证就足够了。