Skip to main content

15 Use remote packages

In this section, you'll learn how to use Buf's Go Module Proxy to import the Go/gRPC client and server stubs as you would import any other Go library. Remote packages thus reduces the code generation workflow to two steps:

  1. buf push
  2. go get (or go mod tidy)

15.1 Remove buf.gen.yaml#

You won't need to generate any code locally at this stage, so you can remove the buf.gen.yaml as well as the generated code in the gen directory:

rm buf.gen.yamlrm -rf gen

As expected, if you try to recompile your Go program, you'll notice a compilation error:

$ go build ./...
Output
client/main.go:10:2: no required module provides package github.com/bufbuild/buf-tour/petstore/gen/proto/go/pet/v1; to add it: go get github.com/bufbuild/buf-tour/petstore/gen/proto/go/pet/v1

15.2 Depend on buf.build/gen/go#

You can depend on the same Go/gRPC client and server stubs by adapting our import paths to use the BSR Go module proxy.

The Go module path you need to use is derived from the name of the module you want to generate for and the name of the plugin you want to generate with:

With the module buf.build/$BUF_USER/petapis and plugin buf.build/grpc/go, for example, the import path looks like this:

buf.build/gen/go/$BUF_USER/petapis/grpc/go

Update your import paths accordingly:

client/main.go
 package main import (     "context"     "fmt"     "log"-    // This import path is based on the name declaration in the go.mod,-    // and the gen/proto/go output location in the buf.gen.yaml.-    petv1 "github.com/bufbuild/buf-tour/petstore/gen/proto/go/pet/v1"+    petv1 "buf.build/gen/go/$BUF_USER/petapis/protocolbuffers/go/pet/v1"+    "buf.build/gen/go/$BUF_USER/petapis/grpc/go/pet/v1/petv1grpc"     "google.golang.org/grpc" )
server/main.go
 package main import (     "context"     "fmt"     "log"     "net"-    // This import path is based on the name declaration in the go.mod,-    // and the gen/proto/go output location in the buf.gen.yaml.-    petv1 "github.com/bufbuild/buf-tour/petstore/gen/proto/go/pet/v1"+    petv1 "buf.build/gen/go/$BUF_USER/petapis/protocolbuffers/go/pet/v1"+    "buf.build/gen/go/$BUF_USER/petapis/grpc/go/pet/v1/petv1grpc"     "google.golang.org/grpc" )

Note, the gRPC generated code is output to a different package, so you'll need to modify the import and references to petv1grpc for the server/client stubs. The base types will remain importable from petv1.

Now if you run the command below, you'll notice that the remote package is successfully resolved:

$ go mod tidy
Output
go: finding module for package buf.build/gen/go/$BUF_USER/petapis/protocolbuffers/go/pet/v1go: finding module for package buf.build/gen/go/$BUF_USER/petapis/grpc/go/pet/v1/petv1grpcgo: found buf.build/gen/go/$BUF_USER/petapis/grpc/go/pet/v1/petv1grpc in buf.build/gen/go/$BUF_USER/petapis/grpc/go v1.2.0-20220907172654-7abdb7802c8f.4go: found buf.build/gen/go/$BUF_USER/petapis/protocolbuffers/go/pet/v1 in buf.build/gen/go/$BUF_USER/petapis/protocolbuffers/go v1.28.1-20220907172654-7abdb7802c8f.4

The Go/gRPC client and server stubs are now included in your go.mod just like any other Go library.

15.3 Run the application#

You can run the application again to verify that the remote package works as expected.

First, start the server:

$ go run server/main.go
Output
... Listening on 127.0.0.1:8080

In a separate terminal, run the client and you'll see a successful PutPet operation:

$ go run client/main.go
Output
... Connected to 127.0.0.1:8080... Successfully PutPet

You'll also notice this in the server logs (in the other terminal running the server):

$ go run server/main.go
Output
... Listening on 127.0.0.1:8080... Got a request to create a PET_TYPE_SNAKE named Ekans

Everything works just as before, but you no longer have any locally generated code:

start/├── buf.work.yaml├── client│   └── main.go├── go.mod├── go.sum├── paymentapis│   ├── buf.lock│   ├── buf.yaml│   └── payment│       └── v1alpha1│           └── payment.proto├── petapis│   ├── buf.lock│   ├── buf.md│   ├── buf.yaml│   └── pet│       └── v1│           └── pet.proto└── server    └── main.go

15.4 Updating Versions#

When you update your module and push new commits, you can update your library version by incrementing the final element in the synthetic version (described above).

To demonstrate, make a small change by adding a comment to the PetStoreService:

$ cd petapis
petapis/pet/v1/pet.proto
+// PetStoreService defines a pet store service. service PetStoreService {   rpc GetPet(GetPetRequest) returns (GetPetResponse) {}   rpc PutPet(PutPetRequest) returns (PutPetResponse) {}   rpc DeletePet(DeletePetRequest) returns (DeletePetResponse) {}   rpc PurchasePet(PurchasePetRequest) returns (PurchasePetResponse) {} }

Push those changes:

$ buf push
Output
4e6df5753af74d6e988ba07d746cde04

Now edit your go.mod to use the latest version:

go.mod
 module github.com/bufbuild/buf-tour/petstore go 1.16 require (-   buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20210812172254-4514ddced058.4-   buf.build/gen/go/acme/petapis/protocolbuffers/go v1.28.1-20210812172254-4514ddced058.4+   buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20221114162513-4e6df5753af7.4+   buf.build/gen/go/acme/petapis/protocolbuffers/go v1.28.1-20221114162513-4e6df5753af7.4     google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216 // indirect     google.golang.org/grpc v1.40.0 )

If you run the command below, you'll notice that your go.sum is updated with the version specified in your go.mod, using grpc/go as an example:

$ go mod tidy
go.sum
- buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20210812172254-4514ddced058.4 h1:QREnaHDWmv55R7nL3buUIRfHH9dSkmPXTenFz1LUUZ4=- buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20210812172254-4514ddced058.4/go.mod h1:txlj4LYzQXieGG4fYs7419d7Mbh6Vp/32ZRkfZwaUMc=+ buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20221114162513-4e6df5753af7.4 h1:lCa/8gUpxGfzYpd9gdkriJUd8YospXHonFySS9LkCzI=+ buf.build/gen/go/acme/petapis/grpc/go v1.2.0-20221114162513-4e6df5753af7.4/go.mod h1:RNC72B+4E2y6/h5H+SDM4J1VOdSiOPBzqCyr7kOdhvw=