Description
Hi,
I'm trying to implement a request with optional (omit) parameters with validation constrains.
As far as I understand, optional field can be achieved using oneof.
In addition, protoc-gen-validate supports oneof.
Unfortunately, when using oneof, the swagger definition and grpc-ecosystem are changed and I can't use the original field name.
Given the following proto:
syntax = "proto3";
package pb;
import "google/api/annotations.proto";
import "github.com/envoyproxy/protoc-gen-validate/validate/validate.proto";
service Account {
rpc Update(UpdateRequest) returns (UpdateResponse) {
option (google.api.http) = {
put: "/v1/account/{ID}"
body: "*"
};
}
}
message ID {
uint32 ID = 1 [(validate.rules).uint32.gte = 0];
};
message UpdateRequest {
int32 ID = 1;
string FirstName = 2 [(validate.rules).string.min_len = 2];
oneof LastName {
bool LastNameNull = 3;
string LastNameValue = 4 [(validate.rules).string.min_len = 2];
}
}
message UpdateResponse {
int32 ID = 1;
string FirstName = 2;
string LastName = 3;
}
- Whenever there is a oneof in the protobuf definition all the keys are simply added to the object: LastNameNull & LastNameValue. In other words, My request payload should contain
LastNameValue
instead of simplyLastName
.
Keep in mind that my Request struct fields should have the same naming as my DB struct for marshaling purposes, therefore the following will not work for me As it addsLastNameValue isUpdateRequest_LastNameValue
to the generated struct:
oneof LastNameValue {
bool LastNameNull = 3;
string LastName = 4 [(validate.rules).string.min_len = 2];
}
-
If I try to send a request with
FirstName
defined, I get the following errorjson: cannot unmarshal string into Go value of type pb.isUpdateRequest_LastName
.
According to @ivucica's comment I should implement UnmarshalJSONPB for that object. Unfortunatelypb.isUpdateRequest_LastName
is an interface and therefore his suggestion is not applicable. -
What is your approach to unified DB & API validation errors?
I have 2 validation levels. gRPC request level (max length etc) and DB objects (email already exists, etc) which can result in different naming convention, especially when nested structs are involved.
I'm using the following interceptors to try and minimaize the situation by maintaining the same error structure.
But still, I'm using different structs and therefore there will be different Naming in the error message & field name.
Please advise how to handle this situation,
Thanks!