Golang. CRUD with gRPC. Protobuf style convention.

Yuri Fenyuk
4 min readJun 13, 2023

--

The current chapter is the continuation of Golang related series started with the previous ones:

The input for the current chapter is here. The project has gRPC framework to support CRUD operations for simple Brand entity. The protobuf message from the same scheme are used to persist Brand repository into file system. As of current state, project exposes Brands via gRPC server and traditional REST API via gRPC-Gateway plugin to gRPC. After set of code interactions, it is far away from a perfect state and has some rudiments that are no longer functional. In addition, protobuf schema now is the only source of truth for Brand entity, so it needs to really follow recommended style convention. This is a plan for current chapter.

Protobuf style guide is relatively concise (same is true for Golang) which makes it not too difficult to study and follow it to make it simple for other developers to understand what-is-what in my small project (My apologizes for not doing it from the beginning). Please read through style guide as I am mostly will show final result of my protobuf schema. I also find useful another style guide as it has more details and explanations of why certain suggestion is better.

There is one paragraph in style guide which made me think for a while before the decision was taken. It is about service’s messages input and output parameters. Probably, it is not always applicable for CRUD gRPC services, since most frequently service’s operation either sends or receives, or both, the CRUD entity. So, creating each time individual request-response messages might be an overkilling.

Starting protobuf schema is here. And the result is below:

#2..#3: shorter and better name for package.

#12..#16: entity itself. It is now called simply Brand (before was ProtoBrand). Entity attributes are now in lower_snake_case.

#19..#21: message used to persist entities from Repository to file system. Brand message is no longer nested inside current message, because it is used extensively in following messages.

#24..#47: request-response messages for each of CRUD operation. The decision for to compose Brand message inside it, even if the message has only Brand. The exception were made for int64 Id as parameter or empty parameter.

#49: start CrudService service definition (before was Crud).

#50..#75: not a lot of changes in CRUD operation definitions, except specifying corresponding request-response parameters which were defined above.

Comand to generate Go wrappers with protoc has not changed:

Pay attention the output folder now is protoc/crud_brand as protobuf package name changed accordingly. This folder is needed to be imported into other Go files.

Another refactoring is rather simplification. From the very beginning (see chapter CRUD in REST API in a generic way), I have used in repository and REST API the distinctive Go struct to represent Brand entity:

entities/brand.go

At current stage, everything is protobuf centric, and protobuf’s Brand is, de facto, used in Data storage lavel as well on gRPC level. Thus, there is no sense to keep separate entity to serve Brand repository struct. Especially, due to multiple remapping between two entities.
So, the decision is to remove entities/brand.go file at all, and use only Brand which is defined in protobuf schema (to be precise, it Go generated version). This will result in quite massive changes in repos/brand-repo.go, luckily it is straightforward… just use crud_brand.Brand everywhere instead of entities.Brand. Final version of source file is on github.

These two housekeeping modifications are further simplify current project. After set of try-and-fix attempt, there should be possible to run gRPC and REST-API (via gRPC-Gateway) servers:

Running the project

And both protocols testing are pass.

gRPC GetList return 4 Brands
REST API GetOne with Id 2
REST API Delete with Id 1
Requery gRPC GetList to see that Brand with Id 1 is no longer returned

Following protobuf style guide is not difficult and saves time for other developers to understand the project details quicker. Long run maintenance efforts are also lower. It is better to do this task at the beginning at the time when protobuf schema is introduced.

--

--