--- layout: default --- # Native gRPC Compatibility This guide explains how to make your Go Micro services compatible with native gRPC clients like `grpcurl`, `grpcui`, or clients generated by the standard `protoc` gRPC plugin in any language. ## Understanding Transport vs Server Go Micro has two different gRPC-related concepts that are often confused: ### gRPC Transport (`go-micro.dev/v6/transport/grpc`) The gRPC **transport** uses the gRPC protocol as a communication layer, similar to how you might use NATS, RabbitMQ, or HTTP. It does **not** guarantee compatibility with native gRPC clients. ```go // This uses gRPC as transport but is NOT compatible with native gRPC clients import "go-micro.dev/v6/transport/grpc" t := grpc.NewTransport() service := micro.NewService("helloworld", micro.Transport(t), ) ``` When using the gRPC transport: - Communication between Go Micro services works fine - Native gRPC clients (grpcurl, etc.) will fail with "Unimplemented" errors - The protocol is used like a message bus, not as a standard gRPC server ### gRPC Server/Client (`go-micro.dev/v6/server/grpc` and `go-micro.dev/v6/client/grpc`) The gRPC **server** and **client** provide native gRPC compatibility. These implement a proper gRPC server that any gRPC client can communicate with. ```go // This IS compatible with native gRPC clients import ( "go-micro.dev/v6" grpcServer "go-micro.dev/v6/server/grpc" grpcClient "go-micro.dev/v6/client/grpc" ) service := micro.NewService("helloworld", micro.Server(grpcServer.NewServer()), micro.Client(grpcClient.NewClient()), ) ``` ## When to Use Which | Use Case | Solution | |----------|----------| | Need native gRPC client compatibility | Use gRPC server/client | | Need to call service with `grpcurl` | Use gRPC server | | Need polyglot gRPC clients (Python, Java, etc.) | Use gRPC server | | Only Go Micro services communicating | Either works | | Want gRPC as a message protocol (like NATS) | Use gRPC transport | ## Complete Example: Native gRPC Compatible Service ### Proto Definition ```protobuf syntax = "proto3"; package helloworld; option go_package = "./proto;helloworld"; service Say { rpc Hello(Request) returns (Response) {} } message Request { string name = 1; } message Response { string message = 1; } ``` ### Generate Code ```bash # Install protoc-gen-micro go install go-micro.dev/v6/cmd/protoc-gen-micro@latest # Generate Go code protoc --proto_path=. \ --go_out=. --go_opt=paths=source_relative \ --micro_out=. --micro_opt=paths=source_relative \ proto/helloworld.proto ``` ### Server Implementation ```go package main import ( "context" "log" "go-micro.dev/v6" grpcServer "go-micro.dev/v6/server/grpc" pb "example.com/helloworld/proto" ) type Say struct{} func (s *Say) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { rsp.Message = "Hello " + req.Name return nil } func main() { // Create service with gRPC server for native gRPC compatibility // Note: Server must be set before Name to ensure the name is applied to the gRPC server service := micro.NewService("helloworld", micro.Server(grpcServer.NewServer()), micro.Address(":8080"), ) service.Init() // Register handler pb.RegisterSayHandler(service.Server(), &Say{}) // Run service if err := service.Run(); err != nil { log.Fatal(err) } } ``` ### Client Implementation (Go Micro) ```go package main import ( "context" "fmt" "log" "go-micro.dev/v6" grpcClient "go-micro.dev/v6/client/grpc" pb "example.com/helloworld/proto" ) func main() { // Create service with gRPC client service := micro.NewService("helloworld.client", micro.Client(grpcClient.NewClient()), ) service.Init() // Create client - use the service name "helloworld" (not the proto package name) // Go Micro uses this name for registry lookup, which may differ from the package name sayService := pb.NewSayService("helloworld", service.Client()) // Call service rsp, err := sayService.Hello(context.Background(), &pb.Request{Name: "Alice"}) if err != nil { log.Fatal(err) } fmt.Println(rsp.Message) // Output: Hello Alice } ``` ### Testing with grpcurl Once your service is running with the gRPC server, you can use `grpcurl`: ```bash # List available services grpcurl -plaintext localhost:8080 list # Call the Hello method grpcurl -proto ./proto/helloworld.proto \ -plaintext \ -d '{"name":"Alice"}' \ localhost:8080 helloworld.Say.Hello ``` ## Using Both gRPC Server and Client Together For full native gRPC compatibility (both inbound and outbound), use both: ```go package main import ( "go-micro.dev/v6" grpcClient "go-micro.dev/v6/client/grpc" grpcServer "go-micro.dev/v6/server/grpc" ) func main() { service := micro.NewService("helloworld", micro.Server(grpcServer.NewServer()), micro.Client(grpcClient.NewClient()), micro.Address(":8080"), ) service.Init() // ... register handlers service.Run() } ``` ## Common Errors ### "unknown service" Error with grpcurl If you see this error: ``` ERROR: Code: Unimplemented Message: unknown service helloworld.Say ``` **Cause**: You're using the gRPC transport instead of the gRPC server. **Solution**: Change from: ```go // Wrong - uses transport t := grpc.NewTransport() service := micro.NewService("helloworld", micro.Transport(t), ) ``` To: ```go // Correct - uses server import grpcServer "go-micro.dev/v6/server/grpc" service := micro.NewService("helloworld", micro.Server(grpcServer.NewServer()), ) ``` ### Import Path Confusion Note the different import paths: ```go // Transport (NOT native gRPC compatible) import "go-micro.dev/v6/transport/grpc" // Server (native gRPC compatible) import "go-micro.dev/v6/server/grpc" // Client (native gRPC compatible) import "go-micro.dev/v6/client/grpc" ``` ### Service Name vs Package Name When creating a client to call another service, use the **service name** passed to `micro.NewService`, not the proto package name: ```go // If the server was started with micro.NewService("helloworld", ...) sayService := pb.NewSayService("helloworld", service.Client()) // Use service name // NOT the package name from the proto file // sayService := pb.NewSayService("helloworld.Say", service.Client()) // Wrong! ``` Go Micro uses the service name for registry lookup, which may differ from the proto package name. ## Environment Variable Configuration You can also configure the server and client via environment variables: ```bash # Use gRPC server MICRO_SERVER=grpc go run main.go # Use gRPC client MICRO_CLIENT=grpc go run main.go ``` ## Summary | Component | Import Path | Native gRPC Compatible | |-----------|-------------|----------------------| | Transport | `go-micro.dev/v6/transport/grpc` | ❌ No | | Server | `go-micro.dev/v6/server/grpc` | ✅ Yes | | Client | `go-micro.dev/v6/client/grpc` | ✅ Yes | For native gRPC compatibility with tools like `grpcurl` or polyglot clients, always use the gRPC **server** and **client** packages, not the transport. ## Related Documentation - [Transport](../transport.md) - Understanding transports in Go Micro - [Plugins](../plugins.md) - Available plugins including gRPC - [Migration from gRPC](migration/from-grpc.md) - Migrating existing gRPC services