Repository: googleapis/gapic-generator-go
Pull request #1220 (2023-01-27 20:44:15)

feat(gengapic): add snippets
The snippet output added in this change is known to differ from legacy snippetgen output as follows:

1. In new snippet metadata, `resultType` pointer values contain the `*` prefix. (In current metadata, the `*` does not appear.)
2. In new snippet file license headers, `https` replaces current headers' usage of `http`.
3. In new snippet file "generated by" header comments, the source is changed to the `protoc` plugin.
4. In new snippet file imports, a blank line that currently appears before `iam` imports is now removed. Note that this decreases the `segments.end` value by `1` in the new snippet metadata.
   ```diff
           datacatalog "cloud.google.com/go/datacatalog/apiv1beta1"
   -
           iampb "google.golang.org/genproto/googleapis/iam/v1"
   ```
5. In new snippet metadata, `clientMethod.method` values are changed to the actual protobuf source values for mixin methods:
   ```diff
            "method": {
              "shortName": "GetLocation",
   -          "fullName": "google.cloud.kms.v1.EkmService.GetLocation",
   +          "fullName": "google.cloud.location.Locations.GetLocation",
              "service": {
   -            "shortName": "EkmService",
   -            "fullName": "google.cloud.kms.v1.EkmService"
   +            "shortName": "Locations",
   +            "fullName": "google.cloud.location.Locations"
              }
   ```


snippet-bot[bot]: <!-- probot comment [11299897]-->
Here is the summary of possible violations 😱<details>
  <summary>There is a possible violation for not having product prefix.</summary>

  - [internal/gengapic/example.go:47](https://github.com/quartzmo/gapic-generator-go/blob/e0a9c288af8a32081127e1445080f1ec36ae3c85/internal/gengapic/example.go#L47), tag `%s`

</details>

<details>
  <summary>There is a format violation for a region tag.</summary>

  - [internal/gengapic/example.go:47](https://github.com/quartzmo/gapic-generator-go/blob/e0a9c288af8a32081127e1445080f1ec36ae3c85/internal/gengapic/example.go#L47), tag `%s`

</details>

**The end of the violation section. All the stuff below is FYI purposes only.**

---
Here is the summary of changes.
<details>
  <summary>You are about to add 2 region tags.</summary>

  - [internal/gengapic/example.go:47](https://github.com/quartzmo/gapic-generator-go/blob/e0a9c288af8a32081127e1445080f1ec36ae3c85/internal/gengapic/example.go#L47), tag `%s`
- [internal/gengapic/testdata/snippet.want:17](https://github.com/quartzmo/gapic-generator-go/blob/e0a9c288af8a32081127e1445080f1ec36ae3c85/internal/gengapic/testdata/snippet.want#L17), tag `bigquerymigration_v2_generated_MigrationService_CreateMigrationWorkflow_sync`

</details>

---
This comment is generated by [snippet-bot](https://github.com/apps/snippet-bot).
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
To update this comment, add `snippet-bot:force-run` label or use the checkbox below:
- [ ] Refresh this comment

noahdietz: Can you add a new config file for SnippetBot to stop it from bothering us about region tags in generator code? Add the following to `.github/snippet-bot.yml`:
```yaml
# The generator prints region tags and snippet-bot wants to correct
# the printing code.
ignoreFiles:
  - "internal/**"
```
quartzmo: @noahdietz I don't know why the snippet-bot checks are still failing after I added the `ignoreFiles` directive, which LGTM.
noahdietz: > @noahdietz I don't know why the snippet-bot checks are still failing after I added the `ignoreFiles` directive, which LGTM.

It might need to be checked into the repo to actually work. In which case, you could either put it in another PR to merge sooner, or just wait until this merges and ignore the Action for now :) Either way, I'm fine.
quartzmo: @noahdietz I also see those diffs in the file view for this PR in GH. But I do not see them locally. The following returns no differences:

```sh
git diff main -- .github/workflows/ci.yaml
```

I guess maybe GH might be confused by so many commits?

Patch:
diff --git a/.github/snippet-bot.yml b/.github/snippet-bot.yml
index 1488c14..2fad6a5 100644
--- a/.github/snippet-bot.yml
+++ b/.github/snippet-bot.yml
@@ -1,2 +1,7 @@
 aggregateChecks: false
 alwaysCreateStatusCheck: false
+
+# The generator prints region tags and snippet-bot wants to correct
+# the printing code.
+ignoreFiles:
+  - "internal/**"
diff --git a/README.md b/README.md
index 4b144dc..044c864 100644
--- a/README.md
+++ b/README.md
@@ -101,6 +101,8 @@ The configuration supported by the plugin option includes:
     * Not enabled by default.
     * Only effective when `rest` is included as a `transport` to be generated.
 
+  * `omit-snippets`: disable generation of code snippets to the `internal/generated/snippets` path. The default is `false`.
+
 Bazel
 -----
 
@@ -165,6 +167,8 @@ following attributes:
     * Default is `False`.
     * Only effective when `rest` is included as a `transport` to be generated.
 
+  * `omit_snippets`: if `True`, code snippets will be generated to the `internal/generated/snippets` path. The default is `false`.
+
 Docker Wrapper
 --------------
 The generator can also be executed via a Docker container. The image containes `protoc`, the microgenerator
diff --git a/internal/gengapic/BUILD.bazel b/internal/gengapic/BUILD.bazel
index e0ec6de..17abbfd 100644
--- a/internal/gengapic/BUILD.bazel
+++ b/internal/gengapic/BUILD.bazel
@@ -19,6 +19,7 @@ go_library(
         "mixins.go",
         "options.go",
         "paging.go",
+        "snippets.go",
         "stream.go",
         "test_utils.go",
     ],
@@ -30,6 +31,7 @@ go_library(
         "//internal/license",
         "//internal/pbinfo",
         "//internal/printer",
+        "//internal/snippets",
         "@com_github_ghodss_yaml//:yaml",
         "@com_gitlab_golang_commonmark_markdown//:markdown",
         "@com_google_cloud_go_iam//apiv1/iampb",
@@ -46,6 +48,7 @@ go_library(
         "@org_golang_google_protobuf//proto",
         "@org_golang_google_protobuf//reflect/protodesc",
         "@org_golang_google_protobuf//runtime/protoiface",
+        "@org_golang_google_protobuf//types/descriptorpb",
     ],
 )
 
@@ -70,6 +73,7 @@ go_test(
     deps = [
         "//internal/grpc_service_config",
         "//internal/pbinfo",
+        "//internal/snippets",
         "//internal/txtdiff",
         "@com_github_google_go_cmp//cmp",
         "@com_google_cloud_go_longrunning//autogen/longrunningpb",
@@ -78,6 +82,7 @@ go_test(
         "@go_googleapis//google/api:httpbody_go_proto",
         "@go_googleapis//google/api:serviceconfig_go_proto",
         "@go_googleapis//google/cloud:extended_operations_go_proto",
+        "@go_googleapis//google/longrunning:longrunning_go_proto",
         "@go_googleapis//google/rpc:code_go_proto",
         "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto",
         "@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
diff --git a/internal/gengapic/client_init.go b/internal/gengapic/client_init.go
index 4e13d36..ceb936e 100644
--- a/internal/gengapic/client_init.go
+++ b/internal/gengapic/client_init.go
@@ -242,21 +242,25 @@ func (g *generator) genClientWrapperMethod(m *descriptor.MethodDescriptorProto,
 	}
 
 	// Generate method documentation just before any method is generated.
-	g.methodDoc(m)
+	g.methodDoc(m, serv)
 
 	if m.GetOutputType() == emptyType {
-		p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) error {",
-			clientTypeName, m.GetName(), inSpec.Name, inType.GetName())
+		reqTyp := fmt.Sprintf("%s.%s", inSpec.Name, inType.GetName())
+		p("func (c *%s) %s(ctx context.Context, req *%s, opts ...gax.CallOption) error {",
+			clientTypeName, m.GetName(), reqTyp)
 		p("    return c.internalClient.%s(ctx, req, opts...)", m.GetName())
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), reqTyp)
 		return nil
 	}
 
 	if g.isLRO(m) {
+		reqTyp := fmt.Sprintf("%s.%s", inSpec.Name, inType.GetName())
 		lroType := lroTypeName(m.GetName())
-		p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (*%s, error) {",
-			clientTypeName, m.GetName(), inSpec.Name, inType.GetName(), lroType)
+		p("func (c *%s) %s(ctx context.Context, req *%s, opts ...gax.CallOption) (*%s, error) {",
+			clientTypeName, m.GetName(), reqTyp, lroType)
 		p("    return c.internalClient.%s(ctx, req, opts...)", m.GetName())
 		p("}")
 		p("")
@@ -266,21 +270,28 @@ func (g *generator) genClientWrapperMethod(m *descriptor.MethodDescriptorProto,
 		p("  return c.internalClient.%s(name)", lroType)
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), reqTyp)
+		g.addSnippetsMetadataResult(m, serv.GetName(), lroType)
 		return nil
 	}
 
 	if pf, _, err := g.getPagingFields(m); err != nil {
 		return err
 	} else if pf != nil {
+		reqTyp := fmt.Sprintf("%s.%s", inSpec.Name, inType.GetName())
 		iter, err := g.iterTypeOf(pf)
 		if err != nil {
 			return err
 		}
-		p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) *%s {",
-			clientTypeName, m.GetName(), inSpec.Name, inType.GetName(), iter.iterTypeName)
+		p("func (c *%s) %s(ctx context.Context, req *%s, opts ...gax.CallOption) *%s {",
+			clientTypeName, m.GetName(), reqTyp, iter.iterTypeName)
 		p("    return c.internalClient.%s(ctx, req, opts...)", m.GetName())
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), reqTyp)
+		g.addSnippetsMetadataResult(m, serv.GetName(), iter.iterTypeName)
 		return nil
 	}
 
@@ -291,34 +302,48 @@ func (g *generator) genClientWrapperMethod(m *descriptor.MethodDescriptorProto,
 			return err
 		}
 
-		p("func (c *%s) %s(ctx context.Context, opts ...gax.CallOption) (%s.%s_%sClient, error) {",
-			clientTypeName, m.GetName(), servSpec.Name, serv.GetName(), m.GetName())
+		retTyp := fmt.Sprintf("%s.%s_%sClient", servSpec.Name, serv.GetName(), m.GetName())
+		p("func (c *%s) %s(ctx context.Context, opts ...gax.CallOption) (%s, error) {",
+			clientTypeName, m.GetName(), retTyp)
 		p("    return c.internalClient.%s(ctx, opts...)", m.GetName())
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), "")
+		g.addSnippetsMetadataResult(m, serv.GetName(), retTyp)
 		return nil
 	case m.GetServerStreaming():
 		servSpec, err := g.descInfo.ImportSpec(serv)
 		if err != nil {
 			return err
 		}
-		p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (%s.%s_%sClient, error) {",
-			clientTypeName, m.GetName(), inSpec.Name, inType.GetName(), servSpec.Name, serv.GetName(), m.GetName())
+
+		reqTyp := fmt.Sprintf("%s.%s", inSpec.Name, inType.GetName())
+		retTyp := fmt.Sprintf("%s.%s_%sClient", servSpec.Name, serv.GetName(), m.GetName())
+		p("func (c *%s) %s(ctx context.Context, req *%s, opts ...gax.CallOption) (%s, error) {",
+			clientTypeName, m.GetName(), reqTyp, retTyp)
 		p("    return c.internalClient.%s(ctx, req, opts...)", m.GetName())
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), reqTyp)
+		g.addSnippetsMetadataResult(m, serv.GetName(), retTyp)
 		return nil
 	default:
+		reqTyp := fmt.Sprintf("%s.%s", inSpec.Name, inType.GetName())
 		retTyp, err := g.returnType(m)
 		if err != nil {
 			return err
 		}
 
-		p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (%s, error) {",
-			clientTypeName, m.GetName(), inSpec.Name, inType.GetName(), retTyp)
+		p("func (c *%s) %s(ctx context.Context, req *%s, opts ...gax.CallOption) (%s, error) {",
+			clientTypeName, m.GetName(), reqTyp, retTyp)
 		p("    return c.internalClient.%s(ctx, req, opts...)", m.GetName())
 		p("}")
 		p("")
+
+		g.addSnippetsMetadataParams(m, serv.GetName(), reqTyp)
+		g.addSnippetsMetadataResult(m, serv.GetName(), retTyp)
 		return nil
 	}
 
