mornindew
mornindew

Reputation: 2221

GRPC Message Structures

I am in the process of migrating a legacy application (bit of microservices and monolith) into using GRPC. The entire code base is currently in GO.

I have started to model my messages and they are looking very similar to my structs that I am using in my application code. It seems odd that I have the same objects defined twice but also seems odd to use message objects as core structs. Seems that I will have a lot of memory intensive marshaling of data though. Below is an example of a message and a struct and how similar they are.

Are there any recommendations/best practices on deciding how to model my messages? Should they be aligned with my core structs? Should I not care about all the marshalling that has to happen from my Golang Structs into messages?

Forgive me if I am asking such a basic question as I am very new to protocol buffers and GRPC.

Message Proto Def:

message Profile {
    string UID = 1;
    string ContactEmail = 2;
    google.protobuf.Timestamp DateOfBirth = 3;
    float WeightInKilos = 4;
    string Gender = 5;
    string Unit = 6;
    string CurrentStatus = 7;
    string Country = 8;
    string ExperienceType = 9;
    google.protobuf.Timestamp DateJoined = 10;
    repeated Ability Abilities = 11;
    repeated Role Roles = 12;
    repeated TermsAndConditionsAcceptance TermsAndConditionsAcceptances = 13;
    string TimeZone = 14;
    repeated BaselineTestResults BaselineTests =15;
    //Excluded UpdatedDate as other domains shouldn't need it
    string FirstName =16;
    string LastName =17;
    string DisplayName = 18;
    string State = 19;
    repeated google.protobuf.Any Preferences = 20;
    Thresholds Thresholds = 21;
    string StripeCustomerID = 22;
}

Struct Def:

type Profile struct {
    UID                           string                         `json:"UID" firestore:"UID"`
    ContactEmail                  string                         `json:"ContactEmail,omitempty" firestore:"ContactEmail"`
    DateOfBirth                   time.Time                      `json:"DateOfBirth,omitempty" firestore:"DateOfBirth"`
    WeightInKilos                 float64                        `json:"WeightInKilos,omitempty" firestore:"WeightInKilos"`
    Gender                        string                         `json:"Gender,omitempty" firestore:"Gender"`
    Unit                          string                         `json:"Unit,omitempty" firestore:"Unit"`
    CurrentStatus                 string                         `json:"CurrentStatus,omitempty" firestore:"CurrentStatus"`
    Country                       string                         `json:"Country,omitempty" firestore:"Country"`
    ExperienceType                string                         `json:"ExperienceType,omitempty" firestore:"ExperienceType"`
    DateJoined                    time.Time                      `json:"DateJoined,omitempty" firestore:"DateJoined"`
    Abilities                     []Ability                      `json:"Abilities,omitempty" firestore:"Abilities"`
    Goals                         Goals                          `json:"Goals,omitempty" firestore:"Goals"`
    Roles                         []Role                         `json:"Roles,omitempty" firestore:"Roles"`
    TermsAndConditionsAcceptances []TermsAndConditionsAcceptance `json:"TermsAndConditionsAcceptances,omitempty" firestore:"TermsAndConditionsAcceptances"`
    TimeZone                      string                         `json:"TimeZone,omitempty" firestore:"TimeZone"`
    BaselineTests                 []BaselineTestResults          `json:"BaselineTests,omitempty" firestore:"BaselineTests"`
    UpdatedDate                   time.Time                      `json:"UpdatedDate,omitempty" firestore:"UpdatedDate"`
    FirstName                     *string                        `json:"FirstName,omitempty" firestore:"FirstName"`
    LastName                      string                         `json:"LastName,omitempty" firestore:"LastName"`
    DisplayName                   string                         `json:"DisplayName,omitempty" firestore:"DisplayName"`
    State                         string                         `json:"State"`
    Preferences                   map[string]interface{}         `json:"Preferences"`
    Thresholds                    Thresholds                     `json:"Thresholds"`
    StripeCustomerID              string                         `json:"-"` //Tells it to ignore exporting
}

Upvotes: 7

Views: 2790

Answers (2)

Jaskirat Singh
Jaskirat Singh

Reputation: 99

you don't need to create structs in app code. just use messages of proto file. Here is a quick start for GRPC in Go.

https://grpc.io/docs/quickstart/go/

Upvotes: -1

Avinash Dhinwa
Avinash Dhinwa

Reputation: 390

Though a very basic question but a very good question too. People generally skip it and have to struggle with codebase later as it grows.

Of course using message as core structs will be helpful in cases where the data you need to process the request is completely available in message. But in cases where you need to fetch data from other sources will not be helpful.

Normally a message data is dealt by boundary-layer/controller which further uses multiple services to create a response. So a service-layer/logic-layer is independent of a controller layer and the same should happen with message structs and core structs.

Always try to reduce coupling between layers so that they become reusable.

So if you have a layer which deals with database, you should have separate structs for that too.

Upvotes: 2

Related Questions