gRPC
Mortar is mostly about gRPC (and REST) web services. We will explain how you should register multiple gRPC/REST APIs. To make it easier, we will use mortar-demo in our example.
Protobuf
Before you implement any gRPC service related code, you first need to define the API by writing proto files.
Once that’s done, you will call protoc
and generate your <name>_grpc.pb.go
, <name>.pb.go
and <name>.pb.gw.go
files.
We will be using the Workshop API example.
service Workshop {
rpc AcceptCar(Car) returns (google.protobuf.Empty);
rpc PaintCar(PaintCarRequest) returns (google.protobuf.Empty);
rpc RetrieveCar(RetrieveCarRequest) returns (Car);
rpc CarPainted(PaintFinishedRequest) returns (google.protobuf.Empty);
}
Implementing
Once we have our gRPC server interfaces generated, we need to implement them. In our case, we need to implement this generated interface.
// WorkshopServer is the server API for Workshop service.
// All implementations must embed UnimplementedWorkshopServer
// for forward compatibility
type WorkshopServer interface {
AcceptCar(context.Context, *Car) (*empty.Empty, error)
PaintCar(context.Context, *PaintCarRequest) (*empty.Empty, error)
RetrieveCar(context.Context, *RetrieveCarRequest) (*Car, error)
CarPainted(context.Context, *PaintFinishedRequest) (*empty.Empty, error)
mustEmbedUnimplementedWorkshopServer()
}
You can see how it’s done in app/services/workshop.go. Here is one of the methods:
...
func (w *workshopImpl) AcceptCar(ctx context.Context, car *workshop.Car) (*empty.Empty, error) {
if err := w.deps.Validations.AcceptCar(ctx, car); err != nil {
return nil, err
}
w.deps.Logger.WithField("car", car).Debug(ctx, "accepting car")
return w.deps.Controller.AcceptCar(ctx, car)
}
...
Registering
Once we have the implementation covered, we need to register it. There are several steps you need to cover:
-
Create a function that will return GRPCServerAPI.
In this function you must register the gRPC API implementation on the provided
grpc.Server
func workshopGRPCServiceAPIs(deps workshopServiceDeps) serverInt.GRPCServerAPI { return func(srv *grpc.Server) { workshop.RegisterWorkshopServer(srv, deps.Workshop) // Any additional gRPC Implementations should be called here } }
You can look here to understand how it’s done in our workshop example.
-
Next, add it to the
groups.GRPCServerAPIs
group as shown here:To better understand Mortar groups read here
return fx.Options( // GRPC Service APIs registration fx.Provide(fx.Annotated{ Group: groups.GRPCServerAPIs, Target: workshopGRPCServiceAPIs, }), ...
This way you can register multiple gRPC API implementations, and they will all be registered in one place.
-
Now we need to add this option to the
Uber-FX
graph, as shown here:return fx.New( ... mortar.WorkshopAPIsAndOtherDependenciesFxOption(), ... )