diff --git a/internal/gengapic/example.go b/internal/gengapic/example.go
index b37bf78..f04cf42 100644
--- a/internal/gengapic/example.go
+++ b/internal/gengapic/example.go
@@ -74,6 +74,8 @@ func (g *generator) exampleInitClient(pkgName, servName string) {
 	p("  // TODO: Handle error.")
 	p("}")
 	p("defer c.Close()")
+
+	g.imports[pbinfo.ImportSpec{Path: "context"}] = true
 }
 
 func (g *generator) exampleMethod(pkgName, servName string, m *descriptor.MethodDescriptorProto) error {
diff --git a/internal/gengapic/generator.go b/internal/gengapic/generator.go
index a3548ba..b3b6fdb 100644
--- a/internal/gengapic/generator.go
+++ b/internal/gengapic/generator.go
@@ -29,6 +29,7 @@ import (
 	"github.com/googleapis/gapic-generator-go/internal/license"
 	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
 	"github.com/googleapis/gapic-generator-go/internal/printer"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
 	"google.golang.org/genproto/googleapis/api/serviceconfig"
 	metadatapb "google.golang.org/genproto/googleapis/gapic/metadata"
 	"google.golang.org/protobuf/encoding/protojson"
@@ -39,6 +40,7 @@ import (
 type generator struct {
 	pt printer.P
 
+	// Protobuf descriptor properties
 	descInfo pbinfo.Info
 
 	// Maps proto elements to their comments
@@ -46,6 +48,9 @@ type generator struct {
 
 	resp plugin.CodeGeneratorResponse
 
+	// Comments to appear after the license header and before the package declaration.
+	headerComments printer.P
+
 	imports map[pbinfo.ImportSpec]bool
 
 	// Human-readable name of the API used in docs
@@ -68,6 +73,9 @@ type generator struct {
 	// gapic_metadata.json file.
 	metadata *metadatapb.GapicMetadata
 
+	// Model for capturing snippet details in a snippet_metadata.*.json file.
+	snippetMetadata *snippets.SnippetMetadata
+
 	mixins mixins
 
 	hasIAMPolicyOverrides bool
@@ -185,9 +193,14 @@ func (g *generator) printf(s string, a ...interface{}) {
 	g.pt.Printf(s, a...)
 }
 
-func (g *generator) commit(fileName, pkgName string) {
+// TODO(chrisdsmith): Add generator_test.go with TestCommit
+
+// commit adds header, etc to current pt and returns the line length of the
+// final file output.
+func (g *generator) commit(fileName, pkgName string) int {
 	var header strings.Builder
 	fmt.Fprintf(&header, license.Apache, time.Now().Year())
+	header.WriteString(g.headerComments.String() + "\n")
 	fmt.Fprintf(&header, "package %s\n\n", pkgName)
 
 	var imps []pbinfo.ImportSpec
@@ -215,7 +228,7 @@ func (g *generator) commit(fileName, pkgName string) {
 		writeImp(imp)
 	}
 	header.WriteString(")\n\n")
-
+	lineCount := len(strings.Split(header.String(), "\n"))
 	g.resp.File = append(g.resp.File, &plugin.CodeGeneratorResponse_File{
 		Name:    &fileName,
 		Content: proto.String(header.String()),
@@ -238,10 +251,13 @@ func (g *generator) commit(fileName, pkgName string) {
 	g.resp.File = append(g.resp.File, &plugin.CodeGeneratorResponse_File{
 		Content: proto.String(body),
 	})
+
+	return lineCount + len(strings.Split(body, "\n"))
 }
 
 func (g *generator) reset() {
 	g.pt.Reset()
+	g.headerComments.Reset()
 	for k := range g.imports {
 		delete(g.imports, k)
 	}
diff --git a/internal/gengapic/gengapic.go b/internal/gengapic/gengapic.go
index f53f87a..7b10b45 100644
--- a/internal/gengapic/gengapic.go
+++ b/internal/gengapic/gengapic.go
@@ -27,6 +27,7 @@ import (
 	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
 	"github.com/googleapis/gapic-generator-go/internal/errors"
 	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/printer"
 	"google.golang.org/genproto/googleapis/api/annotations"
 	"google.golang.org/protobuf/proto"
 )
@@ -94,16 +95,22 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er
 		g.metadata.ProtoPackage = protoPkg
 	}
 	g.metadata.LibraryPackage = g.opts.pkgPath
+	// Initialize the model that will collect snippet metadata.
+	g.snippetMetadata = g.newSnippetsMetadata(protoPkg)
 
 	for _, s := range genServs {
 		// TODO(pongad): gapic-generator does not remove the package name here,
 		// so even though the client for LoggingServiceV2 is just "Client"
 		// the file name is "logging_client.go".
 		// Keep the current behavior for now, but we could revisit this later.
-		outFile := pbinfo.ReduceServName(s.GetName(), "")
-		outFile = camelToSnake(outFile)
+		servName := pbinfo.ReduceServName(s.GetName(), "")
+		outFile := camelToSnake(servName)
 		outFile = filepath.Join(g.opts.outDir, outFile)
 
+		if err := g.genAndCommitSnippets(s); err != nil {
+			return &g.resp, errors.E(err, "snippets: %s", s.GetName())
+		}
+
 		g.reset()
 		// If the service has no REST-able RPCs, then a REGAPIC should not be
 		// generated for it, even if REST is an enabled transport.
@@ -130,7 +137,10 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er
 			g.opts.transports = transports
 		}
 	}
-
+	err := g.genAndCommitSnippetMetadata(protoPkg)
+	if err != nil {
+		return &g.resp, err
+	}
 	g.reset()
 	scopes, err := collectScopes(genServs)
 	if err != nil {
@@ -488,7 +498,7 @@ func containsDeprecated(com string) bool {
 	return false
 }
 
-func (g *generator) methodDoc(m *descriptor.MethodDescriptorProto) {
+func (g *generator) methodDoc(m *descriptor.MethodDescriptorProto, serv *descriptor.ServiceDescriptorProto) {
 	com := g.comments[m]
 
 	// If there's no comment and the method is not deprecated, adding method name is just confusing.
@@ -515,11 +525,13 @@ func (g *generator) methodDoc(m *descriptor.MethodDescriptorProto) {
 
 	// Prepend the method name to all non-empty comments.
 	com = m.GetName() + " " + lowerFirst(com)
-
+	g.addSnippetsMetadataDoc(m, serv.GetName(), com)
 	g.comment(com)
 }
 
-func (g *generator) comment(s string) {
+// printComment accepts a string to print in code comments and a printFunc
+// function to format-print the comment slashes plus the string.
+func (g *generator) printComment(s string, p *printer.P) {
 	s = strings.TrimSpace(s)
 	if s == "" {
 		return
@@ -530,13 +542,23 @@ func (g *generator) comment(s string) {
 	lines := strings.Split(s, "\n")
 	for _, l := range lines {
 		if strings.TrimSpace(l) == "" {
-			g.printf("//")
+			p.Printf("//")
 		} else {
-			g.printf("// %s", l)
+			p.Printf("// %s", l)
 		}
 	}
 }
 
+// comment format-prints a string in code comments to pt using printf.
+func (g *generator) comment(s string) {
+	g.printComment(s, &g.pt)
+}
+
+// comment format-prints a string in code comments to headerComments.
+func (g *generator) headerComment(s string) {
+	g.printComment(s, &g.headerComments)
+}
+
 // Similar functionality to 'comment', except specifically used for generating formatted code snippets.
 func (g *generator) codesnippet(s string) {
 	if s == "" {
diff --git a/internal/gengapic/gengrpc.go b/internal/gengapic/gengrpc.go
index d261e9c..10d80b8 100644
--- a/internal/gengapic/gengrpc.go
+++ b/internal/gengapic/gengrpc.go
@@ -99,16 +99,16 @@ func (g *generator) unaryGRPCCall(servName string, m *descriptor.MethodDescripto
 	p := g.printf
 
 	lowcaseServName := lowcaseGRPCClientName(servName)
-
-	p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (*%s.%s, error) {",
-		lowcaseServName, m.GetName(), inSpec.Name, inType.GetName(), outSpec.Name, outType.GetName())
+	retTyp := fmt.Sprintf("%s.%s", outSpec.Name, outType.GetName())
+	p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (*%s, error) {",
+		lowcaseServName, m.GetName(), inSpec.Name, inType.GetName(), retTyp)
 
 	g.deadline(sFQN, m.GetName())
 
 	g.insertRequestHeaders(m, grpc)
 	g.appendCallOpts(m)
 
-	p("var resp *%s.%s", outSpec.Name, outType.GetName())
+	p("var resp *%s", retTyp)
 	p("err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {")
 	p("  var err error")
 	p("  resp, err = %s", g.grpcStubCall(m))
diff --git a/internal/gengapic/genrest.go b/internal/gengapic/genrest.go
index 8fbb9fd..274ed9e 100644
--- a/internal/gengapic/genrest.go
+++ b/internal/gengapic/genrest.go
@@ -125,7 +125,7 @@ func (g *generator) genRESTMethods(serv *descriptor.ServiceDescriptorProto, serv
 	methods := append(serv.GetMethod(), g.getMixinMethods()...)
 
 	for _, m := range methods {
-		g.methodDoc(m)
+		g.methodDoc(m, serv)
 		if err := g.genRESTMethod(servName, serv, m); err != nil {
 			return errors.E(err, "method: %s", m.GetName())
 		}
diff --git a/internal/gengapic/options.go b/internal/gengapic/options.go
index 3a0691e..780b032 100644
--- a/internal/gengapic/options.go
+++ b/internal/gengapic/options.go
@@ -45,6 +45,7 @@ type options struct {
 	diregapic         bool
 	restNumericEnum   bool
 	pkgOverrides      map[string]string
+	omitSnippets      bool
 }
 
 // parseOptions takes a string and parses it into a struct defining
@@ -59,6 +60,7 @@ type options struct {
 // * release-level (one of 'alpha', 'beta', or empty)
 // * transport ('+' separated list of transport backends to generate)
 // * metadata (enable GAPIC metadata generation)
+// * omit-snippets (skip example code snippets generation to the `internal/generated/snippets` path)
 // The only required option is 'go-gapic-package'.
 //
 // Valid parameter example:
@@ -91,6 +93,9 @@ func parseOptions(parameter *string) (*options, error) {
 		case "rest-numeric-enums":
 			opts.restNumericEnum = true
 			continue
+		case "omit-snippets":
+			opts.omitSnippets = true
+			continue
 		}
 
 		e := strings.IndexByte(s, '=')
diff --git a/internal/gengapic/snippets.go b/internal/gengapic/snippets.go
new file mode 100644
index 0000000..280481f
--- /dev/null
+++ b/internal/gengapic/snippets.go
@@ -0,0 +1,140 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gengapic
+
+import (
+	"fmt"
+	"path/filepath"
+
+	"github.com/golang/protobuf/protoc-gen-go/descriptor"
+	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
+	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
+	"google.golang.org/genproto/googleapis/api/annotations"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/descriptorpb"
+)
+
+// newSnippetsMetadata initializes the model that will collect snippet metadata.
+// Does nothing and returns nil if opts.omitSnippets is true.
+func (g *generator) newSnippetsMetadata(protoPkg string) *snippets.SnippetMetadata {
+	if g.opts.omitSnippets {
+		return nil
+	}
+	return snippets.NewMetadata(protoPkg, g.metadata.LibraryPackage, g.opts.pkgName)
+}
+
+// addSnippetsMetadataDoc sets the documentation for a method in the snippet metadata.
+// Does nothing and returns nil if opts.omitSnippets is true, or if the streaming type is not supported in example.go.
+func (g *generator) addSnippetsMetadataDoc(m *descriptor.MethodDescriptorProto, servName, doc string) {
+	if g.opts.omitSnippets || m.GetClientStreaming() != m.GetServerStreaming() {
+		// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODO(pongad).
+		return
+	}
+	g.snippetMetadata.UpdateMethodDoc(servName, m.GetName(), doc)
+}
+
+// addSnippetsMetadataParams sets the parameters for a method in the snippet metadata.
+// Does nothing and returns nil if opts.omitSnippets is true, or if the streaming type is not supported in example.go.
+func (g *generator) addSnippetsMetadataParams(m *descriptor.MethodDescriptorProto, servName, requestType string) {
+	if g.opts.omitSnippets || m.GetClientStreaming() != m.GetServerStreaming() {
+		// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODO(pongad).
+		return
+	}
+	g.snippetMetadata.AddParams(servName, m.GetName(), requestType)
+}
+
+// addSnippetsMetadataResult sets the result type for a method in the snippet metadata.
+// Does nothing and returns nil if opts.omitSnippets is true, or if the streaming type is not supported in example.go.
+func (g *generator) addSnippetsMetadataResult(m *descriptor.MethodDescriptorProto, servName, resultType string) {
+	if g.opts.omitSnippets || m.GetClientStreaming() != m.GetServerStreaming() {
+		// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODO(pongad).
+		return
+	}
+	g.snippetMetadata.UpdateMethodResult(servName, m.GetName(), resultType)
+}
+
+// genAndCommitSnippets generates and commits a snippet file for each method in a client.
+// Does nothing and returns nil if opts.omitSnippets is true.
+func (g *generator) genAndCommitSnippets(s *descriptor.ServiceDescriptorProto) error {
+	if g.opts.omitSnippets {
+		return nil
+	}
+	defaultHost := proto.GetExtension(s.Options, annotations.E_DefaultHost).(string)
+	g.snippetMetadata.AddService(s.GetName(), defaultHost)
+	methods := append(s.GetMethod(), g.getMixinMethods()...)
+	for _, m := range methods {
+		if m.GetClientStreaming() != m.GetServerStreaming() {
+			// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODOs.
+			continue
+		}
+		// For each method, reset the generator in order to write a
+		// separate main.go snippet file.
+		g.reset()
+		if err := g.genSnippetFile(s, m); err != nil {
+			return err
+		}
+		g.imports[pbinfo.ImportSpec{Name: g.opts.pkgName, Path: g.opts.pkgPath}] = true
+		// Use the client short name in this filepath.
+		// E.g. the client for LoggingServiceV2 is just "Client".
+		clientName := pbinfo.ReduceServName(s.GetName(), g.opts.pkgName) + "Client"
+		// Get the original proto namespace for the method (different from `s` only for mixins).
+		f := g.descInfo.ParentFile[m]
+		// Get the original proto service for the method (different from `s` only for mixins).
+		methodServ := (g.descInfo.ParentElement[m]).(*descriptor.ServiceDescriptorProto)
+		lineCount := g.commit(filepath.Join(g.opts.outDir, "internal",
+			"snippets", clientName, m.GetName(), "main.go"), "main")
+		g.snippetMetadata.AddMethod(s.GetName(), m.GetName(), f.GetPackage(), methodServ.GetName(), lineCount-1)
+	}
+	return nil
+}
+
+// genSnippetFile generates a single RPC snippet by leveraging exampleMethodBody in gengapic/example.go.
+func (g *generator) genSnippetFile(s *descriptor.ServiceDescriptorProto, m *descriptorpb.MethodDescriptorProto) error {
+	regionTag := g.snippetMetadata.RegionTag(s.GetName(), m.GetName())
+	g.headerComment(fmt.Sprintf("[START %s]", regionTag))
+	pkgName := g.opts.pkgName
+	servName := pbinfo.ReduceServName(s.GetName(), pkgName)
+
+	p := g.printf
+	p("func main() {")
+	if err := g.exampleMethodBody(pkgName, servName, m); err != nil {
+		return err
+	}
+	p("}")
+	p("")
+	g.comment(fmt.Sprintf("[END %s]\n", regionTag))
+	return nil
+}
+
+// genAndCommitSnippetMetadata generates and commits the snippet metadata to the generator response.
+// Does nothing and returns nil if opts.omitSnippets is true.
+func (g *generator) genAndCommitSnippetMetadata(protoPkg string) error {
+	if g.opts.omitSnippets {
+		return nil
+	}
+	g.reset()
+	json, err := g.snippetMetadata.ToMetadataJSON()
+	if err != nil {
+		return err
+	}
+	file := filepath.Join(g.opts.outDir, "internal", "snippets",
+		fmt.Sprintf("snippet_metadata.%s.json", protoPkg))
+	g.resp.File = append(g.resp.File, &plugin.CodeGeneratorResponse_File{
+		Name:    proto.String(file),
+		Content: proto.String(string(json[:])),
+	})
+	return nil
+}
diff --git a/internal/gengapic/stream.go b/internal/gengapic/stream.go
index ccd5183..5f5be33 100644
--- a/internal/gengapic/stream.go
+++ b/internal/gengapic/stream.go
@@ -14,7 +14,11 @@
 
 package gengapic
 
-import "github.com/golang/protobuf/protoc-gen-go/descriptor"
+import (
+	"fmt"
+
+	"github.com/golang/protobuf/protoc-gen-go/descriptor"
+)
 
 // Used for both bidi and client streaming.
 func (g *generator) noRequestStreamCall(servName string, s *descriptor.ServiceDescriptorProto, m *descriptor.MethodDescriptorProto) error {
@@ -29,10 +33,11 @@ func (g *generator) noRequestStreamCall(servName string, s *descriptor.ServiceDe
 	// We DON'T want to export the transport layers.
 	lowcaseServName := lowerFirst(servName + "GRPCClient")
 
-	p("func (c *%s) %s(ctx context.Context, opts ...gax.CallOption) (%s.%s_%sClient, error) {",
-		lowcaseServName, m.GetName(), servSpec.Name, s.GetName(), m.GetName())
+	retTyp := fmt.Sprintf("%s.%s_%sClient", servSpec.Name, s.GetName(), m.GetName())
+	p("func (c *%s) %s(ctx context.Context, opts ...gax.CallOption) (%s, error) {",
+		lowcaseServName, m.GetName(), retTyp)
 	g.insertRequestHeaders(nil, grpc)
-	p("  var resp %s.%s_%sClient", servSpec.Name, s.GetName(), m.GetName())
+	p("  var resp %s", retTyp)
 
 	g.appendCallOpts(m)
 
@@ -68,13 +73,14 @@ func (g *generator) serverStreamCall(servName string, s *descriptor.ServiceDescr
 	p := g.printf
 	lowcaseServName := lowerFirst(servName + "GRPCClient")
 
-	p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (%s.%s_%sClient, error) {",
-		lowcaseServName, m.GetName(), inSpec.Name, inType.GetName(), servSpec.Name, s.GetName(), m.GetName())
+	retTyp := fmt.Sprintf("%s.%s_%sClient", servSpec.Name, s.GetName(), m.GetName())
+	p("func (c *%s) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (%s, error) {",
+		lowcaseServName, m.GetName(), inSpec.Name, inType.GetName(), retTyp)
 
 	g.insertRequestHeaders(m, grpc)
 	g.appendCallOpts(m)
 
-	p("  var resp %s.%s_%sClient", servSpec.Name, s.GetName(), m.GetName())
+	p("  var resp %s", retTyp)
 	p("err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {")
 	p("  var err error")
 	p("  resp, err = %s", g.grpcStubCall(m))
diff --git a/internal/snippets/BUILD.bazel b/internal/snippets/BUILD.bazel
new file mode 100644
index 0000000..c20c679
--- /dev/null
+++ b/internal/snippets/BUILD.bazel
@@ -0,0 +1,25 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+    name = "snippets",
+    srcs = ["snippets.go"],
+    importpath = "github.com/googleapis/gapic-generator-go/internal/snippets",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//internal/license",
+        "//internal/pbinfo",
+        "//internal/snippets/metadata",
+        "@org_golang_google_protobuf//encoding/protojson",
+    ],
+)
+
+go_test(
+    name = "snippets_test",
+    srcs = ["snippets_test.go"],
+    embed = [":snippets"],
+    deps = [
+        "@com_github_google_go_cmp//cmp",
+        "//internal/snippets/metadata",
+        "@org_golang_google_protobuf//proto",
+    ],
+)
diff --git a/internal/snippets/metadata/BUILD.bazel b/internal/snippets/metadata/BUILD.bazel
new file mode 100644
index 0000000..147982e
--- /dev/null
+++ b/internal/snippets/metadata/BUILD.bazel
@@ -0,0 +1,23 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+proto_library(
+    name = "metadata_proto",
+    srcs = ["metadata.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+go_proto_library(
+    name = "metadata_go_proto",
+    importpath = "github.com/googleapis/gapic-generator-go/internal/snippets/metadata",
+    proto = ":metadata_proto",
+    visibility = ["//:__subpackages__"],
+)
+
+go_library(
+    name = "metadata",
+    embed = [":metadata_go_proto"],
+    importpath = "github.com/googleapis/gapic-generator-go/internal/snippets/metadata",
+    visibility = ["//:__subpackages__"],
+)
diff --git a/internal/snippets/metadata/metadata.pb.go b/internal/snippets/metadata/metadata.pb.go
new file mode 100644
index 0000000..20d13e5
--- /dev/null
+++ b/internal/snippets/metadata/metadata.pb.go
@@ -0,0 +1,1434 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file temporarily lives here and is sourced from internal usage. In the future
+// this file will be in genproto. Updates to this file for the time being are
+// manual. To regen this file run `go generate ./...` in this module.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.19.4
+// source: metadata/metadata.proto
+
+package metadata
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// A programming language
+type Language int32
+
+const (
+	// The language has not been specified. Consumers should not see this value.
+	Language_LANGUAGE_UNSPECIFIED Language = 0
+	Language_C_PLUS_PLUS          Language = 1
+	Language_C_SHARP              Language = 2
+	Language_DART                 Language = 3
+	Language_ELIXIR               Language = 4
+	Language_ERLANG               Language = 5
+	Language_F_SHARP              Language = 6
+	Language_GO                   Language = 7
+	Language_JAVA                 Language = 8
+	Language_JAVASCRIPT           Language = 9
+	Language_KOTLIN               Language = 10
+	Language_PHP                  Language = 11
+	Language_PYTHON               Language = 12
+	Language_RUBY                 Language = 13
+	Language_RUST                 Language = 14
+	Language_SWIFT                Language = 15
+	Language_TYPESCRIPT           Language = 16
+	Language_VB_NET               Language = 17
+)
+
+// Enum value maps for Language.
+var (
+	Language_name = map[int32]string{
+		0:  "LANGUAGE_UNSPECIFIED",
+		1:  "C_PLUS_PLUS",
+		2:  "C_SHARP",
+		3:  "DART",
+		4:  "ELIXIR",
+		5:  "ERLANG",
+		6:  "F_SHARP",
+		7:  "GO",
+		8:  "JAVA",
+		9:  "JAVASCRIPT",
+		10: "KOTLIN",
+		11: "PHP",
+		12: "PYTHON",
+		13: "RUBY",
+		14: "RUST",
+		15: "SWIFT",
+		16: "TYPESCRIPT",
+		17: "VB_NET",
+	}
+	Language_value = map[string]int32{
+		"LANGUAGE_UNSPECIFIED": 0,
+		"C_PLUS_PLUS":          1,
+		"C_SHARP":              2,
+		"DART":                 3,
+		"ELIXIR":               4,
+		"ERLANG":               5,
+		"F_SHARP":              6,
+		"GO":                   7,
+		"JAVA":                 8,
+		"JAVASCRIPT":           9,
+		"KOTLIN":               10,
+		"PHP":                  11,
+		"PYTHON":               12,
+		"RUBY":                 13,
+		"RUST":                 14,
+		"SWIFT":                15,
+		"TYPESCRIPT":           16,
+		"VB_NET":               17,
+	}
+)
+
+func (x Language) Enum() *Language {
+	p := new(Language)
+	*p = x
+	return p
+}
+
+func (x Language) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Language) Descriptor() protoreflect.EnumDescriptor {
+	return file_metadata_metadata_proto_enumTypes[0].Descriptor()
+}
+
+func (Language) Type() protoreflect.EnumType {
+	return &file_metadata_metadata_proto_enumTypes[0]
+}
+
+func (x Language) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Language.Descriptor instead.
+func (Language) EnumDescriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+// The origin of the snippet.
+type Snippet_Origin int32
+
+const (
+	// The origin has not been specified. Consumers should not see this value.
+	Snippet_ORIGIN_UNSPECIFIED Snippet_Origin = 0
+	// The snippet is generated from the API definition only, including protos
+	// and descriptive information, i.e. the same information used to generate
+	// the client libraries themselves.
+	// No snippet configuration has been specified. This refers to SnippetGen
+	// phase 1.
+	Snippet_API_DEFINITION Snippet_Origin = 1
+	// The snippet is generated from the API definition and a specific snippet
+	// configuration. This refers to SnippetGen phase 2.
+	Snippet_CONFIG Snippet_Origin = 2
+	// The snippet is handwritten.
+	Snippet_HANDWRITTEN Snippet_Origin = 3
+)
+
+// Enum value maps for Snippet_Origin.
+var (
+	Snippet_Origin_name = map[int32]string{
+		0: "ORIGIN_UNSPECIFIED",
+		1: "API_DEFINITION",
+		2: "CONFIG",
+		3: "HANDWRITTEN",
+	}
+	Snippet_Origin_value = map[string]int32{
+		"ORIGIN_UNSPECIFIED": 0,
+		"API_DEFINITION":     1,
+		"CONFIG":             2,
+		"HANDWRITTEN":        3,
+	}
+)
+
+func (x Snippet_Origin) Enum() *Snippet_Origin {
+	p := new(Snippet_Origin)
+	*p = x
+	return p
+}
+
+func (x Snippet_Origin) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Snippet_Origin) Descriptor() protoreflect.EnumDescriptor {
+	return file_metadata_metadata_proto_enumTypes[1].Descriptor()
+}
+
+func (Snippet_Origin) Type() protoreflect.EnumType {
+	return &file_metadata_metadata_proto_enumTypes[1]
+}
+
+func (x Snippet_Origin) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Snippet_Origin.Descriptor instead.
+func (Snippet_Origin) EnumDescriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{1, 0}
+}
+
+// The type of the segment.
+// Basically describes what this segment shows.
+type Snippet_Segment_SegmentType int32
+
+const (
+	// The segment type has not been specified. Consumers should not see this
+	// value.
+	Snippet_Segment_SEGMENT_TYPE_UNSPECIFIED Snippet_Segment_SegmentType = 0
+	// The full sample including import statements.
+	// This corresponds to the sample as determined by the region tags.
+	Snippet_Segment_FULL Snippet_Segment_SegmentType = 1
+	// A shorter version of the full sample, may not include imports and some
+	// langauge specific initialization code. This is to be used in contexts
+	// in which the full aspects of the sample are made clear outside the
+	// code.
+	Snippet_Segment_SHORT Snippet_Segment_SegmentType = 2
+	// The segment contains the service client initialization code only.
+	// To be used in tutorials, codelabs, etc.
+	Snippet_Segment_CLIENT_INITIALIZATION Snippet_Segment_SegmentType = 3
+	// The segment contains the request initialization code only.
+	// To be used in tutorials, codelabs, etc.
+	Snippet_Segment_REQUEST_INITIALIZATION Snippet_Segment_SegmentType = 4
+	// The segment contains the request execution code only.
+	// To be used in tutorials, codelabs, etc.
+	Snippet_Segment_REQUEST_EXECUTION Snippet_Segment_SegmentType = 5
+	// The segment contains the response handling code only.
+	// To be used in tutorials, codelabs, etc.
+	Snippet_Segment_RESPONSE_HANDLING Snippet_Segment_SegmentType = 6
+)
+
+// Enum value maps for Snippet_Segment_SegmentType.
+var (
+	Snippet_Segment_SegmentType_name = map[int32]string{
+		0: "SEGMENT_TYPE_UNSPECIFIED",
+		1: "FULL",
+		2: "SHORT",
+		3: "CLIENT_INITIALIZATION",
+		4: "REQUEST_INITIALIZATION",
+		5: "REQUEST_EXECUTION",
+		6: "RESPONSE_HANDLING",
+	}
+	Snippet_Segment_SegmentType_value = map[string]int32{
+		"SEGMENT_TYPE_UNSPECIFIED": 0,
+		"FULL":                     1,
+		"SHORT":                    2,
+		"CLIENT_INITIALIZATION":    3,
+		"REQUEST_INITIALIZATION":   4,
+		"REQUEST_EXECUTION":        5,
+		"RESPONSE_HANDLING":        6,
+	}
+)
+
+func (x Snippet_Segment_SegmentType) Enum() *Snippet_Segment_SegmentType {
+	p := new(Snippet_Segment_SegmentType)
+	*p = x
+	return p
+}
+
+func (x Snippet_Segment_SegmentType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Snippet_Segment_SegmentType) Descriptor() protoreflect.EnumDescriptor {
+	return file_metadata_metadata_proto_enumTypes[2].Descriptor()
+}
+
+func (Snippet_Segment_SegmentType) Type() protoreflect.EnumType {
+	return &file_metadata_metadata_proto_enumTypes[2]
+}
+
+func (x Snippet_Segment_SegmentType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Snippet_Segment_SegmentType.Descriptor instead.
+func (Snippet_Segment_SegmentType) EnumDescriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{1, 0, 0}
+}
+
+// The snippet index for a single client library.
+type Index struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The Client Library these snippets are for.
+	ClientLibrary *ClientLibrary `protobuf:"bytes,1,opt,name=client_library,json=clientLibrary,proto3" json:"client_library,omitempty"`
+	// The list of snippets.
+	Snippets []*Snippet `protobuf:"bytes,2,rep,name=snippets,proto3" json:"snippets,omitempty"`
+}
+
+func (x *Index) Reset() {
+	*x = Index{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Index) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Index) ProtoMessage() {}
+
+func (x *Index) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Index.ProtoReflect.Descriptor instead.
+func (*Index) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Index) GetClientLibrary() *ClientLibrary {
+	if x != nil {
+		return x.ClientLibrary
+	}
+	return nil
+}
+
+func (x *Index) GetSnippets() []*Snippet {
+	if x != nil {
+		return x.Snippets
+	}
+	return nil
+}
+
+// One sample.
+// Parts of this information will be language specific.
+type Snippet struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The region tag name. Does not include the square brackets or the START or
+	// END indicators.
+	RegionTag string `protobuf:"bytes,1,opt,name=region_tag,json=regionTag,proto3" json:"region_tag,omitempty"`
+	// The title of the snippet, for human consumption mostly. For generated
+	// snippets this may be the snippet method or file name, or obtained from
+	// / snippet configuration.
+	Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+	// A description of the snippet, for human consumption mostly. For generated
+	// snippets this may be the description of the service method, or obtained
+	// from snippet configuration.
+	Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+	// The file where the snippet code lives.
+	// The path should be relative to where this metadata file is stored on the
+	// GitHub repo root and should not include branch, tag, commitish, etc.,
+	// as those will be the same as for the metadata file.
+	File string `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
+	// The programming language the snippet is written in.
+	// This will match the client library language most of the time, but not
+	// always. For instance, in .NET, libraries are written in C# but some samples
+	// may be written in F# or VB .NET.
+	// Note that this does not contain information about the snippet supported
+	// platforms or language versions, etc. This is just a quick way to identify
+	// the generally supported langauge.
+	Language Language `protobuf:"varint,5,opt,name=language,proto3,enum=google.cloud.tools.snippetgen.snippetindex.v1.Language" json:"language,omitempty"`
+	// The client library method this snippet is for.
+	ClientMethod *ClientMethod `protobuf:"bytes,6,opt,name=client_method,json=clientMethod,proto3" json:"client_method,omitempty"`
+	// Wether this is the canonical snippet for the corresponding service method.
+	// This is to be interpreted in conjunction with origin as follows:
+	// For a given service method:
+	// - A handwritten canonical takes precedence over
+	// - A config canonical which in turn takes precedence over
+	// - A baseline canonical.
+	Canonical bool `protobuf:"varint,7,opt,name=canonical,proto3" json:"canonical,omitempty"`
+	// The origin of the snippet.
+	Origin Snippet_Origin `protobuf:"varint,8,opt,name=origin,proto3,enum=google.cloud.tools.snippetgen.snippetindex.v1.Snippet_Origin" json:"origin,omitempty"`
+	// The different segments of the snippet.
+	// Must contain the FULL segment always.
+	// There may be overlap between segments.
+	Segments []*Snippet_Segment `protobuf:"bytes,9,rep,name=segments,proto3" json:"segments,omitempty"`
+}
+
+func (x *Snippet) Reset() {
+	*x = Snippet{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Snippet) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Snippet) ProtoMessage() {}
+
+func (x *Snippet) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Snippet.ProtoReflect.Descriptor instead.
+func (*Snippet) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Snippet) GetRegionTag() string {
+	if x != nil {
+		return x.RegionTag
+	}
+	return ""
+}
+
+func (x *Snippet) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *Snippet) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Snippet) GetFile() string {
+	if x != nil {
+		return x.File
+	}
+	return ""
+}
+
+func (x *Snippet) GetLanguage() Language {
+	if x != nil {
+		return x.Language
+	}
+	return Language_LANGUAGE_UNSPECIFIED
+}
+
+func (x *Snippet) GetClientMethod() *ClientMethod {
+	if x != nil {
+		return x.ClientMethod
+	}
+	return nil
+}
+
+func (x *Snippet) GetCanonical() bool {
+	if x != nil {
+		return x.Canonical
+	}
+	return false
+}
+
+func (x *Snippet) GetOrigin() Snippet_Origin {
+	if x != nil {
+		return x.Origin
+	}
+	return Snippet_ORIGIN_UNSPECIFIED
+}
+
+func (x *Snippet) GetSegments() []*Snippet_Segment {
+	if x != nil {
+		return x.Segments
+	}
+	return nil
+}
+
+// A client library method.
+// Will contain language specific information.
+type ClientMethod struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The short name of the method, usually the name it is declared with.
+	// This may not be unique within the service client because of overloads.
+	ShortName string `protobuf:"bytes,1,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"`
+	// The fully qualified name of the method, which is the short_name qualified
+	// by the full_name of the service client.
+	// This value is redundant, but present to make it easier for consumers to
+	// obtain it.
+	// This may not be unique within the service client because of overloads.
+	FullName string `protobuf:"bytes,2,opt,name=full_name,json=fullName,proto3" json:"full_name,omitempty"`
+	// Indicates wether this method is synchronous or asynchronous.
+	// Some languages may support only one of the variants, in which case, this
+	// field will always have the same value (for that language).
+	Async bool `protobuf:"varint,3,opt,name=async,proto3" json:"async,omitempty"`
+	// Parameters of this method in the same order as they appear on the method
+	// declaration. Must be empty if the method has no parameters.
+	Parameters []*ClientMethod_Parameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"`
+	// Fully qualified type name of this method result, if any.
+	ResultType string `protobuf:"bytes,5,opt,name=result_type,json=retTyp,proto3" json:"result_type,omitempty"`
+	// The service client this method is declared in.
+	Client *ServiceClient `protobuf:"bytes,6,opt,name=client,proto3" json:"client,omitempty"`
+	// The service method this client method is for.
+	Method *Method `protobuf:"bytes,7,opt,name=method,proto3" json:"method,omitempty"`
+}
+
+func (x *ClientMethod) Reset() {
+	*x = ClientMethod{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientMethod) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientMethod) ProtoMessage() {}
+
+func (x *ClientMethod) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientMethod.ProtoReflect.Descriptor instead.
+func (*ClientMethod) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ClientMethod) GetShortName() string {
+	if x != nil {
+		return x.ShortName
+	}
+	return ""
+}
+
+func (x *ClientMethod) GetFullName() string {
+	if x != nil {
+		return x.FullName
+	}
+	return ""
+}
+
+func (x *ClientMethod) GetAsync() bool {
+	if x != nil {
+		return x.Async
+	}
+	return false
+}
+
+func (x *ClientMethod) GetParameters() []*ClientMethod_Parameter {
+	if x != nil {
+		return x.Parameters
+	}
+	return nil
+}
+
+func (x *ClientMethod) GetResultType() string {
+	if x != nil {
+		return x.ResultType
+	}
+	return ""
+}
+
+func (x *ClientMethod) GetClient() *ServiceClient {
+	if x != nil {
+		return x.Client
+	}
+	return nil
+}
+
+func (x *ClientMethod) GetMethod() *Method {
+	if x != nil {
+		return x.Method
+	}
+	return nil
+}
+
+// A service client defined in the client library specified in Index.
+// Will contain language specific information.
+type ServiceClient struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The short name of the service client, usually the name it is declared with.
+	// This may not be unique within the client library because of
+	// namespaces/packages.
+	ShortName string `protobuf:"bytes,1,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"`
+	// The fully qualified name of the service client, which is the short_name
+	// qualified by the namespace/package/type name this client is declared in.
+	// This will be unique within the client libray.
+	FullName string `protobuf:"bytes,2,opt,name=full_name,json=fullName,proto3" json:"full_name,omitempty"`
+}
+
+func (x *ServiceClient) Reset() {
+	*x = ServiceClient{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ServiceClient) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ServiceClient) ProtoMessage() {}
+
+func (x *ServiceClient) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ServiceClient.ProtoReflect.Descriptor instead.
+func (*ServiceClient) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ServiceClient) GetShortName() string {
+	if x != nil {
+		return x.ShortName
+	}
+	return ""
+}
+
+func (x *ServiceClient) GetFullName() string {
+	if x != nil {
+		return x.FullName
+	}
+	return ""
+}
+
+// A client library.
+// Will contain language specific information.
+type ClientLibrary struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the client library. This value will be language dependent
+	// and may or may not include the library version.
+	// Usually this will be the name used to identify the library on per-language
+	// package managers.
+	// Examples: "Google.Cloud.Translate.V3",
+	// "cloud.google.com/go/translate/apiv3".
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// The full version of the client library. May also be language dependent.
+	// Cannot be updated on metadata generation, but on library release.
+	// Examples: "4.3.0", "2.5.2-beta01"
+	Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+	// The programming language the library is written in.
+	// Note that this does not contain information about the library supported
+	// platforms or language versions, etc. This is just a quick way to identify
+	// the generally supported langauge.
+	Language Language `protobuf:"varint,3,opt,name=language,proto3,enum=google.cloud.tools.snippetgen.snippetindex.v1.Language" json:"language,omitempty"`
+	// The APIs this client library is for.
+	// Some languages bundle several APIs on the same client library.
+	Apis []*Api `protobuf:"bytes,4,rep,name=apis,proto3" json:"apis,omitempty"`
+}
+
+func (x *ClientLibrary) Reset() {
+	*x = ClientLibrary{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientLibrary) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientLibrary) ProtoMessage() {}
+
+func (x *ClientLibrary) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientLibrary.ProtoReflect.Descriptor instead.
+func (*ClientLibrary) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ClientLibrary) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *ClientLibrary) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *ClientLibrary) GetLanguage() Language {
+	if x != nil {
+		return x.Language
+	}
+	return Language_LANGUAGE_UNSPECIFIED
+}
+
+func (x *ClientLibrary) GetApis() []*Api {
+	if x != nil {
+		return x.Apis
+	}
+	return nil
+}
+
+type Method struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The short name of the method, which is the name used to
+	// declare it within the proto file. This is unique within the service,
+	// but may not be unique within the API.
+	ShortName string `protobuf:"bytes,1,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"`
+	// The full name of the method, which is the short name qualified
+	// by the full name of the service in which it is declared.
+	// This is globally unique.
+	FullName string `protobuf:"bytes,2,opt,name=full_name,json=fullName,proto3" json:"full_name,omitempty"`
+	// The service this method is declared in.
+	Service *Service `protobuf:"bytes,3,opt,name=service,proto3" json:"service,omitempty"`
+}
+
+func (x *Method) Reset() {
+	*x = Method{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Method) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Method) ProtoMessage() {}
+
+func (x *Method) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Method.ProtoReflect.Descriptor instead.
+func (*Method) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *Method) GetShortName() string {
+	if x != nil {
+		return x.ShortName
+	}
+	return ""
+}
+
+func (x *Method) GetFullName() string {
+	if x != nil {
+		return x.FullName
+	}
+	return ""
+}
+
+func (x *Method) GetService() *Service {
+	if x != nil {
+		return x.Service
+	}
+	return nil
+}
+
+// A service defined in the API the client library referenced in Index is for.
+type Service struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The short name of the service, which is the name used to
+	// declare it within the proto file. This is usually, but not
+	// absolutely necessarily, unique within an API.
+	// Example: "TranslationService"
+	ShortName string `protobuf:"bytes,1,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"`
+	// The full name of the service, which is the short name qualified
+	// by the package of the proto in which it is declared.
+	// This is globally unique.
+	// Example: "google.cloud.translate.v3.TranslationService"
+	FullName string `protobuf:"bytes,2,opt,name=full_name,json=fullName,proto3" json:"full_name,omitempty"`
+}
+
+func (x *Service) Reset() {
+	*x = Service{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Service) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Service) ProtoMessage() {}
+
+func (x *Service) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Service.ProtoReflect.Descriptor instead.
+func (*Service) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *Service) GetShortName() string {
+	if x != nil {
+		return x.ShortName
+	}
+	return ""
+}
+
+func (x *Service) GetFullName() string {
+	if x != nil {
+		return x.FullName
+	}
+	return ""
+}
+
+// An API
+type Api struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The ID of the API, identical to the protobuf package
+	// ending with a version number.
+	// Example: "google.cloud.translate.v3"
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	// The full version inferred from the end of the ID.
+	// Examples: "v3", "v2beta1", "v1beta"
+	Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+}
+
+func (x *Api) Reset() {
+	*x = Api{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Api) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Api) ProtoMessage() {}
+
+func (x *Api) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Api.ProtoReflect.Descriptor instead.
+func (*Api) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *Api) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *Api) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+// A segment of the snippet.
+type Snippet_Segment struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The line where this segment begins, inclusive.
+	// For the FULL segment, this will be the START region tag line + 1.
+	Start int32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"`
+	// The line where this segment ends, inclusive.
+	// For the FULL segment, this will be the END region tag line - 1.
+	End int32 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"`
+	// The type of the segment.
+	Type Snippet_Segment_SegmentType `protobuf:"varint,3,opt,name=type,proto3,enum=google.cloud.tools.snippetgen.snippetindex.v1.Snippet_Segment_SegmentType" json:"type,omitempty"`
+}
+
+func (x *Snippet_Segment) Reset() {
+	*x = Snippet_Segment{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Snippet_Segment) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Snippet_Segment) ProtoMessage() {}
+
+func (x *Snippet_Segment) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Snippet_Segment.ProtoReflect.Descriptor instead.
+func (*Snippet_Segment) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{1, 0}
+}
+
+func (x *Snippet_Segment) GetStart() int32 {
+	if x != nil {
+		return x.Start
+	}
+	return 0
+}
+
+func (x *Snippet_Segment) GetEnd() int32 {
+	if x != nil {
+		return x.End
+	}
+	return 0
+}
+
+func (x *Snippet_Segment) GetType() Snippet_Segment_SegmentType {
+	if x != nil {
+		return x.Type
+	}
+	return Snippet_Segment_SEGMENT_TYPE_UNSPECIFIED
+}
+
+// A method parameter as described by its type and name.
+type ClientMethod_Parameter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Fully qualified type name of this parameter.
+	// May be empty for languages that don't specify a type.
+	Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+	// Name of the parameter as it appears on the method declaration.
+	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *ClientMethod_Parameter) Reset() {
+	*x = ClientMethod_Parameter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metadata_metadata_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientMethod_Parameter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientMethod_Parameter) ProtoMessage() {}
+
+func (x *ClientMethod_Parameter) ProtoReflect() protoreflect.Message {
+	mi := &file_metadata_metadata_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientMethod_Parameter.ProtoReflect.Descriptor instead.
+func (*ClientMethod_Parameter) Descriptor() ([]byte, []int) {
+	return file_metadata_metadata_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (x *ClientMethod_Parameter) GetType() string {
+	if x != nil {
+		return x.Type
+	}
+	return ""
+}
+
+func (x *ClientMethod_Parameter) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+var File_metadata_metadata_proto protoreflect.FileDescriptor
+
+var file_metadata_metadata_proto_rawDesc = []byte{
+	0x0a, 0x17, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e,
+	0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74,
+	0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x22, 0xc0, 0x01, 0x0a, 0x05, 0x49, 0x6e, 0x64,
+	0x65, 0x78, 0x12, 0x63, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x62,
+	0x72, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x6f, 0x6f,
+	0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e,
+	0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70,
+	0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x52, 0x0a, 0x08, 0x73, 0x6e, 0x69, 0x70, 0x70,
+	0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73,
+	0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65,
+	0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65,
+	0x74, 0x52, 0x08, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x73, 0x22, 0x8b, 0x07, 0x0a, 0x07,
+	0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f,
+	0x6e, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x67,
+	0x69, 0x6f, 0x6e, 0x54, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b,
+	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12,
+	0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69,
+	0x6c, 0x65, 0x12, 0x53, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x05,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c,
+	0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65,
+	0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65,
+	0x78, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6c,
+	0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x60, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f,
+	0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73,
+	0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0c, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x61, 0x6e,
+	0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x61,
+	0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x12, 0x55, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,
+	0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69,
+	0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69,
+	0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x2e,
+	0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x5a,
+	0x0a, 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x3e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+	0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e,
+	0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31,
+	0x2e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74,
+	0x52, 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0xb9, 0x02, 0x0a, 0x07, 0x53,
+	0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03,
+	0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x5e,
+	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x4a, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c,
+	0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69,
+	0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x69,
+	0x70, 0x70, 0x65, 0x74, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x67,
+	0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xa5,
+	0x01, 0x0a, 0x0b, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c,
+	0x0a, 0x18, 0x53, 0x45, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,
+	0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04,
+	0x46, 0x55, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x48, 0x4f, 0x52, 0x54, 0x10,
+	0x02, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54,
+	0x49, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16,
+	0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49,
+	0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x51, 0x55,
+	0x45, 0x53, 0x54, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12,
+	0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x5f, 0x48, 0x41, 0x4e, 0x44,
+	0x4c, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x22, 0x51, 0x0a, 0x06, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e,
+	0x12, 0x16, 0x0a, 0x12, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x50, 0x49, 0x5f,
+	0x44, 0x45, 0x46, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06,
+	0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x48, 0x41, 0x4e, 0x44,
+	0x57, 0x52, 0x49, 0x54, 0x54, 0x45, 0x4e, 0x10, 0x03, 0x22, 0xc2, 0x03, 0x0a, 0x0c, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68,
+	0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c,
+	0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75,
+	0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x65, 0x0a, 0x0a,
+	0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x45, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+	0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e,
+	0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x50, 0x61,
+	0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
+	0x65, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x79,
+	0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
+	0x54, 0x79, 0x70, 0x65, 0x12, 0x54, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c,
+	0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65,
+	0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65,
+	0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x4d, 0x0a, 0x06, 0x6d, 0x65,
+	0x74, 0x68, 0x6f, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x6f, 0x6f,
+	0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e,
+	0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70,
+	0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f,
+	0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1a, 0x33, 0x0a, 0x09, 0x50, 0x61, 0x72,
+	0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x4b,
+	0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12,
+	0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b,
+	0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xda, 0x01, 0x0a, 0x0d,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x12, 0x0a,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x08, 0x6c,
+	0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f, 0x6f,
+	0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73, 0x6e,
+	0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61,
+	0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
+	0x12, 0x46, 0x0a, 0x04, 0x61, 0x70, 0x69, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x74, 0x6f,
+	0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e, 0x2e, 0x73,
+	0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x41,
+	0x70, 0x69, 0x52, 0x04, 0x61, 0x70, 0x69, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x74,
+	0x68, 0x6f, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x50, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
+	0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x67, 0x65, 0x6e,
+	0x2e, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x31,
+	0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+	0x65, 0x22, 0x45, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
+	0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66,
+	0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x2f, 0x0a, 0x03, 0x41, 0x70, 0x69, 0x12,
+	0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
+	0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2a, 0xef, 0x01, 0x0a, 0x08, 0x4c, 0x61,
+	0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4c, 0x41, 0x4e, 0x47, 0x55, 0x41,
+	0x47, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
+	0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x5f, 0x50, 0x4c, 0x55, 0x53, 0x5f, 0x50, 0x4c, 0x55, 0x53, 0x10,
+	0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x50, 0x10, 0x02, 0x12, 0x08,
+	0x0a, 0x04, 0x44, 0x41, 0x52, 0x54, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x4c, 0x49, 0x58,
+	0x49, 0x52, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x52, 0x4c, 0x41, 0x4e, 0x47, 0x10, 0x05,
+	0x12, 0x0b, 0x0a, 0x07, 0x46, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x50, 0x10, 0x06, 0x12, 0x06, 0x0a,
+	0x02, 0x47, 0x4f, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x41, 0x56, 0x41, 0x10, 0x08, 0x12,
+	0x0e, 0x0a, 0x0a, 0x4a, 0x41, 0x56, 0x41, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x09, 0x12,
+	0x0a, 0x0a, 0x06, 0x4b, 0x4f, 0x54, 0x4c, 0x49, 0x4e, 0x10, 0x0a, 0x12, 0x07, 0x0a, 0x03, 0x50,
+	0x48, 0x50, 0x10, 0x0b, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x59, 0x54, 0x48, 0x4f, 0x4e, 0x10, 0x0c,
+	0x12, 0x08, 0x0a, 0x04, 0x52, 0x55, 0x42, 0x59, 0x10, 0x0d, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x55,
+	0x53, 0x54, 0x10, 0x0e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x57, 0x49, 0x46, 0x54, 0x10, 0x0f, 0x12,
+	0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x10, 0x12,
+	0x0a, 0x0a, 0x06, 0x56, 0x42, 0x5f, 0x4e, 0x45, 0x54, 0x10, 0x11, 0x42, 0xe3, 0x01, 0x5a, 0x4c,
+	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x67, 0x61, 0x70, 0x69, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x65,
+	0x72, 0x61, 0x74, 0x6f, 0x72, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+	0x6c, 0x2f, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x3b, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xaa, 0x02, 0x2d, 0x47,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x54, 0x6f, 0x6f, 0x6c,
+	0x73, 0x2e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x47, 0x65, 0x6e, 0x2e, 0x53, 0x6e, 0x69,
+	0x70, 0x70, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x2d, 0x47,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x54, 0x6f, 0x6f, 0x6c,
+	0x73, 0x5c, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x47, 0x65, 0x6e, 0x5c, 0x53, 0x6e, 0x69,
+	0x70, 0x70, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x5c, 0x56, 0x31, 0xea, 0x02, 0x32, 0x47,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x54, 0x6f,
+	0x6f, 0x6c, 0x73, 0x3a, 0x3a, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x47, 0x65, 0x6e, 0x3a,
+	0x3a, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x3a, 0x56,
+	0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_metadata_metadata_proto_rawDescOnce sync.Once
+	file_metadata_metadata_proto_rawDescData = file_metadata_metadata_proto_rawDesc
+)
+
+func file_metadata_metadata_proto_rawDescGZIP() []byte {
+	file_metadata_metadata_proto_rawDescOnce.Do(func() {
+		file_metadata_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_metadata_metadata_proto_rawDescData)
+	})
+	return file_metadata_metadata_proto_rawDescData
+}
+
+var file_metadata_metadata_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_metadata_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_metadata_metadata_proto_goTypes = []interface{}{
+	(Language)(0),                    // 0: google.cloud.tools.snippetgen.snippetindex.v1.Language
+	(Snippet_Origin)(0),              // 1: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Origin
+	(Snippet_Segment_SegmentType)(0), // 2: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.SegmentType
+	(*Index)(nil),                    // 3: google.cloud.tools.snippetgen.snippetindex.v1.Index
+	(*Snippet)(nil),                  // 4: google.cloud.tools.snippetgen.snippetindex.v1.Snippet
+	(*ClientMethod)(nil),             // 5: google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod
+	(*ServiceClient)(nil),            // 6: google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient
+	(*ClientLibrary)(nil),            // 7: google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary
+	(*Method)(nil),                   // 8: google.cloud.tools.snippetgen.snippetindex.v1.Method
+	(*Service)(nil),                  // 9: google.cloud.tools.snippetgen.snippetindex.v1.Service
+	(*Api)(nil),                      // 10: google.cloud.tools.snippetgen.snippetindex.v1.Api
+	(*Snippet_Segment)(nil),          // 11: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment
+	(*ClientMethod_Parameter)(nil),   // 12: google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter
+}
+var file_metadata_metadata_proto_depIdxs = []int32{
+	7,  // 0: google.cloud.tools.snippetgen.snippetindex.v1.Index.client_library:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary
+	4,  // 1: google.cloud.tools.snippetgen.snippetindex.v1.Index.snippets:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Snippet
+	0,  // 2: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.language:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Language
+	5,  // 3: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.client_method:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod
+	1,  // 4: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.origin:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Origin
+	11, // 5: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.segments:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment
+	12, // 6: google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.parameters:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter
+	6,  // 7: google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.client:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient
+	8,  // 8: google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.method:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Method
+	0,  // 9: google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.language:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Language
+	10, // 10: google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.apis:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Api
+	9,  // 11: google.cloud.tools.snippetgen.snippetindex.v1.Method.service:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Service
+	2,  // 12: google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.type:type_name -> google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.SegmentType
+	13, // [13:13] is the sub-list for method output_type
+	13, // [13:13] is the sub-list for method input_type
+	13, // [13:13] is the sub-list for extension type_name
+	13, // [13:13] is the sub-list for extension extendee
+	0,  // [0:13] is the sub-list for field type_name
+}
+
+func init() { file_metadata_metadata_proto_init() }
+func file_metadata_metadata_proto_init() {
+	if File_metadata_metadata_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_metadata_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Index); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Snippet); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientMethod); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ServiceClient); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientLibrary); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Method); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Service); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Api); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Snippet_Segment); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metadata_metadata_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientMethod_Parameter); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_metadata_metadata_proto_rawDesc,
+			NumEnums:      3,
+			NumMessages:   10,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_metadata_metadata_proto_goTypes,
+		DependencyIndexes: file_metadata_metadata_proto_depIdxs,
+		EnumInfos:         file_metadata_metadata_proto_enumTypes,
+		MessageInfos:      file_metadata_metadata_proto_msgTypes,
+	}.Build()
+	File_metadata_metadata_proto = out.File
+	file_metadata_metadata_proto_rawDesc = nil
+	file_metadata_metadata_proto_goTypes = nil
+	file_metadata_metadata_proto_depIdxs = nil
+}
diff --git a/internal/snippets/metadata/metadata.proto b/internal/snippets/metadata/metadata.proto
new file mode 100644
index 0000000..65ba5ec
--- /dev/null
+++ b/internal/snippets/metadata/metadata.proto
@@ -0,0 +1,320 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file temporarily lives here and is sourced from internal usage. In the future
+// this file will be in genproto. Updates to this file for the time being are
+// manual. To regen this file run `go generate ./...` in this module.
+syntax = "proto3";
+
+package google.cloud.tools.snippetgen.snippetindex.v1;
+
+option csharp_namespace = "Google.Cloud.Tools.SnippetGen.SnippetIndex.V1";
+option php_namespace = "Google\\Cloud\\Tools\\SnippetGen\\SnippetIndex\\V1";
+option ruby_package = "Google::Cloud::Tools::SnippetGen::SnippetIndex::V1";
+option go_package = "github.com/googleapis/gapic-generator-go/internal/snippets/metadata;metadata";
+
+// The snippet index for a single client library.
+message Index {
+  // The Client Library these snippets are for.
+  ClientLibrary client_library = 1;
+
+  // The list of snippets.
+  repeated Snippet snippets = 2;
+}
+
+// One sample.
+// Parts of this information will be language specific.
+message Snippet {
+  // The region tag name. Does not include the square brackets or the START or
+  // END indicators.
+  string region_tag = 1;
+
+  // The title of the snippet, for human consumption mostly. For generated
+  // snippets this may be the snippet method or file name, or obtained from
+  /// snippet configuration.
+  string title = 2;
+
+  // A description of the snippet, for human consumption mostly. For generated
+  // snippets this may be the description of the service method, or obtained
+  // from snippet configuration.
+  string description = 3;
+
+  // The file where the snippet code lives.
+  // The path should be relative to where this metadata file is stored on the
+  // GitHub repo root and should not include branch, tag, commitish, etc.,
+  // as those will be the same as for the metadata file.
+  string file = 4;
+
+  // The programming language the snippet is written in.
+  // This will match the client library language most of the time, but not
+  // always. For instance, in .NET, libraries are written in C# but some samples
+  // may be written in F# or VB .NET.
+  // Note that this does not contain information about the snippet supported
+  // platforms or language versions, etc. This is just a quick way to identify
+  // the generally supported langauge.
+  Language language = 5;
+
+  // The client library method this snippet is for.
+  ClientMethod client_method = 6;
+
+  // Wether this is the canonical snippet for the corresponding service method.
+  // This is to be interpreted in conjunction with origin as follows:
+  // For a given service method:
+  // - A handwritten canonical takes precedence over
+  // - A config canonical which in turn takes precedence over
+  // - A baseline canonical.
+  bool canonical = 7;
+
+  // The origin of the snippet.
+  Origin origin = 8;
+
+  // The different segments of the snippet.
+  // Must contain the FULL segment always.
+  // There may be overlap between segments.
+  repeated Segment segments = 9;
+
+  // The origin of the snippet.
+  enum Origin {
+    // The origin has not been specified. Consumers should not see this value.
+    ORIGIN_UNSPECIFIED = 0;
+
+    // The snippet is generated from the API definition only, including protos
+    // and descriptive information, i.e. the same information used to generate
+    // the client libraries themselves.
+    // No snippet configuration has been specified. This refers to SnippetGen
+    // phase 1.
+    API_DEFINITION = 1;
+
+    // The snippet is generated from the API definition and a specific snippet
+    // configuration. This refers to SnippetGen phase 2.
+    CONFIG = 2;
+
+    // The snippet is handwritten.
+    HANDWRITTEN = 3;
+  }
+
+  // A segment of the snippet.
+  message Segment {
+    // The line where this segment begins, inclusive.
+    // For the FULL segment, this will be the START region tag line + 1.
+    int32 start = 1;
+
+    // The line where this segment ends, inclusive.
+    // For the FULL segment, this will be the END region tag line - 1.
+    int32 end = 2;
+
+    // The type of the segment.
+    SegmentType type = 3;
+
+    // The type of the segment.
+    // Basically describes what this segment shows.
+    enum SegmentType {
+      // The segment type has not been specified. Consumers should not see this
+      // value.
+      SEGMENT_TYPE_UNSPECIFIED = 0;
+
+      // The full sample including import statements.
+      // This corresponds to the sample as determined by the region tags.
+      FULL = 1;
+
+      // A shorter version of the full sample, may not include imports and some
+      // langauge specific initialization code. This is to be used in contexts
+      // in which the full aspects of the sample are made clear outside the
+      // code.
+      SHORT = 2;
+
+      // The segment contains the service client initialization code only.
+      // To be used in tutorials, codelabs, etc.
+      CLIENT_INITIALIZATION = 3;
+
+      // The segment contains the request initialization code only.
+      // To be used in tutorials, codelabs, etc.
+      REQUEST_INITIALIZATION = 4;
+
+      // The segment contains the request execution code only.
+      // To be used in tutorials, codelabs, etc.
+      REQUEST_EXECUTION = 5;
+
+      // The segment contains the response handling code only.
+      // To be used in tutorials, codelabs, etc.
+      RESPONSE_HANDLING = 6;
+    }
+  }
+}
+
+// A client library method.
+// Will contain language specific information.
+message ClientMethod {
+  // The short name of the method, usually the name it is declared with.
+  // This may not be unique within the service client because of overloads.
+  string short_name = 1;
+
+  // The fully qualified name of the method, which is the short_name qualified
+  // by the full_name of the service client.
+  // This value is redundant, but present to make it easier for consumers to
+  // obtain it.
+  // This may not be unique within the service client because of overloads.
+  string full_name = 2;
+
+  // Indicates wether this method is synchronous or asynchronous.
+  // Some languages may support only one of the variants, in which case, this
+  // field will always have the same value (for that language).
+  bool async = 3;
+
+  // Parameters of this method in the same order as they appear on the method
+  // declaration. Must be empty if the method has no parameters.
+  repeated Parameter parameters = 4;
+
+  // Fully qualified type name of this method result, if any.
+  string result_type = 5;
+
+  // The service client this method is declared in.
+  ServiceClient client = 6;
+
+  // The service method this client method is for.
+  Method method = 7;
+
+  // A method parameter as described by its type and name.
+  message Parameter {
+    // Fully qualified type name of this parameter.
+    // May be empty for languages that don't specify a type.
+    string type = 1;
+
+    // Name of the parameter as it appears on the method declaration.
+    string name = 2;
+  }
+}
+
+// A service client defined in the client library specified in Index.
+// Will contain language specific information.
+message ServiceClient {
+  // The short name of the service client, usually the name it is declared with.
+  // This may not be unique within the client library because of
+  // namespaces/packages.
+  string short_name = 1;
+
+  // The fully qualified name of the service client, which is the short_name
+  // qualified by the namespace/package/type name this client is declared in.
+  // This will be unique within the client libray.
+  string full_name = 2;
+}
+
+// A client library.
+// Will contain language specific information.
+message ClientLibrary {
+  // The name of the client library. This value will be language dependent
+  // and may or may not include the library version.
+  // Usually this will be the name used to identify the library on per-language
+  // package managers.
+  // Examples: "Google.Cloud.Translate.V3",
+  // "cloud.google.com/go/translate/apiv3".
+  string name = 1;
+
+  // The full version of the client library. May also be language dependent.
+  // Cannot be updated on metadata generation, but on library release.
+  // Examples: "4.3.0", "2.5.2-beta01"
+  string version = 2;
+
+  // The programming language the library is written in.
+  // Note that this does not contain information about the library supported
+  // platforms or language versions, etc. This is just a quick way to identify
+  // the generally supported langauge.
+  Language language = 3;
+
+  // The APIs this client library is for.
+  // Some languages bundle several APIs on the same client library.
+  repeated Api apis = 4;
+}
+
+message Method {
+  // The short name of the method, which is the name used to
+  // declare it within the proto file. This is unique within the service,
+  // but may not be unique within the API.
+  string short_name = 1;
+
+  // The full name of the method, which is the short name qualified
+  // by the full name of the service in which it is declared.
+  // This is globally unique.
+  string full_name = 2;
+
+  // The service this method is declared in.
+  Service service = 3;
+}
+
+// A service defined in the API the client library referenced in Index is for.
+message Service {
+  // The short name of the service, which is the name used to
+  // declare it within the proto file. This is usually, but not
+  // absolutely necessarily, unique within an API.
+  // Example: "TranslationService"
+  string short_name = 1;
+
+  // The full name of the service, which is the short name qualified
+  // by the package of the proto in which it is declared.
+  // This is globally unique.
+  // Example: "google.cloud.translate.v3.TranslationService"
+  string full_name = 2;
+}
+
+// An API
+message Api {
+  // The ID of the API, identical to the protobuf package
+  // ending with a version number.
+  // Example: "google.cloud.translate.v3"
+  string id = 1;
+
+  // The full version inferred from the end of the ID.
+  // Examples: "v3", "v2beta1", "v1beta"
+  string version = 2;
+}
+
+// A programming language
+enum Language {
+  // The language has not been specified. Consumers should not see this value.
+  LANGUAGE_UNSPECIFIED = 0;
+
+  C_PLUS_PLUS = 1;
+
+  C_SHARP = 2;
+
+  DART = 3;
+
+  ELIXIR = 4;
+
+  ERLANG = 5;
+
+  F_SHARP = 6;
+
+  GO = 7;
+
+  JAVA = 8;
+
+  JAVASCRIPT = 9;
+
+  KOTLIN = 10;
+
+  PHP = 11;
+
+  PYTHON = 12;
+
+  RUBY = 13;
+
+  RUST = 14;
+
+  SWIFT = 15;
+
+  TYPESCRIPT = 16;
+
+  VB_NET = 17;
+}
\ No newline at end of file
diff --git a/internal/snippets/snippets.go b/internal/snippets/snippets.go
new file mode 100644
index 0000000..86ea165
--- /dev/null
+++ b/internal/snippets/snippets.go
@@ -0,0 +1,292 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package snippets
+
+//go:generate protoc --go_out=. --go_opt=paths=source_relative metadata/metadata.proto
+
+import (
+	"fmt"
+	"regexp"
+	"sort"
+	"strings"
+
+	"github.com/googleapis/gapic-generator-go/internal/license"
+	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets/metadata"
+	"google.golang.org/protobuf/encoding/protojson"
+)
+
+// VersionPlaceholder is the string value $VERSION, intended to be replaced with
+// the actual module version by a generator post-processing script.
+var VersionPlaceholder = "$VERSION"
+
+// headerLen is the length of the Apache license header including trailing newlines.
+var headerLen = len(strings.Split(license.Apache, "\n"))
+
+var spaceSanitizerRegex = regexp.MustCompile(`:\s*`)
+
+var ctxParam = &param{
+	name:  "ctx",
+	pType: "context.Context",
+}
+
+var optsParam = &param{
+	name:  "opts",
+	pType: "...gax.CallOption",
+}
+
+// SnippetMetadata is a model for capturing snippet details and writing them to
+// a snippet_metadata.*.json file.
+type SnippetMetadata struct {
+	// protoPkg is the proto namespace for the API package.
+	protoPkg string
+	// libPkg is the Go import path for the GAPIC client.
+	libPkg string
+	// protoServices is a map of gapic service short names to service structs.
+	protoServices map[string]*service
+	// apiVersion is the gapic service version. (e.g. "v1", "v1beta1")
+	apiVersion string
+	// pkgName is the short package name after the semi-colon in go-gapic-package.
+	pkgName string
+}
+
+// NewMetadata initializes the model that will collect snippet metadata, from:
+// protoPkg - dot-separated, without final type name element (e.g. "google.cloud.bigquery.migration.v2")
+// libPkg - the Go import path for the GAPIC client, per libraryPackage in gapic_metadata.json (e.g. "cloud.google.com/go/bigquery/migration/apiv2")
+// pkgName - stored in g.opts.pkgName, used as an argument to pbinfo.ReduceServName
+func NewMetadata(protoPkg, libPkg, pkgName string) *SnippetMetadata {
+	lastDot := strings.LastIndex(protoPkg, ".")
+	apiVersion := protoPkg[lastDot+1:]
+	return &SnippetMetadata{
+		protoPkg:      protoPkg,
+		libPkg:        libPkg,
+		apiVersion:    apiVersion,
+		protoServices: make(map[string]*service),
+		pkgName:       pkgName,
+	}
+}
+
+// AddService creates a service entry from:
+// servName - the service short name (e.g. "AutoscalingPolicyService") identifier
+// defaultHost - the DNS hostname for the service, available from annotations.E_DefaultHost. (e.g. "bigquerymigration.googleapis.com")
+func (sm *SnippetMetadata) AddService(servName, defaultHost string) {
+	shortName := strings.Split(defaultHost, ".")[0]
+	s := &service{
+		protoName: servName,
+		methods:   make(map[string]*method),
+		shortName: shortName,
+	}
+	sm.protoServices[servName] = s
+}
+
+// AddMethod uses the service short name (e.g. "AutoscalingPolicyService") and method name
+// to add an incomplete method entry that will be updated via UpdateMethodDoc and UpdateMethodResult.
+// parentProtoPkg and parentName are the original proto namespace and service for the method.
+// (In mixin methods, these are different from the protoPkg and service into which it has been mixed.)
+func (sm *SnippetMetadata) AddMethod(servName, methodName, parentProtoPkg, parentName string, regionTagEnd int) {
+	m := &method{
+		regionTag:      sm.RegionTag(servName, methodName),
+		regionTagStart: headerLen,
+		regionTagEnd:   regionTagEnd,
+		parentProtoPkg: parentProtoPkg,
+		parentName:     parentName,
+	}
+	sm.protoServices[servName].methods[methodName] = m
+}
+
+// UpdateMethodDoc uses service short name (e.g. "AutoscalingPolicyService") and
+// and method name identifiers to add a doc method comment.
+func (sm *SnippetMetadata) UpdateMethodDoc(servName, methodName, doc string) {
+	m := sm.protoServices[servName].methods[methodName]
+	lines := strings.Split(doc, "\n")
+	var b strings.Builder
+	for _, l := range lines {
+		b.WriteString(strings.TrimSpace(l) + "\n")
+	}
+	m.doc = b.String()
+}
+
+// UpdateMethodResult uses service short name (e.g. "AutoscalingPolicyService") and
+// and method name identifiers to add a method result type.
+func (sm *SnippetMetadata) UpdateMethodResult(servName, methodName, result string) {
+	m := sm.protoServices[servName].methods[methodName]
+	m.result = result
+}
+
+// AddParams adds a slice of 3 params to the method: ctx context.Context, req <requestType>, opts ...gax.CallOption,
+// ctx and opts params are hardcoded since these are currently the same in all client wrapper methods.
+// The req param will be omitted if empty requestType is given.
+func (sm *SnippetMetadata) AddParams(servName, methodName, requestType string) {
+	m := sm.protoServices[servName].methods[methodName]
+	m.params = []*param{ctxParam}
+	if requestType != "" {
+		m.params = append(m.params,
+			&param{
+				name:  "req",
+				pType: requestType,
+			})
+	}
+	m.params = append(m.params, optsParam)
+}
+
+// RegionTag generates a snippet region tag from service.shortName(defaultHost),
+// apiVersion, and the given full servName and method name.
+func (sm *SnippetMetadata) RegionTag(servName, methodName string) string {
+	s := sm.protoServices[servName]
+	return fmt.Sprintf("%s_%s_generated_%s_%s_sync", s.shortName, sm.apiVersion, servName, methodName)
+}
+
+// ToMetadataJSON marshals the completed SnippetMetadata to a []byte containing
+// the protojson output.
+func (sm *SnippetMetadata) ToMetadataJSON() ([]byte, error) {
+	m := sm.ToMetadataIndex()
+	b, err := protojson.MarshalOptions{Multiline: true}.Marshal(m)
+	if err != nil {
+		return nil, err
+	}
+	// Hack to standardize output from protojson which is currently
+	// non-deterministic with spacing after json keys.
+	return spaceSanitizerRegex.ReplaceAll(b, []byte(": ")), nil
+}
+
+// ToMetadataIndex creates a metadata.Index from the SnippetMetadata.
+func (sm *SnippetMetadata) ToMetadataIndex() *metadata.Index {
+	index := &metadata.Index{
+		ClientLibrary: &metadata.ClientLibrary{
+			Name:     sm.libPkg,
+			Version:  VersionPlaceholder,
+			Language: metadata.Language_GO,
+			Apis: []*metadata.Api{
+				{
+					Id:      sm.protoPkg,
+					Version: sm.protoVersion(),
+				},
+			},
+		},
+	}
+
+	// Sort keys to stabilize output
+	var svcKeys []string
+	for k := range sm.protoServices {
+		svcKeys = append(svcKeys, k)
+	}
+	sort.StringSlice(svcKeys).Sort()
+	for _, serviceShortName := range svcKeys {
+		reducedServName := pbinfo.ReduceServName(serviceShortName, sm.pkgName)
+		clientShortName := reducedServName + "Client"
+		service := sm.protoServices[serviceShortName]
+		var methodKeys []string
+		for k := range service.methods {
+			methodKeys = append(methodKeys, k)
+		}
+		sort.StringSlice(methodKeys).Sort()
+		for _, methodShortName := range methodKeys {
+			method := service.methods[methodShortName]
+			snp := &metadata.Snippet{
+				RegionTag:   method.regionTag,
+				Title:       fmt.Sprintf("%s %s Sample", service.shortName, methodShortName),
+				Description: strings.TrimSpace(method.doc),
+				File:        fmt.Sprintf("%s/%s/main.go", clientShortName, methodShortName),
+				Language:    metadata.Language_GO,
+				Canonical:   false,
+				Origin:      *metadata.Snippet_API_DEFINITION.Enum(),
+				ClientMethod: &metadata.ClientMethod{
+					ShortName:  methodShortName,
+					FullName:   fmt.Sprintf("%s.%s.%s", sm.protoPkg, clientShortName, methodShortName),
+					Async:      false,
+					ResultType: method.result,
+					Client: &metadata.ServiceClient{
+						ShortName: clientShortName,
+						FullName:  fmt.Sprintf("%s.%s", sm.protoPkg, clientShortName),
+					},
+					Method: &metadata.Method{
+						ShortName: methodShortName,
+						FullName:  fmt.Sprintf("%s.%s.%s", method.parentProtoPkg, method.parentName, methodShortName),
+						Service: &metadata.Service{
+							ShortName: method.parentName,
+							FullName:  fmt.Sprintf("%s.%s", method.parentProtoPkg, method.parentName),
+						},
+					},
+				},
+			}
+			segment := &metadata.Snippet_Segment{
+				// The line where this segment begins, inclusive.
+				// For the FULL segment, this will be the START region tag line + 1.
+				Start: int32(method.regionTagStart + 1),
+				// The line where this segment ends, inclusive.
+				// For the FULL segment, this will be the END region tag line - 1.
+				End:  int32(method.regionTagEnd - 1),
+				Type: metadata.Snippet_Segment_FULL,
+			}
+			snp.Segments = append(snp.Segments, segment)
+			for _, param := range method.params {
+				methParam := &metadata.ClientMethod_Parameter{
+					Type: param.pType,
+					Name: param.name,
+				}
+				snp.ClientMethod.Parameters = append(snp.ClientMethod.Parameters, methParam)
+			}
+			index.Snippets = append(index.Snippets, snp)
+		}
+	}
+	return index
+}
+
+func (sm *SnippetMetadata) protoVersion() string {
+	ss := strings.Split(sm.protoPkg, ".")
+	return ss[len(ss)-1]
+}
+
+// service associates a proto service from gapic metadata with gapic client and its methods.
+type service struct {
+	// protoName is the service short name.
+	protoName string
+	// methods is a map of gapic method short names to method structs.
+	methods map[string]*method
+	// shortName the first element of the default DNS hostname for the service.
+	// (e.g. "bigquerymigration" from "bigquerymigration.googleapis.com")
+	shortName string
+}
+
+// method associates elements of gapic client methods (docs, params and return types)
+// with snippet file details such as the region tag string and line numbers.
+type method struct {
+	// doc is the documentation for the methods.
+	doc string
+	// regionTag is the region tag that will be used for the generated snippet.
+	regionTag string
+	// regionTagStart is the number of the line AFTER the START region tag in the snippet file.
+	regionTagStart int
+	// regionTagEnd is the line number of the END region tag in the snippet file.
+	regionTagEnd int
+	// params are the input parameters for the gapic method.
+	params []*param
+	// result is the return value for the method.
+	result string
+	// parentProtoPkg is the original proto namespace for the method.
+	// In mixin methods, this namespace is different from the protoPkg namespace into which it has been mixed.
+	parentProtoPkg string
+	// parentName is the proto name of the method's original parent.
+	// In mixin methods, this parent is different from the service into which it has been mixed.
+	parentName string
+}
+
+// param contains the details of a method parameter.
+type param struct {
+	// name of the parameter.
+	name string
+	// pType is the Go type for the parameter.
+	pType string
+}
diff --git a/rules_go_gapic/go_gapic.bzl b/rules_go_gapic/go_gapic.bzl
index 1b4dfb3..4570f84 100644
--- a/rules_go_gapic/go_gapic.bzl
+++ b/rules_go_gapic/go_gapic.bzl
@@ -94,6 +94,7 @@ def go_gapic_library(
   transport = "grpc",
   diregapic = False,
   rest_numeric_enums = False,
+  omit_snippets = False,
   **kwargs):
 
   file_args = {}
