i’m following the documentation here
and have this in my protobuf service definition
message ListUsersResponse {
repeated UserViewState results = 1;
}
service ListUsers {
option (kalix.codegen) = {
view: {}
};
rpc UpdateUser(bet.gente.user.domain.UserState) returns (UserViewState) {
option (kalix.method).eventing.in = {
value_entity: "user"
};
option (kalix.method).view.update = {
table: "users_list"
transform_updates: true
};
}
rpc ListUsers(google.protobuf.Empty) returns (ListUsersResponse) {
option (kalix.method).view.query = {
query: "SELECT * AS results FROM users_list"
};
option (kalix.method).acl = {
allow: { principal: ALL }
};
}
}
and the method that transforms UserState => UserViewState
is
override def updateUser(state: UserViewState, userState: UserState): UpdateEffect[UserViewState] = {
val viewState = UserViewState(userId = userState.userId, name = userState.name, email = userState.email)
effects.updateState(viewState)
}
However, i ALWAYS get a 400 response from a HTTP request:
Expect message object but got: null
And the result of a gRPC request to ListUsers looks like this:
{
"user_id": "\n\u0006trevor\u0012\u000etrevor@eli.com\u001a\u0006trevor",
"email": "",
"name": ""
}
I’m clearly missing something here but i can’t find it in the documentation - can anyone show me where i’m making the mistake?
It looks like the request you’re doing there might not be correct… could you show us how the request and what the corresponding proto looks like on the User ValueEntity? The code for the view looks OK as far as I can see, so I would expect the issue to be on the source of the view (the User ValueEntity).
thanks for your reply - sure, here’s the proto for the value entity:
message User {
string user_id = 1 [(kalix.field).entity_key = true];
string email = 2;
string name = 3;
}
service UserService {
option (kalix.codegen) = {
value_entity: {
name: "bet.gente.user.domain.User"
entity_type: "user"
state: "bet.gente.user.domain.UserState"
}
};
rpc CreateUser(User) returns (google.protobuf.Empty) {
option (kalix.method).acl = {
allow: { principal: ALL }
};
}
rpc GetUser(GetUserRequest) returns (User) {}
rpc ChangeName(ChangeNameRequest) returns (google.protobuf.Empty) {}
}
and the UserState
is:
message UserState {
string user_id = 1;
string email = 2;
string name = 3;
}
I’m sending the CreateUser
HTTP command from Postman - the code version is:
curl --location --request POST 'http://localhost:9000/bet.gente.user.api.UserService/CreateUser' \
--header 'Content-Type: application/json' \
--data-raw '{
"user_id": "trevor",
"name": "trevor",
"email": "trevor@eli.com"
}'
and i’m using BloomRPC for the ListUsers
request because grpcurl
doesn’t seem to like the local setup…
grpcurl -plaintext localhost:9000 list
gives me
bet.gente.user.api.UserService
but
grpcurl -plaintext localhost:9000 describe bet.gente.user.api.UserService
gives me
Failed to resolve symbol "bet.gente.user.api.UserService": Symbol not found: bet.gente.user.api.UserService
so i think i’m missing something else there, too because when i do
grpcurl -d '{}' -plaintext localhost:9000 bet.gente.user.view.ListUsers/ListUsers
I get
Error invoking method "bet.gente.user.view.ListUsers/ListUsers": target server does not expose service "bet.gente.user.view.ListUsers"
and yet BloomRPC gives me the result from the message in the original post… i must be doing all sorts of things wrong
sorry, missed the HTTP ListUsers
command
curl --location --request POST 'http://localhost:9000/bet.gente.user.view.ListUsers/ListUsers' \
--header 'Content-Type: application/json' \
--data-raw ''
I also tried with an empty json object in case that was what the expected object got null
was about
curl --location --request POST 'http://localhost:9000/bet.gente.user.view.ListUsers/ListUsers' \
--header 'Content-Type: application/json' \
--data-raw '{}'
I used the .g8
template which references kalix v1.2.1-M3 - i tried M4 as well as earlier versions going back to v1.2.0 just in case - always the same results as described above
ok, update - the empty object in the body of the HTTP request was missing from Postman’s request - that fixes the HTTP version when i curl
the ListUsers
endpoint i get
{
"results": [
{
"id": "trevor2",
"email": "trevor2@eli.com",
"name": "trevor"
},
{
"id": "eli",
"email": "eli@eli.com",
"name": "eli"
}
]
}
the results
array contains all the users…
the gRPC response, though, not so much… hitting ListUsers
using grpcurl i get:
$ grpcurl -d '{}' -plaintext localhost:9000 bet.gente.user.view.ListUsers/ListUsers
Error invoking method "bet.gente.user.view.ListUsers/ListUsers": target server does not expose service "bet.gente.user.view.ListUsers"
It’s been a while since i worked with gPRC endpoints and didn’t realise BloomRPC was deprecated :face-palm - but Postman gPRC works just fine so there’s something i’m missing about that grpcurl command, it seems
T
Tried a few different things locally but cannot really reproduce that behaviour. As in, I can obviously reproduce that error if I provide the wrong path for the service but given you seem to be using the same path for gRPC and HTTP AFAICS, I’m not seeing a reason for it to fail.
Does the view endpoint get listed when you do grpcurl --plaintext localhost:9000 list
?
If you have the chance to share the full code or a smaller sample that I can reproduce locally, then we could at least know if this is something on kalix or some weird thing with your local setup.
Ii’m able to reproduce the behaviour with the sbt giter8 template - i create a new project with sbt new lightbend/kalix-value-entity.g8
and while grpcurl -plaintext localhost:9000 list
gives me
com.example.CounterService
grpc.reflection.v1alpha.ServerReflection
when i do grpcurl -plaintext localhost:9000 describe com.example.CounterService
i get:
Failed to resolve symbol "com.example.CounterService": Symbol not found: com.example.CounterService
And when i do grpcurl -d '{"counterId": "foo"}' -plaintext localhost:9000 com.example.CounterService/CurrentCounter
(the example command from the docs) i get:
Error invoking method "com.example.CounterService/CurrentCounter": target server does not expose service "com.example.CounterService"
It seems like this is down to an issue on grpcurl
itself. We’ve managed to reproduce this if using grpcurl 1.8.1 but once upgraded to grpcurl 1.8.7 it works as expected. (I’m not certain from which version the fix is included but it works as expected with 1.8.7).