In the previous blog I started my journey into Protobuf and introduced my first steps by introducing an example Contract service and some business operations on it.
Now let’s start with diving into details of how to model the gRPC calls.

Modeling a call

As all the RPC calls of my service basically have the same basic structure, I will zoom in on the first one, the newQuote() call and detail it:

Listing 1. grpc_contract_api_v1.proto (partial)
import "google/type/money.proto"; (1)

service ContractService {
    rpc newQuote (NewQuoteRequest) returns (NewQuoteResponse);

message NewQuoteRequest {
    string fullNameOfCustomer = 1;
    google.type.Money quotedPrice = 2; (2)
    string descriptionOfWorkRequested = 3;

message NewQuoteResponse {
    string contractId = 1; (3)
1 Import one of the many Google-defined standard types
2 No BigDecimal in Protobuf, so we use Money here
3 Encapsulated contract id

There’s a lot of things happening in this definition and decisions have been made. Let’s look at them in detail.

Designed for extensibility

The NewQuoteRequest and NewQuoteResponse messages look bloated, don’t they? Even though only the contract id needs to be returned it still is in a separate response message.
Maybe we could have returned a 'string' type, so why this way?

The answer is a technical one, gRPC just doesn’t allow these primitive types in a RPC response.

But there’s a good reason gRPC does not allow it.[1]

Let’s assume it is allowed to return a primitive on a call. Then if I wanted to enhance the data returned by the call, either I’d have to make a separate RPC call for it with its own response message (say a V2 version) - or prepare for it in advance, which is what I’m doing here.

Protobuf has some very fancy ways to cope with extensibility on the field level, but if the request or response messages itself are wrong, that’s bad.

Modelling fancy stuff

The list of datatypes in protobuf is elaborate but one of the design principals of Protobuf is that it should cater for a wide variety of target platforms, and the all the datatypes that live there. This regrettably means that datatypes like BigDecimal are just not there (yet).[2]

Within the Java world we are used to representing money with a BigDecimal class, so we either have to model it ourselves, or we can import one of Google’s common types[3] to represent it.

Not-So-Happy Flow

The next decision is one that is not immediately visible as it is one of omission. The definition I’ve made doesn’t have any provision for errors: no codes, no special block, nothing. Errorhandling is always difficult in protocols, in gRPC that’s no different.

When I started out creating my democode with resultcode and reason fields I quickly became aware that I was digging myself into a hole, so I stopped like you should [4] and found another solution.

Full model

The full model can be seen here: grpc-contract-service definition. As you can see, it’s more of the same except for the admin stuff at the top which I’ll not go into.

In the next Blog I will investigate the not-so-happy Flow in more detail: Practical protobuf - The Not-So-Happy Flow