From grpc/grpc-dotnet issue #2097
I am new to gRPC and I am not sure if I am implementing the FieldMask in the correct way.
Here are my messages definitions
// Events messages
message Event {
// optional string id = 1 [deprecated = true];
reserved 1;
optional string name = 2;
optional string description = 3;
// ...
optional string locationId = 21;
}
message UpdateEventRequest {
string id = 1;
Event event = 2;
google.protobuf.FieldMask updateMask = 3;
}
and here is my csharp code
public override async Task<EventResponse> UpdateEvent(UpdateEventRequest request, ServerCallContext context)
{
if (!_eventRepository.Exists(request.Id, out var evt) || evt is null)
{
throw new RpcException(new Status(StatusCode.NotFound, "Entity not found"));
}
var dto = evt.AdaptToDto();
request.UpdateMask.Merge(request.Event, dto);
await new EventValidator().ValidateAndThrowAsync(dto);
evt = dto.AdaptToPoco(evt);
var success = _eventRepository.UpdateEvent(evt);
if (!success) throw new RpcException(new Status(StatusCode.NotFound, "Entity not updated."));
return new EventResponse
{
Id = evt.Id,
Event = dto
};
}
I am using .NET7 and Grpc.AspNetCore 2.52.0
when I try to update a field that has pascal-case (like locationId
) I face this wired error that occurs with some clients, when I send this request
{
"id": "fd416fa0-5794-4bdc-be9e-1feece4f7cac",
"event": {
"locationId": "e3362b3b-2b8d-42cd-8c63-a5d9d9d46597"
},
"updateMask": "locationId"
}
in the path locationId
get translated to location_id
, where the merge fails.
but I am sending the following request
{
"id": "fd416fa0-5794-4bdc-be9e-1feece4f7cac",
"event": {
"locationId": "e3362b3b-2b8d-42cd-8c63-a5d9d9d46597"
},
"updateMask": {
"paths": [
"locationId"
]
}
}
the merge works but there is a warning inside the FieldMask
Did I do something wrong? Is this the expected behavior, and how can I fix it?
This comment on the source-code of FieldMask
points that:
Fields name in each path are converted to/from lower-camel naming conventions.
(a.k.a snake_case)
And in the examples you see they use full paths, not only the field they want to update but they also specify the message that contains it if any.
So, with your current JSON request I think you are technically requesting the update of a "root-level" field called location_id
.
Consider using location_id
as a field-name to align with the style-guide or specify a json_name
(assuming you are using proto3
) like this:
message Event {
// optional string id = 1 [deprecated = true];
reserved 1;
optional string name = 2;
optional string description = 3;
// ...
optional string locationId = 21 [json_name = "location_id"];
}
And making the request like this should get it working:
{
"id": "fd416fa0-5794-4bdc-be9e-1feece4f7cac",
"event": {
"locationId": "e3362b3b-2b8d-42cd-8c63-a5d9d9d46597"
},
"updateMask": {
"paths": [
"event.locationId"
]
}
}