@@ -121,6 +122,9 @@ def go_gapic_library(
   if rest_numeric_enums:
     plugin_args.append("rest-numeric-enums")
 
+  if omit_snippets:
+    plugin_args.append("omit-snippets")
+
   srcjar_name = name+"_srcjar"
   raw_srcjar_name = srcjar_name+"_raw"
   output_suffix = ".srcjar"


Test patch:
diff --git a/internal/gengapic/client_init_test.go b/internal/gengapic/client_init_test.go
index 13e1776..c9d32d9 100644
--- a/internal/gengapic/client_init_test.go
+++ b/internal/gengapic/client_init_test.go
@@ -24,6 +24,7 @@ import (
 	"github.com/google/go-cmp/cmp"
 	conf "github.com/googleapis/gapic-generator-go/internal/grpc_service_config"
 	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
 	"github.com/googleapis/gapic-generator-go/internal/txtdiff"
 	"google.golang.org/genproto/googleapis/api/annotations"
 	"google.golang.org/genproto/googleapis/api/serviceconfig"
@@ -385,6 +386,7 @@ func TestClientInit(t *testing.T) {
 		customOpServ *descriptor.ServiceDescriptorProto
 		parameter    *string
 		imports      map[pbinfo.ImportSpec]bool
+		wantNumSnps  int
 	}{
 		{
 			tstName: "foo_client_init",
@@ -405,6 +407,7 @@ func TestClientInit(t *testing.T) {
 				{Name: "locationpb", Path: "google.golang.org/genproto/googleapis/cloud/location"}: true,
 				{Name: "mypackagepb", Path: "github.com/googleapis/mypackage"}:                     true,
 			},
+			wantNumSnps: 6,
 		},
 		{
 			tstName: "foo_rest_client_init",
@@ -424,6 +427,7 @@ func TestClientInit(t *testing.T) {
 				{Path: "net/http"}:                                                    true,
 				{Name: "httptransport", Path: "google.golang.org/api/transport/http"}: true,
 			},
+			wantNumSnps: 6,
 		},
 		{
 			tstName:   "empty_client_init",
@@ -441,6 +445,7 @@ func TestClientInit(t *testing.T) {
 				{Name: "mypackagepb", Path: "github.com/googleapis/mypackage"}:        true,
 				{Name: "httptransport", Path: "google.golang.org/api/transport/http"}: true,
 			},
+			wantNumSnps: 1,
 		},
 		{
 			tstName: "lro_client_init",
@@ -460,6 +465,7 @@ func TestClientInit(t *testing.T) {
 				{Path: "google.golang.org/grpc"}:          true,
 				{Path: "google.golang.org/grpc/metadata"}: true,
 			},
+			wantNumSnps: 6,
 		},
 		{
 			tstName:   "deprecated_client_init",
@@ -477,6 +483,7 @@ func TestClientInit(t *testing.T) {
 				{Path: "google.golang.org/grpc/metadata"}:             true,
 				{Path: "net/http"}:                                    true,
 			},
+			wantNumSnps: 1,
 		},
 		{
 			tstName:      "custom_op_init",
@@ -493,6 +500,7 @@ func TestClientInit(t *testing.T) {
 				{Path: "net/http"}:                                                    true,
 				{Name: "httptransport", Path: "google.golang.org/api/transport/http"}: true,
 			},
+			wantNumSnps: 1,
 		},
 	} {
 		fds := append(mixinDescriptors(), &descriptor.FileDescriptorProto{
@@ -539,6 +547,15 @@ func TestClientInit(t *testing.T) {
 		}
 
 		g.reset()
+		sm := snippets.NewMetadata("mypackage", "github.com/googleapis/mypackage", "mypackagego")
+		sm.AddService(tst.serv.GetName(), "mypackage.googleapis.com")
+		for _, m := range tst.serv.GetMethod() {
+			sm.AddMethod(tst.serv.GetName(), m.GetName(), "mypackage", tst.serv.GetName(), 50)
+		}
+		for _, m := range g.getMixinMethods() {
+			sm.AddMethod(tst.serv.GetName(), m.GetName(), "mypackage", tst.serv.GetName(), 50)
+		}
+		g.snippetMetadata = sm
 		g.makeClients(tst.serv, tst.servName)
 
 		if diff := cmp.Diff(g.imports, tst.imports); diff != "" {
@@ -546,6 +563,24 @@ func TestClientInit(t *testing.T) {
 		}
 
 		txtdiff.Diff(t, tst.tstName, g.pt.String(), filepath.Join("testdata", tst.tstName+".want"))
+		mi := g.snippetMetadata.ToMetadataIndex()
+		if got := len(mi.Snippets); got != tst.wantNumSnps {
+			t.Errorf("%s: got %d want len %d", t.Name(), tst.wantNumSnps, got)
+		}
+		for _, snp := range mi.Snippets {
+			if got := snp.ClientMethod.Parameters[0].Name; got != "ctx" {
+				t.Errorf("%s: got %s want ctx,", t.Name(), got)
+			}
+			if got := snp.ClientMethod.Parameters[1].Name; got != "req" {
+				t.Errorf("%s: got %s want req,", t.Name(), got)
+			}
+			if got := snp.ClientMethod.Parameters[2].Name; got != "opts" {
+				t.Errorf("%s: got %s want opts,", t.Name(), got)
+			}
+			if snp.ClientMethod.ShortName != "CancelOperation" && snp.ClientMethod.ShortName != "DeleteOperation" && snp.ClientMethod.ResultType == "" {
+				t.Errorf("%s: got empty string, want ResultType for %s", t.Name(), snp.ClientMethod.ShortName)
+			}
+		}
 	}
 }
 
diff --git a/internal/gengapic/example_test.go b/internal/gengapic/example_test.go
index 7db23ba..974d702 100644
--- a/internal/gengapic/example_test.go
+++ b/internal/gengapic/example_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/golang/protobuf/protoc-gen-go/descriptor"
 	"github.com/google/go-cmp/cmp"
 	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
 	"github.com/googleapis/gapic-generator-go/internal/txtdiff"
 	"google.golang.org/genproto/googleapis/api/annotations"
 	"google.golang.org/genproto/googleapis/api/serviceconfig"
@@ -276,6 +277,88 @@ func TestExample(t *testing.T) {
 	}
 }
 
+func TestGenSnippetFile(t *testing.T) {
+	var g generator
+	g.imports = map[pbinfo.ImportSpec]bool{}
+	g.serviceConfig = &serviceconfig.Service{
+		Apis: []*apipb.Api{
+			{Name: "google.cloud.bigquery.migration.v2.MigrationService"},
+		},
+	}
+
+	protoPkg := "google.cloud.bigquery.migration.v2"
+	libPkg := "cloud.google.com/go/bigquery/migration/apiv2"
+	pkgName := "bigquerymigration"
+	g.snippetMetadata = snippets.NewMetadata(protoPkg, libPkg, pkgName)
+
+	inputType := &descriptor.DescriptorProto{
+		Name: proto.String("CreateMigrationWorkflowRequest"),
+	}
+	outputType := &descriptor.DescriptorProto{
+		Name: proto.String("MigrationWorkflow"),
+	}
+
+	file := &descriptor.FileDescriptorProto{
+		Options: &descriptor.FileOptions{
+			GoPackage: proto.String("cloud.google.com/go/bigquery/migration/apiv2/migrationpb"),
+		},
+		Package: proto.String(protoPkg),
+	}
+
+	files := []*descriptor.FileDescriptorProto{}
+	g.descInfo = pbinfo.Of(files)
+	for _, typ := range []*descriptor.DescriptorProto{
+		inputType, outputType,
+	} {
+		g.descInfo.Type[".google.cloud.bigquery.migration.v2."+typ.GetName()] = typ
+		g.descInfo.ParentFile[typ] = file
+	}
+
+	serv := &descriptor.ServiceDescriptorProto{
+		Name: proto.String("MigrationService"),
+		Method: []*descriptor.MethodDescriptorProto{
+			{
+				Name:       proto.String("CreateMigrationWorkflow"),
+				InputType:  proto.String(".google.cloud.bigquery.migration.v2.CreateMigrationWorkflowRequest"),
+				OutputType: proto.String(".google.cloud.bigquery.migration.v2.MigrationWorkflow"),
+			},
+		},
+	}
+
+	for _, tst := range []struct {
+		tstName string
+		options options
+		imports map[pbinfo.ImportSpec]bool
+	}{
+		{
+			tstName: "snippet",
+			options: options{
+				pkgName:    "migration",
+				transports: []transport{grpc, rest},
+			},
+			imports: map[pbinfo.ImportSpec]bool{
+				{Path: "context"}: true,
+				{Name: "migrationpb", Path: "cloud.google.com/go/bigquery/migration/apiv2/migrationpb"}: true,
+			},
+		},
+	} {
+		g.reset()
+		g.opts = &tst.options
+		defaultHost := "bigquerymigration.googleapis.com"
+		g.snippetMetadata.AddService(serv.GetName(), defaultHost)
+		err := g.genSnippetFile(serv, serv.Method[0])
+		if err != nil {
+			t.Fatal(err)
+		}
+		g.commit(filepath.Join(g.opts.outDir, "temp", "snippets", "main.go"), "main")
+		if diff := cmp.Diff(g.imports, tst.imports); diff != "" {
+			t.Errorf("TestExample(%s): imports got(-),want(+):\n%s", tst.tstName, diff)
+		}
+		got := *g.resp.File[0].Content + *g.resp.File[1].Content
+		txtdiff.Diff(t, tst.tstName, got, filepath.Join("testdata", tst.tstName+".want"))
+	}
+}
+
 func commonTypes(g *generator) {
 	empty := &descriptor.DescriptorProto{
 		Name: proto.String("Empty"),
diff --git a/internal/gengapic/gengapic_test.go b/internal/gengapic/gengapic_test.go
index ba64a15..61a5958 100644
--- a/internal/gengapic/gengapic_test.go
+++ b/internal/gengapic/gengapic_test.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 	"path/filepath"
 	"sort"
+	"strings"
 	"testing"
 
 	longrunning "cloud.google.com/go/longrunning/autogen/longrunningpb"
@@ -26,8 +27,10 @@ import (
 	"github.com/google/go-cmp/cmp"
 	conf "github.com/googleapis/gapic-generator-go/internal/grpc_service_config"
 	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
 	"github.com/googleapis/gapic-generator-go/internal/txtdiff"
 	"google.golang.org/genproto/googleapis/api/annotations"
+	metadatapb "google.golang.org/genproto/googleapis/gapic/metadata"
 	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/runtime/protoiface"
@@ -124,7 +127,9 @@ func TestGRPCClientField(t *testing.T) {
 	}
 }
 
-func TestGenMethod(t *testing.T) {
+// TODO(chrisdsmith): Expand this test to invoke Gen (or at least gen) in gengapic.go,
+// otherwise move it to gengrpc_test.go. (genGRPCMethods was extracted to gengrpc.go on 2021-05-04.)
+func TestGenGRPCMethods(t *testing.T) {
 	extra := &descriptor.DescriptorProto{
 		Name: proto.String("ExtraMessage"),
 		Field: []*descriptor.FieldDescriptorProto{
@@ -306,6 +311,9 @@ func TestGenMethod(t *testing.T) {
 	g.opts = &options{
 		pkgName: "pkg",
 	}
+	g.metadata = &metadatapb.GapicMetadata{
+		Services: make(map[string]*metadatapb.GapicMetadata_ServiceForTransport),
+	}
 	g.mixins = mixins{
 		"google.longrunning.Operations":   operationsMethods(),
 		"google.cloud.location.Locations": locationMethods(),
@@ -485,11 +493,14 @@ methods:
 	} {
 		g.reset()
 		g.descInfo.ParentElement[tst.m] = serv
+		serv.Method = []*descriptor.MethodDescriptorProto{
+			tst.m,
+		}
 
 		g.aux = &auxTypes{
 			iters: map[string]*iterType{},
 		}
-		if err := g.genGRPCMethod("Foo", serv, tst.m); err != nil {
+		if err := g.genGRPCMethods(serv, "Foo"); err != nil {
 			t.Error(err)
 			continue
 		}
@@ -555,13 +566,20 @@ func TestContainsDeprecated(t *testing.T) {
 }
 
 func TestMethodDoc(t *testing.T) {
+	servName := "Foo"
+	methodName := "MyMethod"
 	m := &descriptor.MethodDescriptorProto{
-		Name: proto.String("MyMethod"),
+		Name: proto.String(methodName),
+	}
+	serv := &descriptor.ServiceDescriptorProto{
+		Name: proto.String(servName),
 	}
 
 	g := generator{
 		comments: make(map[protoiface.MessageV1]string),
 	}
+	g.descInfo.ParentElement = map[pbinfo.ProtoType]pbinfo.ProtoType{}
+	g.descInfo.ParentElement[m] = serv
 
 	for _, tst := range []struct {
 		in, want                    string
@@ -573,11 +591,11 @@ func TestMethodDoc(t *testing.T) {
 			want: "",
 		},
 		{
-			in:   "Does stuff.\n It also does other stuffs.",
+			in:   "Does stuff.\nIt also does other stuffs.",
 			want: "// MyMethod does stuff.\n// It also does other stuffs.\n",
 		},
 		{
-			in:         "This is deprecated.\n It does not have a proper comment.",
+			in:         "This is deprecated.\nIt does not have a proper comment.",
 			want:       "// MyMethod this is deprecated.\n// It does not have a proper comment.\n//\n// Deprecated: MyMethod may be removed in a future version.\n",
 			deprecated: true,
 		},
@@ -597,23 +615,39 @@ func TestMethodDoc(t *testing.T) {
 			deprecated: true,
 		},
 		{
-			in:              "Does client streaming stuff.\n It also does other stuffs.",
+			in:              "Does client streaming stuff.\nIt also does other stuffs.",
 			want:            "// MyMethod does client streaming stuff.\n// It also does other stuffs.\n//\n// This method is not supported for the REST transport.\n",
 			clientStreaming: true,
 			opts:            options{transports: []transport{rest}},
 		},
 	} {
 		g.opts = &tst.opts
+		sm := snippets.NewMetadata("mypackage", "github.com/googleapis/mypackage", "mypackagego")
+		sm.AddService(servName, "mypackage.googleapis.com")
+		sm.AddMethod(servName, methodName, "mypackage", servName, 50)
+		g.snippetMetadata = sm
 		g.comments[m] = tst.in
 		m.Options = &descriptor.MethodOptions{
 			Deprecated: proto.Bool(tst.deprecated),
 		}
 		m.ClientStreaming = proto.Bool(tst.clientStreaming)
 		g.pt.Reset()
-		g.methodDoc(m)
+		g.methodDoc(m, serv)
 		if diff := cmp.Diff(g.pt.String(), tst.want); diff != "" {
 			t.Errorf("comment() got(-),want(+):\n%s", diff)
 		}
+		mi := g.snippetMetadata.ToMetadataIndex()
+		if got := len(mi.Snippets); got != 1 {
+			t.Errorf("%s: got %d want 1,", t.Name(), got)
+		}
+		snp := mi.Snippets[0]
+		// remove slashes to compare with snippet description.
+		want := strings.Replace(tst.want, "// ", "", -1)
+		want = strings.Replace(want, "//", "", -1)
+		want = strings.Trim(want, "\n")
+		if got := snp.Description; !tst.clientStreaming && got != want {
+			t.Errorf("%s: got %s want %s", t.Name(), got, want)
+		}
 	}
 }
 
diff --git a/internal/gengapic/imports_test.go b/internal/gengapic/imports_test.go
new file mode 100644
index 0000000..de9f91a
--- /dev/null
+++ b/internal/gengapic/imports_test.go
@@ -0,0 +1,97 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gengapic
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+)
+
+func TestSortImports(t *testing.T) {
+	for _, tst := range []struct {
+		name    string
+		imports []pbinfo.ImportSpec
+		sorted  []pbinfo.ImportSpec
+		want    int
+	}{
+		{
+			name: "foo_foopb",
+			imports: []pbinfo.ImportSpec{
+				{Name: "foopb", Path: "cloud.google.com/go/foopb"},
+				{Name: "foo", Path: "cloud.google.com/go/foo"},
+			},
+			sorted: []pbinfo.ImportSpec{
+				{Name: "foo", Path: "cloud.google.com/go/foo"},
+				{Name: "foopb", Path: "cloud.google.com/go/foopb"},
+			},
+			want: 0,
+		},
+		{
+			name: "context_foo_foopb",
+			imports: []pbinfo.ImportSpec{
+				{Name: "foopb", Path: "cloud.google.com/go/foopb"},
+				{Path: "context"},
+				{Name: "foo", Path: "cloud.google.com/go/foo"},
+			},
+			sorted: []pbinfo.ImportSpec{
+				{Path: "context"},
+				{Name: "foo", Path: "cloud.google.com/go/foo"},
+				{Name: "foopb", Path: "cloud.google.com/go/foopb"},
+			},
+			want: 1,
+		},
+		{
+			name: "context_datacatalog_iampb",
+			imports: []pbinfo.ImportSpec{
+				{Name: "iampb", Path: "google.golang.org/genproto/googleapis/iam/v1"},
+				{Path: "context"},
+				{Name: "datacatalog", Path: "cloud.google.com/go/datacatalog/apiv1beta1"},
+			},
+			sorted: []pbinfo.ImportSpec{
+				{Path: "context"},
+				{Name: "datacatalog", Path: "cloud.google.com/go/datacatalog/apiv1beta1"},
+				{Name: "iampb", Path: "google.golang.org/genproto/googleapis/iam/v1"},
+			},
+			want: 1,
+		},
+		{
+			name: "context_strings_datacatalog_iampb",
+			imports: []pbinfo.ImportSpec{
+				{Path: "strings"},
+				{Name: "iampb", Path: "google.golang.org/genproto/googleapis/iam/v1"},
+				{Path: "context"},
+				{Name: "datacatalog", Path: "cloud.google.com/go/datacatalog/apiv1beta1"},
+			},
+			sorted: []pbinfo.ImportSpec{
+				{Path: "context"},
+				{Path: "strings"},
+				{Name: "datacatalog", Path: "cloud.google.com/go/datacatalog/apiv1beta1"},
+				{Name: "iampb", Path: "google.golang.org/genproto/googleapis/iam/v1"},
+			},
+			want: 2,
+		},
+	} {
+		in := tst.imports
+		got := sortImports(in)
+		if diff := cmp.Diff(tst.imports, tst.sorted); diff != "" {
+			t.Errorf("test %s got(-), want(+):\n%s", tst.name, diff)
+		}
+		if got != tst.want {
+			t.Errorf("test %s got %d, want %d", tst.name, got, tst.want)
+		}
+	}
+}
diff --git a/internal/gengapic/options_test.go b/internal/gengapic/options_test.go
index 031e932..1d21bc6 100644
--- a/internal/gengapic/options_test.go
+++ b/internal/gengapic/options_test.go
@@ -97,6 +97,16 @@ func TestParseOptions(t *testing.T) {
 			},
 			expectErr: false,
 		},
+		{
+			param: "omit-snippets,go-gapic-package=path;pkg",
+			expectedOpts: &options{
+				transports:   []transport{grpc},
+				pkgPath:      "path",
+				pkgName:      "pkg",
+				outDir:       "path",
+				omitSnippets: true,
+			},
+		},
 		{
 			param:     "transport=tcp,go-gapic-package=path;pkg",
 			expectErr: true,
diff --git a/internal/gengapic/snippets_test.go b/internal/gengapic/snippets_test.go
new file mode 100644
index 0000000..c1975cc
--- /dev/null
+++ b/internal/gengapic/snippets_test.go
@@ -0,0 +1,212 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gengapic
+
+import (
+	"fmt"
+	"path/filepath"
+	"testing"
+
+	"github.com/golang/protobuf/protoc-gen-go/descriptor"
+	"github.com/google/go-cmp/cmp"
+	"github.com/googleapis/gapic-generator-go/internal/pbinfo"
+	"github.com/googleapis/gapic-generator-go/internal/snippets"
+	"github.com/googleapis/gapic-generator-go/internal/txtdiff"
+	"google.golang.org/protobuf/proto"
+)
+
+func TestGenAndCommitSnippets(t *testing.T) {
+	inputType := &descriptor.DescriptorProto{
+		Name: proto.String("InputType"),
+		Field: []*descriptor.FieldDescriptorProto{
+			{
+				Name:  proto.String("biz"),
+				Type:  typep(descriptor.FieldDescriptorProto_TYPE_DOUBLE),
+				Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL),
+			},
+		},
+	}
+	outputType := &descriptor.DescriptorProto{
+		Name: proto.String("OutputType"),
+	}
+	pageInputType := &descriptor.DescriptorProto{
+		Name: proto.String("PageInputType"),
+		Field: append(inputType.GetField(), &descriptor.FieldDescriptorProto{
+			Name:  proto.String("page_size"),
+			Type:  typep(descriptor.FieldDescriptorProto_TYPE_INT32),
+			Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL),
+		}, &descriptor.FieldDescriptorProto{
+			Name:  proto.String("page_token"),
+			Type:  typep(descriptor.FieldDescriptorProto_TYPE_STRING),
+			Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL),
+		}),
+	}
+	paginatedField := &descriptor.FieldDescriptorProto{
+		Name:  proto.String("items"),
+		Type:  typep(descriptor.FieldDescriptorProto_TYPE_STRING),
+		Label: labelp(descriptor.FieldDescriptorProto_LABEL_REPEATED),
+	}
+	pageOutputType := &descriptor.DescriptorProto{
+		Name: proto.String("PageOutputType"),
+		Field: []*descriptor.FieldDescriptorProto{
+			{
+				Name:  proto.String("next_page_token"),
+				Type:  typep(descriptor.FieldDescriptorProto_TYPE_STRING),
+				Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL),
+			},
+			paginatedField,
+		},
+	}
+	file := &descriptor.FileDescriptorProto{
+		Package: proto.String("my.pkg"),
+		Options: &descriptor.FileOptions{
+			GoPackage: proto.String("mypackage"),
+		},
+	}
+	serv := &descriptor.ServiceDescriptorProto{
+		Name: proto.String("Foo"),
+	}
+
+	var g generator
+	g.opts = &options{
+		pkgName:    "pkg",
+		transports: []transport{grpc},
+	}
+	// TODO(chrisdsmith): Add a test case below for ListLocations or similar.
+	g.mixins = mixins{
+		"google.longrunning.Operations":   operationsMethods(),
+		"google.cloud.location.Locations": locationMethods(),
+		"google.iam.v1.IAMPolicy":         iamPolicyMethods(),
+	}
+	g.imports = map[pbinfo.ImportSpec]bool{}
+	commonTypes(&g)
+	for _, typ := range []pbinfo.ProtoType{
+		inputType, outputType, pageInputType, pageOutputType,
+	} {
+		g.descInfo.Type[".my.pkg."+typ.GetName()] = typ
+		g.descInfo.ParentFile[typ] = file
+	}
+	g.descInfo.ParentFile[serv] = file
+	g.descInfo.ParentElement = map[pbinfo.ProtoType]pbinfo.ProtoType{
+		paginatedField: pageOutputType,
+	}
+	g.snippetMetadata = snippets.NewMetadata("my.pkg", "github.com/googleapis/mypackage", "pkg")
+
+	for _, tst := range []struct {
+		wantNil bool
+		m       *descriptor.MethodDescriptorProto
+		imports map[pbinfo.ImportSpec]bool
+	}{
+		{
+			m: &descriptor.MethodDescriptorProto{
+				Name:       proto.String("GetEmptyThing"),
+				InputType:  proto.String(".my.pkg.InputType"),
+				OutputType: proto.String(emptyType),
+			},
+			imports: map[pbinfo.ImportSpec]bool{
+				{Path: "context"}:                        true,
+				{Name: "mypackagepb", Path: "mypackage"}: true,
+				{Name: "pkg"}:                            true,
+			},
+		},
+		{
+			m: &descriptor.MethodDescriptorProto{
+				Name:       proto.String("GetOneThing"),
+				InputType:  proto.String(".my.pkg.InputType"),
+				OutputType: proto.String(".my.pkg.OutputType"),
+			},
+			imports: map[pbinfo.ImportSpec]bool{
+				{Path: "context"}:                        true,
+				{Name: "mypackagepb", Path: "mypackage"}: true,
+				{Name: "pkg"}:                            true,
+			},
+		},
+		{
+			m: &descriptor.MethodDescriptorProto{
+				Name:       proto.String("GetManyThings"),
+				InputType:  proto.String(".my.pkg.PageInputType"),
+				OutputType: proto.String(".my.pkg.PageOutputType"),
+			},
+			imports: map[pbinfo.ImportSpec]bool{
+				{Path: "context"}:                        true,
+				{Path: "google.golang.org/api/iterator"}: true,
+				{Name: "mypackagepb", Path: "mypackage"}: true,
+				{Name: "pkg"}:                            true,
+			},
+		},
+		{
+			// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODOs.
+			wantNil: true,
+			m: &descriptor.MethodDescriptorProto{
+				Name:            proto.String("ServerThings"),
+				InputType:       proto.String(".my.pkg.InputType"),
+				OutputType:      proto.String(".my.pkg.OutputType"),
+				ServerStreaming: proto.Bool(true),
+			},
+			imports: map[pbinfo.ImportSpec]bool{},
+		},
+		{
+			// TODO(chrisdsmith): implement streaming examples correctly, see example.go TODOs.
+			wantNil: true,
+			m: &descriptor.MethodDescriptorProto{
+				Name:            proto.String("ClientThings"),
+				InputType:       proto.String(".my.pkg.InputType"),
+				OutputType:      proto.String(".my.pkg.OutputType"),
+				ClientStreaming: proto.Bool(true),
+			},
+			imports: map[pbinfo.ImportSpec]bool{},
+		},
+		{
+			m: &descriptor.MethodDescriptorProto{
+				Name:            proto.String("BidiThings"),
+				InputType:       proto.String(".my.pkg.InputType"),
+				OutputType:      proto.String(".my.pkg.OutputType"),
+				ServerStreaming: proto.Bool(true),
+				ClientStreaming: proto.Bool(true),
+			},
+			imports: map[pbinfo.ImportSpec]bool{
+				{Path: "context"}:                        true,
+				{Path: "io"}:                             true,
+				{Name: "mypackagepb", Path: "mypackage"}: true,
+				{Name: "pkg"}:                            true,
+			},
+		},
+	} {
+		g.reset()
+		g.descInfo.ParentElement[tst.m] = serv
+		serv.Method = []*descriptor.MethodDescriptorProto{
+			tst.m,
+		}
+		g.aux = &auxTypes{
+			iters: map[string]*iterType{},
+		}
+
+		if err := g.genAndCommitSnippets(serv); err != nil {
+			t.Error(err)
+			continue
+		}
+
+		if diff := cmp.Diff(g.imports, tst.imports); diff != "" {
+			t.Errorf("TestGenAndCommitSnippets(%s): imports got(-),want(+):\n%s", tst.m.GetName(), diff)
+		}
+		if !tst.wantNil {
+			wantRegionTag := fmt.Sprintf("// [START _pkg_generated_Foo_%s_sync]\n", tst.m.GetName())
+			if g.headerComments.String() != wantRegionTag {
+				t.Errorf("TestGenAndCommitSnippets(%s): got %s, want %s", tst.m.GetName(), g.headerComments.String(), wantRegionTag)
+			}
+			txtdiff.Diff(t, tst.m.GetName(), g.pt.String(), filepath.Join("testdata", "snippet_"+tst.m.GetName()+".want"))
+		}
+	}
+}
diff --git a/internal/gengapic/testdata/snippet.want b/internal/gengapic/testdata/snippet.want
new file mode 100644
index 0000000..2275e0d
--- /dev/null
+++ b/internal/gengapic/testdata/snippet.want
@@ -0,0 +1,52 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
+
+// [START bigquerymigration_v2_generated_MigrationService_CreateMigrationWorkflow_sync]
+
+package main
+
+import (
+	"context"
+
+	migrationpb "cloud.google.com/go/bigquery/migration/apiv2/migrationpb"
+)
+
+func main() {
+	ctx := context.Background()
+	// This snippet has been automatically generated and should be regarded as a code template only.
+	// It will require modifications to work:
+	// - It may require correct/in-range values for request initialization.
+	// - It may require specifying regional endpoints when creating the service client as shown in:
+	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+	c, err := migration.NewClient(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	defer c.Close()
+
+	req := &migrationpb.CreateMigrationWorkflowRequest{
+		// TODO: Fill request struct fields.
+		// See https://pkg.go.dev/cloud.google.com/go/bigquery/migration/apiv2/migrationpb#CreateMigrationWorkflowRequest.
+	}
+	resp, err := c.CreateMigrationWorkflow(ctx, req)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	// TODO: Use resp.
+	_ = resp
+}
+
+// [END bigquerymigration_v2_generated_MigrationService_CreateMigrationWorkflow_sync]
diff --git a/internal/gengapic/testdata/snippet_BidiThings.want b/internal/gengapic/testdata/snippet_BidiThings.want
new file mode 100644
index 0000000..e6b3fd2
--- /dev/null
+++ b/internal/gengapic/testdata/snippet_BidiThings.want
@@ -0,0 +1,41 @@
+func main() {
+	ctx := context.Background()
+	// This snippet has been automatically generated and should be regarded as a code template only.
+	// It will require modifications to work:
+	// - It may require correct/in-range values for request initialization.
+	// - It may require specifying regional endpoints when creating the service client as shown in:
+	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+	c, err := pkg.NewFooClient(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	defer c.Close()
+	stream, err := c.BidiThings(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	go func() {
+		reqs := []*mypackagepb.InputType{
+			// TODO: Create requests.
+		}
+		for _, req := range reqs {
+			if err := stream.Send(req); err != nil {
+				// TODO: Handle error.
+			}
+		}
+		stream.CloseSend()
+	}()
+	for {
+		resp, err := stream.Recv()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			// TODO: handle error.
+		}
+		// TODO: Use resp.
+		_ = resp
+	}
+}
+
+// [END _pkg_generated_Foo_BidiThings_sync]
diff --git a/internal/gengapic/testdata/snippet_GetEmptyThing.want b/internal/gengapic/testdata/snippet_GetEmptyThing.want
new file mode 100644
index 0000000..76fd688
--- /dev/null
+++ b/internal/gengapic/testdata/snippet_GetEmptyThing.want
@@ -0,0 +1,24 @@
+func main() {
+	ctx := context.Background()
+	// This snippet has been automatically generated and should be regarded as a code template only.
+	// It will require modifications to work:
+	// - It may require correct/in-range values for request initialization.
+	// - It may require specifying regional endpoints when creating the service client as shown in:
+	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+	c, err := pkg.NewFooClient(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	defer c.Close()
+
+	req := &mypackagepb.InputType{
+		// TODO: Fill request struct fields.
+		// See https://pkg.go.dev/mypackage#InputType.
+	}
+	err = c.GetEmptyThing(ctx, req)
+	if err != nil {
+		// TODO: Handle error.
+	}
+}
+
+// [END _pkg_generated_Foo_GetEmptyThing_sync]
diff --git a/internal/gengapic/testdata/snippet_GetManyThings.want b/internal/gengapic/testdata/snippet_GetManyThings.want
new file mode 100644
index 0000000..d0eb6d6
--- /dev/null
+++ b/internal/gengapic/testdata/snippet_GetManyThings.want
@@ -0,0 +1,32 @@
+func main() {
+	ctx := context.Background()
+	// This snippet has been automatically generated and should be regarded as a code template only.
+	// It will require modifications to work:
+	// - It may require correct/in-range values for request initialization.
+	// - It may require specifying regional endpoints when creating the service client as shown in:
+	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+	c, err := pkg.NewFooClient(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	defer c.Close()
+
+	req := &mypackagepb.PageInputType{
+		// TODO: Fill request struct fields.
+		// See https://pkg.go.dev/mypackage#PageInputType.
+	}
+	it := c.GetManyThings(ctx, req)
+	for {
+		resp, err := it.Next()
+		if err == iterator.Done {
+			break
+		}
+		if err != nil {
+			// TODO: Handle error.
+		}
+		// TODO: Use resp.
+		_ = resp
+	}
+}
+
+// [END _pkg_generated_Foo_GetManyThings_sync]
diff --git a/internal/gengapic/testdata/snippet_GetOneThing.want b/internal/gengapic/testdata/snippet_GetOneThing.want
new file mode 100644
index 0000000..dc205d1
--- /dev/null
+++ b/internal/gengapic/testdata/snippet_GetOneThing.want
@@ -0,0 +1,26 @@
+func main() {
+	ctx := context.Background()
+	// This snippet has been automatically generated and should be regarded as a code template only.
+	// It will require modifications to work:
+	// - It may require correct/in-range values for request initialization.
+	// - It may require specifying regional endpoints when creating the service client as shown in:
+	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
+	c, err := pkg.NewFooClient(ctx)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	defer c.Close()
+
+	req := &mypackagepb.InputType{
+		// TODO: Fill request struct fields.
+		// See https://pkg.go.dev/mypackage#InputType.
+	}
+	resp, err := c.GetOneThing(ctx, req)
+	if err != nil {
+		// TODO: Handle error.
+	}
+	// TODO: Use resp.
+	_ = resp
+}
+
+// [END _pkg_generated_Foo_GetOneThing_sync]
diff --git a/internal/snippets/snippets_test.go b/internal/snippets/snippets_test.go
new file mode 100644
index 0000000..4d22427
--- /dev/null
+++ b/internal/snippets/snippets_test.go
@@ -0,0 +1,156 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package snippets
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/googleapis/gapic-generator-go/internal/snippets/metadata"
+	"google.golang.org/protobuf/proto"
+)
+
+var protoPkg = "google.cloud.bigquery.migration.v2"
+var libPkg = "cloud.google.com/go/bigquery/migration/apiv2"
+var defaultHost = "bigquerymigration.googleapis.com"
+var version = "v2"
+var pkgName = "migration"
+
+func TestNewMetadata(t *testing.T) {
+	sm := NewMetadata(protoPkg, libPkg, pkgName)
+
+	if sm.protoPkg != protoPkg {
+		t.Errorf("%s: got %s want %s,", t.Name(), sm.protoPkg, protoPkg)
+	}
+	if sm.libPkg != libPkg {
+		t.Errorf("%s: got %s want %s", t.Name(), sm.libPkg, libPkg)
+	}
+	if got := len(sm.protoServices); got != 0 {
+		t.Errorf("%s: got %d want empty", t.Name(), len(sm.protoServices))
+	}
+	if sm.apiVersion != version {
+		t.Errorf("%s: got %s want %s", t.Name(), sm.apiVersion, version)
+	}
+}
+
+func TestToMetadataJSON(t *testing.T) {
+	// Build fixture
+	sm := NewMetadata(protoPkg, libPkg, pkgName)
+	regionTagStart := 18
+	regionTagEnd := 50
+	for i := 0; i < 2; i++ {
+		serviceName := fmt.Sprintf("Foo%dService", i)
+		methodName := fmt.Sprintf("Bar%dMethod", i)
+		sm.AddService(serviceName, defaultHost)
+		sm.AddMethod(serviceName, methodName, protoPkg, serviceName, regionTagEnd)
+		sm.UpdateMethodDoc(serviceName, methodName, methodName+" doc\n New line.")
+		sm.UpdateMethodResult(serviceName, methodName, "mypackage."+methodName+"Result")
+		sm.AddParams(serviceName, methodName, "mypackage."+methodName+"Request")
+	}
+
+	// Build expectation
+	want := &metadata.Index{
+		ClientLibrary: &metadata.ClientLibrary{
+			Name:     libPkg,
+			Version:  VersionPlaceholder,
+			Language: metadata.Language_GO,
+			Apis: []*metadata.Api{
+				{
+					Id:      protoPkg,
+					Version: "v2",
+				},
+			},
+		},
+	}
+	for i := 0; i < 2; i++ {
+		snp := &metadata.Snippet{
+			RegionTag:   fmt.Sprintf("bigquerymigration_v2_generated_Foo%dService_Bar%dMethod_sync", i, i),
+			Title:       fmt.Sprintf("bigquerymigration Bar%dMethod Sample", i),
+			Description: fmt.Sprintf("Bar%dMethod doc\nNew line.", i),
+			File:        fmt.Sprintf("Foo%dClient/Bar%dMethod/main.go", i, i),
+			Language:    metadata.Language_GO,
+			Canonical:   false,
+			Origin:      *metadata.Snippet_API_DEFINITION.Enum(),
+			ClientMethod: &metadata.ClientMethod{
+				ShortName:  fmt.Sprintf("Bar%dMethod", i),
+				FullName:   fmt.Sprintf("google.cloud.bigquery.migration.v2.Foo%dClient.Bar%dMethod", i, i),
+				Async:      false,
+				ResultType: fmt.Sprintf("mypackage.Bar%dMethodResult", i),
+				Client: &metadata.ServiceClient{
+					ShortName: fmt.Sprintf("Foo%dClient", i),
+					FullName:  fmt.Sprintf("google.cloud.bigquery.migration.v2.Foo%dClient", i),
+				},
+				Method: &metadata.Method{
+					ShortName: fmt.Sprintf("Bar%dMethod", i),
+					FullName:  fmt.Sprintf("google.cloud.bigquery.migration.v2.Foo%dService.Bar%dMethod", i, i),
+					Service: &metadata.Service{
+						ShortName: fmt.Sprintf("Foo%dService", i),
+						FullName:  fmt.Sprintf("google.cloud.bigquery.migration.v2.Foo%dService", i),
+					},
+				},
+				Parameters: []*metadata.ClientMethod_Parameter{
+					{
+						Type: "context.Context",
+						Name: "ctx",
+					},
+					{
+						Type: fmt.Sprintf("mypackage.Bar%dMethodRequest", i),
+						Name: "req",
+					},
+					{
+						Type: "...gax.CallOption",
+						Name: "opts",
+					},
+				},
+			},
+			Segments: []*metadata.Snippet_Segment{
+				{
+					Start: int32(regionTagStart),
+					End:   int32(regionTagEnd - 1),
+					Type:  metadata.Snippet_Segment_FULL,
+				},
+			},
+		}
+		want.Snippets = append(want.Snippets, snp)
+	}
+
+	mi := sm.ToMetadataIndex()
+	if diff := cmp.Diff(mi, want, cmp.Comparer(proto.Equal)); diff != "" {
+		t.Errorf("ToMetadataIndex(): got(-),want(+):\n%s", diff)
+	}
+
+	json, err := sm.ToMetadataJSON()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if got := len(json); got == 0 {
+		t.Errorf("%s: got len 0, want non-empty []byte", t.Name())
+	}
+}
+
+func TestRegionTag(t *testing.T) {
+	protoPkg := "google.cloud.bigquery.migration.v2"
+	libPkg := "google.golang.org/genproto/googleapis/cloud/bigquery/migration/v2"
+	sm := NewMetadata(protoPkg, libPkg, pkgName)
+	serviceName := "MigrationService"
+	defaultHost := "bigquerymigration.googleapis.com"
+	sm.AddService(serviceName, defaultHost)
+	methodName := "GetMigrationWorkflow"
+	want := "bigquerymigration_v2_generated_MigrationService_GetMigrationWorkflow_sync"
+	if got := sm.RegionTag(serviceName, methodName); got != want {
+		t.Errorf("%s: got %s want %s", t.Name(), got, want)
+	}
+}
diff --git a/test.sh b/test.sh
index 90af934..1bbcf96 100755
--- a/test.sh
+++ b/test.sh
@@ -37,7 +37,7 @@ generate() {
 }
 
 echo "Generating Cloud KMS v1 - gRPC"
-generate --go_gapic_opt 'go-gapic-package=cloud.google.com/go/kms/apiv1;kms,transport=grpc' $GOOGLEAPIS/google/cloud/kms/v1/*.proto
+generate --go_gapic_opt "go-gapic-package=cloud.google.com/go/kms/apiv1;kms,transport=grpc,api-service-config=$GOOGLEAPIS/google/cloud/kms/v1/cloudkms_v1.yaml" $GOOGLEAPIS/google/cloud/kms/v1/*.proto
 
 echo "Generating Cloud Data Catalog v1beta1 - REST"
 generate --go_gapic_opt 'go-gapic-package=cloud.google.com/go/datacatalog/apiv1beta1;datacatalog,transport=rest' $GOOGLEAPIS/google/cloud/datacatalog/v1beta1/*.proto