diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index f4cc2ba40c2..940be4691f5 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -19,7 +19,10 @@
       "bazel.buildifierExecutable": "/go/bin/buildifier",
       "bazel.buildifierFixOnFormat": true,
       "bazel.enableCodeLens": true,
-      "extensions": ["golang.Go", "bazelbuild.vscode-bazel"]
+      "extensions": [
+        "golang.Go",
+        "bazelbuild.vscode-bazel"
+      ]
     }
   }
-}
+}
\ No newline at end of file
diff --git a/Makefile b/Makefile
index c8791a64f37..2ba12195685 100644
--- a/Makefile
+++ b/Makefile
@@ -151,6 +151,10 @@ proto:
 		--template ./protoc-gen-openapiv2/options/buf.gen.yaml \
 		--path ./protoc-gen-openapiv2/options/annotations.proto \
 		--path ./protoc-gen-openapiv2/options/openapiv2.proto
+	buf generate \
+		--template ./protoc-gen-openapiv3/options/buf.gen.yaml \
+		--path ./protoc-gen-openapiv3/options/annotations.proto \
+		--path ./protoc-gen-openapiv3/options/openapiv3.proto
 
 generate: proto $(ECHO_EXAMPLE_SRCS) $(ABE_EXAMPLE_SRCS) $(UNANNOTATED_ECHO_EXAMPLE_SRCS) $(RESPONSE_BODY_EXAMPLE_SRCS) $(GENERATE_UNBOUND_METHODS_EXAMPLE_SRCS)
 
diff --git a/internal/descriptor/BUILD.bazel b/internal/descriptor/BUILD.bazel
index 28b6e25834b..145b1cf75f7 100644
--- a/internal/descriptor/BUILD.bazel
+++ b/internal/descriptor/BUILD.bazel
@@ -17,8 +17,10 @@ go_library(
         "//internal/codegenerator",
         "//internal/descriptor/apiconfig",
         "//internal/descriptor/openapiconfig",
+        "//internal/descriptor/openapiconfigv3:openapiconfig",
         "//internal/httprule",
         "//protoc-gen-openapiv2/options",
+        "//protoc-gen-openapiv3/options",
         "@in_gopkg_yaml_v3//:yaml_v3",
         "@org_golang_google_genproto_googleapis_api//annotations",
         "@org_golang_google_grpc//grpclog",
diff --git a/internal/descriptor/openapiconfigv3/BUILD.bazel b/internal/descriptor/openapiconfigv3/BUILD.bazel
new file mode 100644
index 00000000000..2fdba650d89
--- /dev/null
+++ b/internal/descriptor/openapiconfigv3/BUILD.bazel
@@ -0,0 +1,32 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+proto_library(
+    name = "openapiconfig_proto",
+    srcs = ["openapiconfig.proto"],
+    visibility = ["//:__subpackages__"],
+    deps = ["//protoc-gen-openapiv3/options:options_proto"],
+)
+
+go_proto_library(
+    name = "openapiconfig_go_proto",
+    compilers = ["//:go_apiv2"],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfigv3",
+    proto = ":openapiconfig_proto",
+    visibility = ["//:__subpackages__"],
+    deps = ["//protoc-gen-openapiv3/options"],
+)
+
+go_library(
+    name = "openapiconfig",
+    embed = [":openapiconfig_go_proto"],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfigv3",
+    visibility = ["//:__subpackages__"],
+)
+
+alias(
+    name = "go_default_library",
+    actual = ":openapiconfigv3",
+    visibility = ["//:__subpackages__"],
+)
diff --git a/internal/descriptor/openapiconfigv3/openapiconfig.pb.go b/internal/descriptor/openapiconfigv3/openapiconfig.pb.go
new file mode 100644
index 00000000000..4c700b32fda
--- /dev/null
+++ b/internal/descriptor/openapiconfigv3/openapiconfig.pb.go
@@ -0,0 +1,584 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.35.1
+// 	protoc        (unknown)
+// source: internal/descriptor/openapiconfigv3/openapiconfig.proto
+
+package openapiconfigv3
+
+import (
+	options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options"
+	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)
+)
+
+// OpenAPIFileOption represents OpenAPI options on a file
+type OpenAPIFileOption struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	File   string           `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
+	Option *options.Swagger `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"`
+}
+
+func (x *OpenAPIFileOption) Reset() {
+	*x = OpenAPIFileOption{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIFileOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIFileOption) ProtoMessage() {}
+
+func (x *OpenAPIFileOption) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIFileOption.ProtoReflect.Descriptor instead.
+func (*OpenAPIFileOption) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *OpenAPIFileOption) GetFile() string {
+	if x != nil {
+		return x.File
+	}
+	return ""
+}
+
+func (x *OpenAPIFileOption) GetOption() *options.Swagger {
+	if x != nil {
+		return x.Option
+	}
+	return nil
+}
+
+// OpenAPIMethodOption represents OpenAPI options on a method
+type OpenAPIMethodOption struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Method string             `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
+	Option *options.Operation `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"`
+}
+
+func (x *OpenAPIMethodOption) Reset() {
+	*x = OpenAPIMethodOption{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIMethodOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIMethodOption) ProtoMessage() {}
+
+func (x *OpenAPIMethodOption) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIMethodOption.ProtoReflect.Descriptor instead.
+func (*OpenAPIMethodOption) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *OpenAPIMethodOption) GetMethod() string {
+	if x != nil {
+		return x.Method
+	}
+	return ""
+}
+
+func (x *OpenAPIMethodOption) GetOption() *options.Operation {
+	if x != nil {
+		return x.Option
+	}
+	return nil
+}
+
+// OpenAPIMessageOption represents OpenAPI options on a message
+type OpenAPIMessageOption struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message string          `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Option  *options.Schema `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"`
+}
+
+func (x *OpenAPIMessageOption) Reset() {
+	*x = OpenAPIMessageOption{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIMessageOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIMessageOption) ProtoMessage() {}
+
+func (x *OpenAPIMessageOption) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIMessageOption.ProtoReflect.Descriptor instead.
+func (*OpenAPIMessageOption) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *OpenAPIMessageOption) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *OpenAPIMessageOption) GetOption() *options.Schema {
+	if x != nil {
+		return x.Option
+	}
+	return nil
+}
+
+// OpenAPIServiceOption represents OpenAPI options on a service
+type OpenAPIServiceOption struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Service string       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // ex: Service
+	Option  *options.Tag `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"`
+}
+
+func (x *OpenAPIServiceOption) Reset() {
+	*x = OpenAPIServiceOption{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIServiceOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIServiceOption) ProtoMessage() {}
+
+func (x *OpenAPIServiceOption) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIServiceOption.ProtoReflect.Descriptor instead.
+func (*OpenAPIServiceOption) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *OpenAPIServiceOption) GetService() string {
+	if x != nil {
+		return x.Service
+	}
+	return ""
+}
+
+func (x *OpenAPIServiceOption) GetOption() *options.Tag {
+	if x != nil {
+		return x.Option
+	}
+	return nil
+}
+
+// OpenAPIFieldOption represents OpenAPI options on a field
+type OpenAPIFieldOption struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Field  string              `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"`
+	Option *options.JSONSchema `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"`
+}
+
+func (x *OpenAPIFieldOption) Reset() {
+	*x = OpenAPIFieldOption{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIFieldOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIFieldOption) ProtoMessage() {}
+
+func (x *OpenAPIFieldOption) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIFieldOption.ProtoReflect.Descriptor instead.
+func (*OpenAPIFieldOption) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *OpenAPIFieldOption) GetField() string {
+	if x != nil {
+		return x.Field
+	}
+	return ""
+}
+
+func (x *OpenAPIFieldOption) GetOption() *options.JSONSchema {
+	if x != nil {
+		return x.Option
+	}
+	return nil
+}
+
+// OpenAPIOptions represents OpenAPI protobuf options
+type OpenAPIOptions struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	File    []*OpenAPIFileOption    `protobuf:"bytes,1,rep,name=file,proto3" json:"file,omitempty"`
+	Method  []*OpenAPIMethodOption  `protobuf:"bytes,2,rep,name=method,proto3" json:"method,omitempty"`
+	Message []*OpenAPIMessageOption `protobuf:"bytes,3,rep,name=message,proto3" json:"message,omitempty"`
+	Service []*OpenAPIServiceOption `protobuf:"bytes,4,rep,name=service,proto3" json:"service,omitempty"`
+	Field   []*OpenAPIFieldOption   `protobuf:"bytes,5,rep,name=field,proto3" json:"field,omitempty"`
+}
+
+func (x *OpenAPIOptions) Reset() {
+	*x = OpenAPIOptions{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIOptions) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIOptions) ProtoMessage() {}
+
+func (x *OpenAPIOptions) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIOptions.ProtoReflect.Descriptor instead.
+func (*OpenAPIOptions) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *OpenAPIOptions) GetFile() []*OpenAPIFileOption {
+	if x != nil {
+		return x.File
+	}
+	return nil
+}
+
+func (x *OpenAPIOptions) GetMethod() []*OpenAPIMethodOption {
+	if x != nil {
+		return x.Method
+	}
+	return nil
+}
+
+func (x *OpenAPIOptions) GetMessage() []*OpenAPIMessageOption {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *OpenAPIOptions) GetService() []*OpenAPIServiceOption {
+	if x != nil {
+		return x.Service
+	}
+	return nil
+}
+
+func (x *OpenAPIOptions) GetField() []*OpenAPIFieldOption {
+	if x != nil {
+		return x.Field
+	}
+	return nil
+}
+
+// OpenAPIConfig represents a set of OpenAPI options
+type OpenAPIConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	OpenapiOptions *OpenAPIOptions `protobuf:"bytes,1,opt,name=openapi_options,json=openapiOptions,proto3" json:"openapi_options,omitempty"`
+}
+
+func (x *OpenAPIConfig) Reset() {
+	*x = OpenAPIConfig{}
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenAPIConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenAPIConfig) ProtoMessage() {}
+
+func (x *OpenAPIConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenAPIConfig.ProtoReflect.Descriptor instead.
+func (*OpenAPIConfig) Descriptor() ([]byte, []int) {
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *OpenAPIConfig) GetOpenapiOptions() *OpenAPIOptions {
+	if x != nil {
+		return x.OpenapiOptions
+	}
+	return nil
+}
+
+var File_internal_descriptor_openapiconfigv3_openapiconfig_proto protoreflect.FileDescriptor
+
+var file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDesc = []byte{
+	0x0a, 0x37, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x30, 0x67, 0x72, 0x70, 0x63, 0x2e,
+	0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
+	0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76, 0x33, 0x1a, 0x2c, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x11, 0x4f, 0x70, 0x65,
+	0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12,
+	0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69,
+	0x6c, 0x65, 0x12, 0x4a, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53,
+	0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7b,
+	0x0a, 0x13, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x4c, 0x0a,
+	0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7b, 0x0a, 0x14, 0x4f,
+	0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x49, 0x0a,
+	0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x78, 0x0a, 0x14, 0x4f, 0x70, 0x65, 0x6e,
+	0x41, 0x50, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x22, 0x79, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c,
+	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x4d,
+	0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69,
+	0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xe8, 0x03,
+	0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x12, 0x57, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
+	0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76,
+	0x33, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x5d, 0x0a, 0x06, 0x6d, 0x65, 0x74,
+	0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+	0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76, 0x33, 0x2e, 0x4f, 0x70, 0x65,
+	0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x60, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+	0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76, 0x33, 0x2e, 0x4f, 0x70, 0x65,
+	0x6e, 0x41, 0x50, 0x49, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x60, 0x0a, 0x07, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
+	0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76, 0x33, 0x2e, 0x4f,
+	0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x05,
+	0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
+	0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x76, 0x33, 0x2e, 0x4f,
+	0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x7a, 0x0a, 0x0d, 0x4f, 0x70, 0x65, 0x6e,
+	0x41, 0x50, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x0f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x76, 0x33, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x50, 0x49, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+	0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65,
+	0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x76,
+	0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x76, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescOnce sync.Once
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescData = file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDesc
+)
+
+func file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescGZIP() []byte {
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescOnce.Do(func() {
+		file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescData)
+	})
+	return file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDescData
+}
+
+var file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
+var file_internal_descriptor_openapiconfigv3_openapiconfig_proto_goTypes = []any{
+	(*OpenAPIFileOption)(nil),    // 0: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFileOption
+	(*OpenAPIMethodOption)(nil),  // 1: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMethodOption
+	(*OpenAPIMessageOption)(nil), // 2: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMessageOption
+	(*OpenAPIServiceOption)(nil), // 3: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIServiceOption
+	(*OpenAPIFieldOption)(nil),   // 4: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFieldOption
+	(*OpenAPIOptions)(nil),       // 5: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions
+	(*OpenAPIConfig)(nil),        // 6: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIConfig
+	(*options.Swagger)(nil),      // 7: grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	(*options.Operation)(nil),    // 8: grpc.gateway.protoc_gen_openapiv3.options.Operation
+	(*options.Schema)(nil),       // 9: grpc.gateway.protoc_gen_openapiv3.options.Schema
+	(*options.Tag)(nil),          // 10: grpc.gateway.protoc_gen_openapiv3.options.Tag
+	(*options.JSONSchema)(nil),   // 11: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+}
+var file_internal_descriptor_openapiconfigv3_openapiconfig_proto_depIdxs = []int32{
+	7,  // 0: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFileOption.option:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	8,  // 1: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMethodOption.option:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation
+	9,  // 2: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMessageOption.option:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Schema
+	10, // 3: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIServiceOption.option:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag
+	11, // 4: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFieldOption.option:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	0,  // 5: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions.file:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFileOption
+	1,  // 6: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions.method:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMethodOption
+	2,  // 7: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions.message:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIMessageOption
+	3,  // 8: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions.service:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIServiceOption
+	4,  // 9: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions.field:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIFieldOption
+	5,  // 10: grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIConfig.openapi_options:type_name -> grpc.gateway.internal.descriptor.openapiconfigv3.OpenAPIOptions
+	11, // [11:11] is the sub-list for method output_type
+	11, // [11:11] is the sub-list for method input_type
+	11, // [11:11] is the sub-list for extension type_name
+	11, // [11:11] is the sub-list for extension extendee
+	0,  // [0:11] is the sub-list for field type_name
+}
+
+func init() { file_internal_descriptor_openapiconfigv3_openapiconfig_proto_init() }
+func file_internal_descriptor_openapiconfigv3_openapiconfig_proto_init() {
+	if File_internal_descriptor_openapiconfigv3_openapiconfig_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   7,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_internal_descriptor_openapiconfigv3_openapiconfig_proto_goTypes,
+		DependencyIndexes: file_internal_descriptor_openapiconfigv3_openapiconfig_proto_depIdxs,
+		MessageInfos:      file_internal_descriptor_openapiconfigv3_openapiconfig_proto_msgTypes,
+	}.Build()
+	File_internal_descriptor_openapiconfigv3_openapiconfig_proto = out.File
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_rawDesc = nil
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_goTypes = nil
+	file_internal_descriptor_openapiconfigv3_openapiconfig_proto_depIdxs = nil
+}
diff --git a/internal/descriptor/openapiconfigv3/openapiconfig.proto b/internal/descriptor/openapiconfigv3/openapiconfig.proto
new file mode 100644
index 00000000000..0ef2d290de3
--- /dev/null
+++ b/internal/descriptor/openapiconfigv3/openapiconfig.proto
@@ -0,0 +1,51 @@
+syntax = "proto3";
+
+package grpc.gateway.internal.descriptor.openapiconfigv3;
+
+import "protoc-gen-openapiv3/options/openapiv3.proto";
+
+option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfigv3";
+
+// OpenAPIFileOption represents OpenAPI options on a file
+message OpenAPIFileOption {
+  string file = 1;
+  grpc.gateway.protoc_gen_openapiv3.options.Swagger option = 2;
+}
+
+// OpenAPIMethodOption represents OpenAPI options on a method
+message OpenAPIMethodOption {
+  string method = 1;
+  grpc.gateway.protoc_gen_openapiv3.options.Operation option = 2;
+}
+
+// OpenAPIMessageOption represents OpenAPI options on a message
+message OpenAPIMessageOption {
+  string message = 1;
+  grpc.gateway.protoc_gen_openapiv3.options.Schema option = 2;
+}
+
+// OpenAPIServiceOption represents OpenAPI options on a service
+message OpenAPIServiceOption {
+  string service = 1; // ex: Service
+  grpc.gateway.protoc_gen_openapiv3.options.Tag option = 2;
+}
+
+// OpenAPIFieldOption represents OpenAPI options on a field
+message OpenAPIFieldOption {
+  string field = 1;
+  grpc.gateway.protoc_gen_openapiv3.options.JSONSchema option = 2;
+}
+
+// OpenAPIOptions represents OpenAPI protobuf options
+message OpenAPIOptions {
+  repeated OpenAPIFileOption file = 1;
+  repeated OpenAPIMethodOption method = 2;
+  repeated OpenAPIMessageOption message = 3;
+  repeated OpenAPIServiceOption service = 4;
+  repeated OpenAPIFieldOption field = 5;
+}
+
+// OpenAPIConfig represents a set of OpenAPI options
+message OpenAPIConfig {
+  OpenAPIOptions openapi_options = 1;
+}
diff --git a/internal/descriptor/openapiconfigv3/openapiconfig.swagger.json b/internal/descriptor/openapiconfigv3/openapiconfig.swagger.json
new file mode 100644
index 00000000000..6517bd1a2fa
--- /dev/null
+++ b/internal/descriptor/openapiconfigv3/openapiconfig.swagger.json
@@ -0,0 +1,44 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "internal/descriptor/openapiconfigv3/openapiconfig.proto",
+    "version": "version not set"
+  },
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {},
+  "definitions": {
+    "protobufAny": {
+      "type": "object",
+      "properties": {
+        "@type": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": {}
+    },
+    "rpcStatus": {
+      "type": "object",
+      "properties": {
+        "code": {
+          "type": "integer",
+          "format": "int32"
+        },
+        "message": {
+          "type": "string"
+        },
+        "details": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "$ref": "#/definitions/protobufAny"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/internal/descriptor/registry.go b/internal/descriptor/registry.go
index 743cea8f126..0f7955eb8f9 100644
--- a/internal/descriptor/registry.go
+++ b/internal/descriptor/registry.go
@@ -7,7 +7,9 @@ import (
 
 	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator"
 	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfigv3"
 	"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
+	optionsv3 "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options"
 	"golang.org/x/text/cases"
 	"golang.org/x/text/language"
 	"google.golang.org/genproto/googleapis/api/annotations"
@@ -132,6 +134,22 @@ type Registry struct {
 	// field name and a period to additional OpenAPI field options
 	fieldOptions map[string]*options.JSONSchema
 
+	// fileOptions is a mapping of file name to additional OpenAPI file options
+	fileOptionsv3 map[string]*optionsv3.Swagger
+
+	// methodOptions is a mapping of fully-qualified method name to additional OpenAPI method options
+	methodOptionsv3 map[string]*optionsv3.Operation
+
+	// messageOptions is a mapping of fully-qualified message name to additional OpenAPI message options
+	messageOptionsv3 map[string]*optionsv3.Schema
+
+	//serviceOptions is a mapping of fully-qualified service name to additional OpenAPI service options
+	serviceOptionsv3 map[string]*optionsv3.Tag
+
+	// fieldOptions is a mapping of the fully-qualified name of the parent message concat
+	// field name and a period to additional OpenAPI field options
+	fieldOptionsv3 map[string]*optionsv3.JSONSchema
+
 	// generateUnboundMethods causes the registry to generate proxy methods even for
 	// RPC methods that have no HttpRule annotation.
 	generateUnboundMethods bool
@@ -809,36 +827,132 @@ func (r *Registry) RegisterOpenAPIOptions(opts *openapiconfig.OpenAPIOptions) er
 	return nil
 }
 
+// RegisterOpenAPIOptions registers OpenAPI options
+func (r *Registry) RegisterOpenAPIOptionsv3(opts *openapiconfigv3.OpenAPIOptions) error {
+	if opts == nil {
+		return nil
+	}
+
+	for _, opt := range opts.File {
+		if _, ok := r.files[opt.File]; !ok {
+			return fmt.Errorf("no file %s found", opt.File)
+		}
+		r.fileOptionsv3[opt.File] = opt.Option
+	}
+
+	// build map of all registered methods
+	methods := make(map[string]struct{})
+	services := make(map[string]struct{})
+	for _, f := range r.files {
+		for _, s := range f.Services {
+			services[s.FQSN()] = struct{}{}
+			for _, m := range s.Methods {
+				methods[m.FQMN()] = struct{}{}
+			}
+		}
+	}
+
+	for _, opt := range opts.Method {
+		qualifiedMethod := "." + opt.Method
+		if _, ok := methods[qualifiedMethod]; !ok {
+			return fmt.Errorf("no method %s found", opt.Method)
+		}
+		r.methodOptionsv3[qualifiedMethod] = opt.Option
+	}
+
+	for _, opt := range opts.Message {
+		qualifiedMessage := "." + opt.Message
+		if _, ok := r.msgs[qualifiedMessage]; !ok {
+			return fmt.Errorf("no message %s found", opt.Message)
+		}
+		r.messageOptionsv3[qualifiedMessage] = opt.Option
+	}
+
+	for _, opt := range opts.Service {
+		qualifiedService := "." + opt.Service
+		if _, ok := services[qualifiedService]; !ok {
+			return fmt.Errorf("no service %s found", opt.Service)
+		}
+		r.serviceOptionsv3[qualifiedService] = opt.Option
+	}
+
+	// build map of all registered fields
+	fields := make(map[string]struct{})
+	for _, m := range r.msgs {
+		for _, f := range m.Fields {
+			fields[f.FQFN()] = struct{}{}
+		}
+	}
+	for _, opt := range opts.Field {
+		qualifiedField := "." + opt.Field
+		if _, ok := fields[qualifiedField]; !ok {
+			return fmt.Errorf("no field %s found", opt.Field)
+		}
+		r.fieldOptionsv3[qualifiedField] = opt.Option
+	}
+	return nil
+}
+
 // GetOpenAPIFileOption returns a registered OpenAPI option for a file
 func (r *Registry) GetOpenAPIFileOption(file string) (*options.Swagger, bool) {
 	opt, ok := r.fileOptions[file]
 	return opt, ok
 }
 
+// GetOpenAPIFileOption returns a registered OpenAPI option for a file
+func (r *Registry) GetOpenAPIFileOptionv3(file string) (*optionsv3.Swagger, bool) {
+	opt, ok := r.fileOptionsv3[file]
+	return opt, ok
+}
+
 // GetOpenAPIMethodOption returns a registered OpenAPI option for a method
 func (r *Registry) GetOpenAPIMethodOption(qualifiedMethod string) (*options.Operation, bool) {
 	opt, ok := r.methodOptions[qualifiedMethod]
 	return opt, ok
 }
 
+// GetOpenAPIMethodOptionv3 returns a registered OpenAPI option for a method
+func (r *Registry) GetOpenAPIMethodOptionv3(qualifiedMethod string) (*optionsv3.Operation, bool) {
+	opt, ok := r.methodOptionsv3[qualifiedMethod]
+	return opt, ok
+}
+
 // GetOpenAPIMessageOption returns a registered OpenAPI option for a message
 func (r *Registry) GetOpenAPIMessageOption(qualifiedMessage string) (*options.Schema, bool) {
 	opt, ok := r.messageOptions[qualifiedMessage]
 	return opt, ok
 }
 
+// GetOpenAPIMessageOptionv3 returns a registered OpenAPI option for a message
+func (r *Registry) GetOpenAPIMessageOptionv3(qualifiedMessage string) (*optionsv3.Schema, bool) {
+	opt, ok := r.messageOptionsv3[qualifiedMessage]
+	return opt, ok
+}
+
 // GetOpenAPIServiceOption returns a registered OpenAPI option for a service
 func (r *Registry) GetOpenAPIServiceOption(qualifiedService string) (*options.Tag, bool) {
 	opt, ok := r.serviceOptions[qualifiedService]
 	return opt, ok
 }
 
+// GetOpenAPIServiceOptionv3 returns a registered OpenAPI option for a service
+func (r *Registry) GetOpenAPIServiceOptionv3(qualifiedService string) (*optionsv3.Tag, bool) {
+	opt, ok := r.serviceOptionsv3[qualifiedService]
+	return opt, ok
+}
+
 // GetOpenAPIFieldOption returns a registered OpenAPI option for a field
 func (r *Registry) GetOpenAPIFieldOption(qualifiedField string) (*options.JSONSchema, bool) {
 	opt, ok := r.fieldOptions[qualifiedField]
 	return opt, ok
 }
 
+// GetOpenAPIFieldOption returns a registered OpenAPI option for a field
+func (r *Registry) GetOpenAPIFieldOptionv3(qualifiedField string) (*optionsv3.JSONSchema, bool) {
+	opt, ok := r.fieldOptionsv3[qualifiedField]
+	return opt, ok
+}
+
 func (r *Registry) FieldName(f *Field) string {
 	if r.useJSONNamesForFields {
 		return f.GetJsonName()
diff --git a/protoc-gen-openapiv3/BUILD.bazel b/protoc-gen-openapiv3/BUILD.bazel
new file mode 100644
index 00000000000..27b50a3779b
--- /dev/null
+++ b/protoc-gen-openapiv3/BUILD.bazel
@@ -0,0 +1,31 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+
+package(default_visibility = ["//visibility:private"])
+
+go_library(
+    name = "protoc-gen-openapiv3_lib",
+    srcs = ["main.go"],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3",
+    deps = [
+        "//internal/codegenerator",
+        "//internal/descriptor",
+        "//protoc-gen-openapiv3/internal/genopenapi",
+        "//utilities",
+        "@org_golang_google_grpc//grpclog",
+        "@org_golang_google_protobuf//proto",
+        "@org_golang_google_protobuf//types/pluginpb",
+    ],
+)
+
+go_binary(
+    name = "protoc-gen-openapiv3",
+    embed = [":protoc-gen-openapiv3_lib"],
+    visibility = ["//visibility:public"],
+)
+
+go_test(
+    name = "protoc-gen-openapiv3_test",
+    size = "small",
+    srcs = ["main_test.go"],
+    embed = [":protoc-gen-openapiv3_lib"],
+)
diff --git a/protoc-gen-openapiv3/defs.bzl b/protoc-gen-openapiv3/defs.bzl
new file mode 100644
index 00000000000..18e8d36d3ec
--- /dev/null
+++ b/protoc-gen-openapiv3/defs.bzl
@@ -0,0 +1,478 @@
+"""Generated an open-api spec for a grpc api spec.
+
+Reads the api spec in protobuf format and generate an open-api spec.
+Optionally applies settings from the grpc-service configuration.
+"""
+
+load("@rules_proto//proto:defs.bzl", "ProtoInfo")
+
+# TODO(yannic): Replace with |proto_common.direct_source_infos| when
+# https://github.com/bazelbuild/rules_proto/pull/22 lands.
+def _direct_source_infos(proto_info, provided_sources = []):
+    """Returns sequence of `ProtoFileInfo` for `proto_info`'s direct sources.
+
+    Files that are both in `proto_info`'s direct sources and in
+    `provided_sources` are skipped. This is useful, e.g., for well-known
+    protos that are already provided by the Protobuf runtime.
+
+    Args:
+      proto_info: An instance of `ProtoInfo`.
+      provided_sources: Optional. A sequence of files to ignore.
+          Usually, these files are already provided by the
+          Protocol Buffer runtime (e.g. Well-Known protos).
+
+    Returns: A sequence of `ProtoFileInfo` containing information about
+        `proto_info`'s direct sources.
+    """
+
+    source_root = proto_info.proto_source_root
+    if "." == source_root:
+        return [struct(file = src, import_path = src.path) for src in proto_info.check_deps_sources.to_list()]
+
+    offset = len(source_root) + 1  # + '/'.
+
+    infos = []
+    for src in proto_info.check_deps_sources.to_list():
+        # TODO(yannic): Remove this hack when we drop support for Bazel < 1.0.
+        local_offset = offset
+        if src.root.path and not source_root.startswith(src.root.path):
+            # Before Bazel 1.0, `proto_source_root` wasn't guaranteed to be a
+            # prefix of `src.path`. This could happened, e.g., if `file` was
+            # generated (https://github.com/bazelbuild/bazel/issues/9215).
+            local_offset += len(src.root.path) + 1  # + '/'.
+        infos.append(struct(file = src, import_path = src.path[local_offset:]))
+
+    return infos
+
+def _run_proto_gen_openapi(
+        actions,
+        proto_info,
+        target_name,
+        transitive_proto_srcs,
+        protoc,
+        protoc_gen_openapiv3,
+        single_output,
+        allow_delete_body,
+        grpc_api_configuration,
+        json_names_for_fields,
+        repeated_path_param_separator,
+        include_package_in_tags,
+        fqn_for_openapi_name,
+        openapi_naming_strategy,
+        use_go_templates,
+        go_template_args,
+        ignore_comments,
+        remove_internal_comments,
+        disable_default_errors,
+        disable_service_tags,
+        enums_as_ints,
+        omit_enum_default_value,
+        output_format,
+        simple_operation_ids,
+        proto3_optional_nullable,
+        openapi_configuration,
+        generate_unbound_methods,
+        visibility_restriction_selectors,
+        use_allof_for_refs,
+        disable_default_responses,
+        enable_rpc_deprecation,
+        expand_slashed_path_patterns,
+        preserve_rpc_order,
+        generate_x_go_type):
+    args = actions.args()
+
+    args.add("--plugin", "protoc-gen-openapiv3=%s" % protoc_gen_openapiv3.path)
+
+    extra_inputs = []
+    if grpc_api_configuration:
+        extra_inputs.append(grpc_api_configuration)
+        args.add("--openapiv3_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path)
+
+    if openapi_configuration:
+        extra_inputs.append(openapi_configuration)
+        args.add("--openapiv3_opt", "openapi_configuration=%s" % openapi_configuration.path)
+
+    if not json_names_for_fields:
+        args.add("--openapiv3_opt", "json_names_for_fields=false")
+
+    if fqn_for_openapi_name:
+        args.add("--openapiv3_opt", "fqn_for_openapi_name=true")
+
+    if openapi_naming_strategy:
+        args.add("--openapiv3_opt", "openapi_naming_strategy=%s" % openapi_naming_strategy)
+
+    if generate_unbound_methods:
+        args.add("--openapiv3_opt", "generate_unbound_methods=true")
+
+    if simple_operation_ids:
+        args.add("--openapiv3_opt", "simple_operation_ids=true")
+
+    if allow_delete_body:
+        args.add("--openapiv3_opt", "allow_delete_body=true")
+
+    if include_package_in_tags:
+        args.add("--openapiv3_opt", "include_package_in_tags=true")
+
+    if use_go_templates:
+        args.add("--openapiv3_opt", "use_go_templates=true")
+
+    for go_template_arg in go_template_args:
+        args.add("--openapiv3_opt", "go_template_args=%s" % go_template_arg)
+
+    if ignore_comments:
+        args.add("--openapiv3_opt", "ignore_comments=true")
+
+    if remove_internal_comments:
+        args.add("--openapiv3_opt", "remove_internal_comments=true")
+
+    if disable_default_errors:
+        args.add("--openapiv3_opt", "disable_default_errors=true")
+
+    if disable_service_tags:
+        args.add("--openapiv3_opt", "disable_service_tags=true")
+
+    if enums_as_ints:
+        args.add("--openapiv3_opt", "enums_as_ints=true")
+
+    if omit_enum_default_value:
+        args.add("--openapiv3_opt", "omit_enum_default_value=true")
+
+    if output_format:
+        args.add("--openapiv3_opt", "output_format=%s" % output_format)
+
+    if proto3_optional_nullable:
+        args.add("--openapiv3_opt", "proto3_optional_nullable=true")
+
+    for visibility_restriction_selector in visibility_restriction_selectors:
+        args.add("--openapiv3_opt", "visibility_restriction_selectors=%s" % visibility_restriction_selector)
+
+    if use_allof_for_refs:
+        args.add("--openapiv3_opt", "use_allof_for_refs=true")
+
+    if disable_default_responses:
+        args.add("--openapiv3_opt", "disable_default_responses=true")
+
+    if enable_rpc_deprecation:
+        args.add("--openapiv3_opt", "enable_rpc_deprecation=true")
+
+    if expand_slashed_path_patterns:
+        args.add("--openapiv3_opt", "expand_slashed_path_patterns=true")
+
+    if preserve_rpc_order:
+        args.add("--openapiv3_opt", "preserve_rpc_order=true")
+    if generate_x_go_type:
+        args.add("--openapiv3_opt", "generate_x_go_type=true")
+
+    args.add("--openapiv3_opt", "repeated_path_param_separator=%s" % repeated_path_param_separator)
+
+    proto_file_infos = _direct_source_infos(proto_info)
+
+    # TODO(yannic): Use |proto_info.transitive_descriptor_sets| when
+    # https://github.com/bazelbuild/bazel/issues/9337 is fixed.
+    args.add_all(proto_info.transitive_proto_path, format_each = "--proto_path=%s")
+
+    if single_output:
+        args.add("--openapiv3_opt", "allow_merge=true")
+        args.add("--openapiv3_opt", "merge_file_name=%s" % target_name)
+
+        openapi_file = actions.declare_file("%s.swagger.json" % target_name)
+        args.add("--openapiv3_out", openapi_file.dirname)
+
+        args.add_all([f.import_path for f in proto_file_infos])
+
+        actions.run(
+            executable = protoc,
+            tools = [protoc_gen_openapiv3],
+            inputs = depset(
+                direct = extra_inputs,
+                transitive = [transitive_proto_srcs],
+            ),
+            outputs = [openapi_file],
+            arguments = [args],
+        )
+
+        return [openapi_file]
+
+    # TODO(yannic): We may be able to generate all files in a single action,
+    # but that will change at least the semantics of `use_go_template.proto`.
+    openapi_files = []
+    for proto_file_info in proto_file_infos:
+        # TODO(yannic): This probably doesn't work as expected: we only add this
+        # option after we have seen it, so `.proto` sources that happen to be
+        # in the list of `.proto` files before `use_go_template.proto` will be
+        # compiled without this option, and all sources that get compiled after
+        # `use_go_template.proto` will have this option on.
+        if proto_file_info.file.basename == "use_go_template.proto":
+            args.add("--openapiv3_opt", "use_go_templates=true")
+
+        file_name = "%s.swagger.json" % proto_file_info.import_path[:-len(".proto")]
+        openapi_file = actions.declare_file(
+            "_virtual_imports/%s/%s" % (target_name, file_name),
+        )
+
+        file_args = actions.args()
+
+        offset = len(file_name) + 1  # + '/'.
+        file_args.add("--openapiv3_out", openapi_file.path[:-offset])
+
+        file_args.add(proto_file_info.import_path)
+
+        actions.run(
+            executable = protoc,
+            tools = [protoc_gen_openapiv3],
+            inputs = depset(
+                direct = extra_inputs,
+                transitive = [transitive_proto_srcs],
+            ),
+            outputs = [openapi_file],
+            arguments = [args, file_args],
+        )
+        openapi_files.append(openapi_file)
+
+    return openapi_files
+
+def _proto_gen_openapi_impl(ctx):
+    proto = ctx.attr.proto[ProtoInfo]
+    return [
+        DefaultInfo(
+            files = depset(
+                _run_proto_gen_openapi(
+                    actions = ctx.actions,
+                    proto_info = proto,
+                    target_name = ctx.attr.name,
+                    transitive_proto_srcs = depset(
+                        direct = ctx.files._well_known_protos,
+                        transitive = [proto.transitive_sources],
+                    ),
+                    protoc = ctx.executable._protoc,
+                    protoc_gen_openapiv3 = ctx.executable._protoc_gen_openapi,
+                    single_output = ctx.attr.single_output,
+                    allow_delete_body = ctx.attr.allow_delete_body,
+                    grpc_api_configuration = ctx.file.grpc_api_configuration,
+                    json_names_for_fields = ctx.attr.json_names_for_fields,
+                    repeated_path_param_separator = ctx.attr.repeated_path_param_separator,
+                    include_package_in_tags = ctx.attr.include_package_in_tags,
+                    fqn_for_openapi_name = ctx.attr.fqn_for_openapi_name,
+                    openapi_naming_strategy = ctx.attr.openapi_naming_strategy,
+                    use_go_templates = ctx.attr.use_go_templates,
+                    go_template_args = ctx.attr.go_template_args,
+                    ignore_comments = ctx.attr.ignore_comments,
+                    remove_internal_comments = ctx.attr.remove_internal_comments,
+                    disable_default_errors = ctx.attr.disable_default_errors,
+                    disable_service_tags = ctx.attr.disable_service_tags,
+                    enums_as_ints = ctx.attr.enums_as_ints,
+                    omit_enum_default_value = ctx.attr.omit_enum_default_value,
+                    output_format = ctx.attr.output_format,
+                    simple_operation_ids = ctx.attr.simple_operation_ids,
+                    proto3_optional_nullable = ctx.attr.proto3_optional_nullable,
+                    openapi_configuration = ctx.file.openapi_configuration,
+                    generate_unbound_methods = ctx.attr.generate_unbound_methods,
+                    visibility_restriction_selectors = ctx.attr.visibility_restriction_selectors,
+                    use_allof_for_refs = ctx.attr.use_allof_for_refs,
+                    disable_default_responses = ctx.attr.disable_default_responses,
+                    enable_rpc_deprecation = ctx.attr.enable_rpc_deprecation,
+                    expand_slashed_path_patterns = ctx.attr.expand_slashed_path_patterns,
+                    preserve_rpc_order = ctx.attr.preserve_rpc_order,
+                    generate_x_go_type = ctx.attr.generate_x_go_type,
+                ),
+            ),
+        ),
+    ]
+
+protoc_gen_openapiv3 = rule(
+    attrs = {
+        "proto": attr.label(
+            mandatory = True,
+            providers = [ProtoInfo],
+        ),
+        "single_output": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, the rule will generate a single OpenAPI file",
+        ),
+        "allow_delete_body": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "unless set, HTTP DELETE methods may not have a body",
+        ),
+        "grpc_api_configuration": attr.label(
+            allow_single_file = True,
+            mandatory = False,
+            doc = "path to file which describes the gRPC API Configuration in YAML format",
+        ),
+        "json_names_for_fields": attr.bool(
+            default = True,
+            mandatory = False,
+            doc = "if disabled, the original proto name will be used for generating OpenAPI definitions",
+        ),
+        "repeated_path_param_separator": attr.string(
+            default = "csv",
+            mandatory = False,
+            values = ["csv", "pipes", "ssv", "tsv"],
+            doc = "configures how repeated fields should be split." +
+                  " Allowed values are `csv`, `pipes`, `ssv` and `tsv`",
+        ),
+        "include_package_in_tags": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if unset, the gRPC service name is added to the `Tags`" +
+                  " field of each operation. If set and the `package` directive" +
+                  " is shown in the proto file, the package name will be " +
+                  " prepended to the service name",
+        ),
+        "fqn_for_openapi_name": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, the object's OpenAPI names will use the fully" +
+                  " qualified names from the proto definition" +
+                  " (ie my.package.MyMessage.MyInnerMessage",
+        ),
+        "openapi_naming_strategy": attr.string(
+            default = "",
+            mandatory = False,
+            values = ["", "simple", "package", "legacy", "fqn"],
+            doc = "configures how OpenAPI names are determined." +
+                  " Allowed values are `` (empty), `simple`, `package`, `legacy` and `fqn`." +
+                  " If unset, either `legacy` or `fqn` are selected, depending" +
+                  " on the value of the `fqn_for_openapi_name` setting",
+        ),
+        "use_go_templates": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, you can use Go templates in protofile comments",
+        ),
+        "go_template_args": attr.string_list(
+            mandatory = False,
+            doc = "specify a key value pair as inputs to the Go template of the protofile" +
+                  " comments. Repeat this option to specify multiple template arguments." +
+                  " Requires the `use_go_templates` option to be set.",
+        ),
+        "ignore_comments": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, all protofile comments are excluded from output",
+        ),
+        "remove_internal_comments": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, removes all substrings in comments that start with " +
+                  "`(--` and end with `--)` as specified in " +
+                  "https://google.aip.dev/192#internal-comments",
+        ),
+        "disable_default_errors": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, disables generation of default errors." +
+                  " This is useful if you have defined custom error handling",
+        ),
+        "disable_service_tags": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, disables generation of service tags." +
+                  " This is useful if you do not want to expose the names of your backend grpc services.",
+        ),
+        "enums_as_ints": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "whether to render enum values as integers, as opposed to string values",
+        ),
+        "omit_enum_default_value": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, omit default enum value",
+        ),
+        "output_format": attr.string(
+            default = "json",
+            mandatory = False,
+            values = ["json", "yaml"],
+            doc = "output content format. Allowed values are: `json`, `yaml`",
+        ),
+        "simple_operation_ids": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "whether to remove the service prefix in the operationID" +
+                  " generation. Can introduce duplicate operationIDs, use with caution.",
+        ),
+        "proto3_optional_nullable": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "whether Proto3 Optional fields should be marked as x-nullable",
+        ),
+        "openapi_configuration": attr.label(
+            allow_single_file = True,
+            mandatory = False,
+            doc = "path to file which describes the OpenAPI Configuration in YAML format",
+        ),
+        "generate_unbound_methods": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "generate swagger metadata even for RPC methods that have" +
+                  " no HttpRule annotation",
+        ),
+        "visibility_restriction_selectors": attr.string_list(
+            mandatory = False,
+            doc = "list of `google.api.VisibilityRule` visibility labels to include" +
+                  " in the generated output when a visibility annotation is defined." +
+                  " Repeat this option to supply multiple values. Elements without" +
+                  " visibility annotations are unaffected by this setting.",
+        ),
+        "use_allof_for_refs": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, will use allOf as container for $ref to preserve" +
+                  " same-level properties.",
+        ),
+        "disable_default_responses": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, disables generation of default responses. Useful" +
+                  " if you have to support custom response codes that are" +
+                  " not 200.",
+        ),
+        "enable_rpc_deprecation": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "whether to process grpc method's deprecated option.",
+        ),
+        "expand_slashed_path_patterns": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, expands path patterns containing slashes into URI." +
+                  " It also creates a new path parameter for each wildcard in " +
+                  " the path pattern.",
+        ),
+        "preserve_rpc_order": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, ensures the order of paths emitted in OpenAPI files" +
+                  " mirrors the order of RPC methods found in proto files." +
+                  " If false, emitted paths will be ordered alphabetically.",
+        ),
+        "use_proto3_field_semantics": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "if set, uses proto3 field semantics for the OpenAPI schema." +
+                  "  This means that fields are required by default.",
+        ),
+        "generate_x_go_type": attr.bool(
+            default = False,
+            mandatory = False,
+            doc = "Generate x-go-type extension using the go_package option from proto files",
+        ),
+        "_protoc": attr.label(
+            default = "@com_google_protobuf//:protoc",
+            executable = True,
+            cfg = "exec",
+        ),
+        "_well_known_protos": attr.label(
+            default = "@com_google_protobuf//:well_known_type_protos",
+            allow_files = True,
+        ),
+        "_protoc_gen_openapi": attr.label(
+            default = Label("//protoc-gen-openapiv3:protoc-gen-openapiv3"),
+            executable = True,
+            cfg = "exec",
+        ),
+    },
+    implementation = _proto_gen_openapi_impl,
+)
diff --git a/protoc-gen-openapiv3/internal/genopenapi/BUILD.bazel b/protoc-gen-openapiv3/internal/genopenapi/BUILD.bazel
new file mode 100644
index 00000000000..9b9db250e1f
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/BUILD.bazel
@@ -0,0 +1,87 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+package(default_visibility = ["//protoc-gen-openapiv3:__subpackages__"])
+
+go_library(
+    name = "genopenapi",
+    srcs = [
+        "doc.go",
+        "format.go",
+        "generator.go",
+        "helpers.go",
+        "helpers_go111_old.go",
+        "naming.go",
+        "template.go",
+        "types.go",
+    ],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/internal/genopenapi",
+    deps = [
+        "//internal/casing",
+        "//internal/descriptor",
+        "//internal/generator",
+        "//protoc-gen-openapiv3/options",
+        "@in_gopkg_yaml_v3//:yaml_v3",
+        "@org_golang_google_genproto_googleapis_api//annotations",
+        "@org_golang_google_genproto_googleapis_api//visibility",
+        "@org_golang_google_genproto_googleapis_rpc//status",
+        "@org_golang_google_grpc//grpclog",
+        "@org_golang_google_protobuf//encoding/protojson",
+        "@org_golang_google_protobuf//proto",
+        "@org_golang_google_protobuf//reflect/protodesc",
+        "@org_golang_google_protobuf//types/descriptorpb",
+        "@org_golang_google_protobuf//types/known/anypb",
+        "@org_golang_google_protobuf//types/known/structpb",
+        "@org_golang_google_protobuf//types/pluginpb",
+        "@org_golang_x_text//cases",
+        "@org_golang_x_text//language",
+    ],
+)
+
+go_test(
+    name = "genopenapi_test",
+    size = "small",
+    srcs = [
+        "cycle_test.go",
+        "format_test.go",
+        "generator_test.go",
+        "helpers_test.go",
+        "naming_test.go",
+        "template_fuzz_test.go",
+        "template_test.go",
+        "types_test.go",
+    ],
+    data = glob(["testdata/**"]),
+    embed = [":genopenapi"],
+    deps = [
+        "//internal/descriptor",
+        "//internal/descriptor/openapiconfigv3:openapiconfig",
+        "//internal/httprule",
+        "//protoc-gen-openapiv3/options",
+        "//runtime",
+        "@com_github_google_go_cmp//cmp",
+        "@in_gopkg_yaml_v3//:yaml_v3",
+        "@org_golang_google_genproto_googleapis_api//annotations",
+        "@org_golang_google_genproto_googleapis_api//visibility",
+        "@org_golang_google_protobuf//encoding/protojson",
+        "@org_golang_google_protobuf//encoding/prototext",
+        "@org_golang_google_protobuf//proto",
+        "@org_golang_google_protobuf//reflect/protodesc",
+        "@org_golang_google_protobuf//reflect/protoreflect",
+        "@org_golang_google_protobuf//reflect/protoregistry",
+        "@org_golang_google_protobuf//types/descriptorpb",
+        "@org_golang_google_protobuf//types/known/anypb",
+        "@org_golang_google_protobuf//types/known/durationpb",
+        "@org_golang_google_protobuf//types/known/emptypb",
+        "@org_golang_google_protobuf//types/known/fieldmaskpb",
+        "@org_golang_google_protobuf//types/known/structpb",
+        "@org_golang_google_protobuf//types/known/timestamppb",
+        "@org_golang_google_protobuf//types/known/wrapperspb",
+        "@org_golang_google_protobuf//types/pluginpb",
+    ],
+)
+
+alias(
+    name = "go_default_library",
+    actual = ":genopenapi",
+    visibility = ["//protoc-gen-openapiv3:__subpackages__"],
+)
diff --git a/protoc-gen-openapiv3/internal/genopenapi/cycle_test.go b/protoc-gen-openapiv3/internal/genopenapi/cycle_test.go
new file mode 100644
index 00000000000..88613155610
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/cycle_test.go
@@ -0,0 +1,41 @@
+package genopenapi
+
+import (
+	"testing"
+)
+
+func TestCycle(t *testing.T) {
+	for _, tt := range []struct {
+		max     int
+		attempt int
+		e       bool
+	}{
+		{
+			max:     3,
+			attempt: 3,
+			e:       true,
+		},
+		{
+			max:     5,
+			attempt: 6,
+		},
+		{
+			max:     1000,
+			attempt: 1001,
+		},
+	} {
+
+		c := newCycleChecker(tt.max)
+		var final bool
+		for i := 0; i < tt.attempt; i++ {
+			final = c.Check("a")
+			if !final {
+				break
+			}
+		}
+
+		if final != tt.e {
+			t.Errorf("got: %t wanted: %t", final, tt.e)
+		}
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/doc.go b/protoc-gen-openapiv3/internal/genopenapi/doc.go
new file mode 100644
index 00000000000..42f9237f66e
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/doc.go
@@ -0,0 +1,2 @@
+// Package genopenapi provides a code generator for OpenAPI v2.
+package genopenapi
diff --git a/protoc-gen-openapiv3/internal/genopenapi/format.go b/protoc-gen-openapiv3/internal/genopenapi/format.go
new file mode 100644
index 00000000000..6f0faa8e538
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/format.go
@@ -0,0 +1,46 @@
+package genopenapi
+
+import (
+	"encoding/json"
+	"errors"
+	"io"
+
+	"gopkg.in/yaml.v3"
+)
+
+type Format string
+
+const (
+	FormatJSON Format = "json"
+	FormatYAML Format = "yaml"
+)
+
+type ContentEncoder interface {
+	Encode(v interface{}) (err error)
+}
+
+func (f Format) Validate() error {
+	switch f {
+	case FormatJSON, FormatYAML:
+		return nil
+	default:
+		return errors.New("unknown format: " + string(f))
+	}
+}
+
+func (f Format) NewEncoder(w io.Writer) (ContentEncoder, error) {
+	switch f {
+	case FormatYAML:
+		enc := yaml.NewEncoder(w)
+		enc.SetIndent(2)
+
+		return enc, nil
+	case FormatJSON:
+		enc := json.NewEncoder(w)
+		enc.SetIndent("", "  ")
+
+		return enc, nil
+	default:
+		return nil, errors.New("unknown format: " + string(f))
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/format_test.go b/protoc-gen-openapiv3/internal/genopenapi/format_test.go
new file mode 100644
index 00000000000..9c2ea42f999
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/format_test.go
@@ -0,0 +1,105 @@
+package genopenapi_test
+
+import (
+	"bytes"
+	"encoding/json"
+	"io"
+	"reflect"
+	"testing"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/internal/genopenapi"
+	"gopkg.in/yaml.v3"
+)
+
+func TestFormatValidate(t *testing.T) {
+	t.Parallel()
+
+	testCases := [...]struct {
+		Format genopenapi.Format
+		Valid  bool
+	}{{
+		Format: genopenapi.FormatJSON,
+		Valid:  true,
+	}, {
+		Format: genopenapi.FormatYAML,
+		Valid:  true,
+	}, {
+		Format: genopenapi.Format("unknown"),
+		Valid:  false,
+	}, {
+		Format: genopenapi.Format(""),
+		Valid:  false,
+	}}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(string(tc.Format), func(t *testing.T) {
+			t.Parallel()
+
+			err := tc.Format.Validate()
+			switch {
+			case tc.Valid && err != nil:
+				t.Fatalf("expect no validation error, got: %s", err)
+			case !tc.Valid && err == nil:
+				t.Fatal("expect validation error, got nil")
+			}
+		})
+	}
+}
+
+func TestFormatEncode(t *testing.T) {
+	t.Parallel()
+
+	type contentDecoder interface {
+		Decode(v interface{}) error
+	}
+
+	testCases := [...]struct {
+		Format     genopenapi.Format
+		NewDecoder func(r io.Reader) contentDecoder
+	}{{
+		Format: genopenapi.FormatJSON,
+		NewDecoder: func(r io.Reader) contentDecoder {
+			return json.NewDecoder(r)
+		},
+	}, {
+		Format: genopenapi.FormatYAML,
+		NewDecoder: func(r io.Reader) contentDecoder {
+			return yaml.NewDecoder(r)
+		},
+	}}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(string(tc.Format), func(t *testing.T) {
+			t.Parallel()
+
+			expParams := map[string]string{
+				"hello": "world",
+			}
+
+			var buf bytes.Buffer
+			enc, err := tc.Format.NewEncoder(&buf)
+			if err != nil {
+				t.Fatalf("expect no encoder creating error, got: %s", err)
+			}
+
+			err = enc.Encode(expParams)
+			if err != nil {
+				t.Fatalf("expect no encoding error, got: %s", err)
+			}
+
+			gotParams := make(map[string]string)
+			err = tc.NewDecoder(&buf).Decode(&gotParams)
+			if err != nil {
+				t.Fatalf("expect no decoding error, got: %s", err)
+			}
+
+			if !reflect.DeepEqual(expParams, gotParams) {
+				t.Fatalf("expected: %+v, actual: %+v", expParams, gotParams)
+			}
+		})
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/generator.go b/protoc-gen-openapiv3/internal/genopenapi/generator.go
new file mode 100644
index 00000000000..59b9f1c17c2
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/generator.go
@@ -0,0 +1,480 @@
+package genopenapi
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator"
+	openapioptions "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options"
+	statuspb "google.golang.org/genproto/googleapis/rpc/status"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protodesc"
+	"google.golang.org/protobuf/types/descriptorpb"
+	"google.golang.org/protobuf/types/known/anypb"
+	"google.golang.org/protobuf/types/pluginpb"
+	"gopkg.in/yaml.v3"
+)
+
+var errNoTargetService = errors.New("no target service defined in the file")
+
+type generator struct {
+	reg    *descriptor.Registry
+	format Format
+}
+
+type wrapper struct {
+	fileName string
+	swagger  *openapiSwaggerObject
+}
+
+type GeneratorOptions struct {
+	Registry       *descriptor.Registry
+	RecursiveDepth int
+}
+
+// New returns a new generator which generates grpc gateway files.
+func New(reg *descriptor.Registry, format Format) gen.Generator {
+	return &generator{
+		reg:    reg,
+		format: format,
+	}
+}
+
+// Merge a lot of OpenAPI file (wrapper) to single one OpenAPI file
+func mergeTargetFile(targets []*wrapper, mergeFileName string) *wrapper {
+	var mergedTarget *wrapper
+	for _, f := range targets {
+		if mergedTarget == nil {
+			mergedTarget = &wrapper{
+				fileName: mergeFileName,
+				swagger:  f.swagger,
+			}
+		} else {
+			for k, v := range f.swagger.Definitions {
+				mergedTarget.swagger.Definitions[k] = v
+			}
+			for k, v := range f.swagger.SecurityDefinitions {
+				mergedTarget.swagger.SecurityDefinitions[k] = v
+			}
+			copy(mergedTarget.swagger.Paths, f.swagger.Paths)
+			mergedTarget.swagger.Security = append(mergedTarget.swagger.Security, f.swagger.Security...)
+		}
+	}
+	return mergedTarget
+}
+
+// Q: What's up with the alias types here?
+// A: We don't want to completely override how these structs are marshaled into
+// JSON, we only want to add fields (see below, extensionMarshalJSON).
+// An infinite recursion would happen if we'd call json.Marshal on the struct
+// that has swaggerObject as an embedded field. To avoid that, we'll create
+// type aliases, and those don't have the custom MarshalJSON methods defined
+// on them. See http://choly.ca/post/go-json-marshalling/ (or, if it ever
+// goes away, use
+// https://web.archive.org/web/20190806073003/http://choly.ca/post/go-json-marshalling/).
+func (so openapiSwaggerObject) MarshalJSON() ([]byte, error) {
+	type alias openapiSwaggerObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+// MarshalYAML implements yaml.Marshaler interface.
+//
+// It is required in order to pass extensions inline.
+//
+// Example:
+//
+//	extensions: {x-key: x-value}
+//	type: string
+//
+// It will be rendered as:
+//
+//	x-key: x-value
+//	type: string
+//
+// Use generics when the project will be upgraded to go 1.18+.
+func (so openapiSwaggerObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiSwaggerObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+// Custom json marshaller for openapiPathsObject. Ensures
+// openapiPathsObject is marshalled into expected format in generated
+// swagger.json.
+func (po openapiPathsObject) MarshalJSON() ([]byte, error) {
+	var buf bytes.Buffer
+
+	buf.WriteString("{")
+	for i, pd := range po {
+		if i != 0 {
+			buf.WriteString(",")
+		}
+		// marshal key
+		key, err := json.Marshal(pd.Path)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(key)
+		buf.WriteString(":")
+		// marshal value
+		val, err := json.Marshal(pd.PathItemObject)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(val)
+	}
+
+	buf.WriteString("}")
+	return buf.Bytes(), nil
+}
+
+// Custom yaml marshaller for openapiPathsObject. Ensures
+// openapiPathsObject is marshalled into expected format in generated
+// swagger.yaml.
+func (po openapiPathsObject) MarshalYAML() (interface{}, error) {
+	var pathObjectNode yaml.Node
+	pathObjectNode.Kind = yaml.MappingNode
+
+	for _, pathData := range po {
+		var pathNode yaml.Node
+
+		pathNode.SetString(pathData.Path)
+		pathItemObjectNode, err := pathData.PathItemObject.toYAMLNode()
+		if err != nil {
+			return nil, err
+		}
+		pathObjectNode.Content = append(pathObjectNode.Content, &pathNode, pathItemObjectNode)
+	}
+
+	return pathObjectNode, nil
+}
+
+// We can simplify this implementation once the go-yaml bug is resolved. See: https://github.com/go-yaml/yaml/issues/643.
+//
+//	func (pio *openapiPathItemObject) toYAMLNode() (*yaml.Node, error) {
+//		var node yaml.Node
+//		if err := node.Encode(pio); err != nil {
+//			return nil, err
+//		}
+//		return &node, nil
+//	}
+func (pio *openapiPathItemObject) toYAMLNode() (*yaml.Node, error) {
+	var doc yaml.Node
+	var buf bytes.Buffer
+	ec := yaml.NewEncoder(&buf)
+	ec.SetIndent(2)
+	if err := ec.Encode(pio); err != nil {
+		return nil, err
+	}
+	if err := yaml.Unmarshal(buf.Bytes(), &doc); err != nil {
+		return nil, err
+	}
+	if len(doc.Content) == 0 {
+		return nil, errors.New("unexpected number of yaml nodes")
+	}
+	return doc.Content[0], nil
+}
+
+func (so openapiInfoObject) MarshalJSON() ([]byte, error) {
+	type alias openapiInfoObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiInfoObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiInfoObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiSecuritySchemeObject) MarshalJSON() ([]byte, error) {
+	type alias openapiSecuritySchemeObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiSecuritySchemeObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiSecuritySchemeObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiOperationObject) MarshalJSON() ([]byte, error) {
+	type alias openapiOperationObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiOperationObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiOperationObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiResponseObject) MarshalJSON() ([]byte, error) {
+	type alias openapiResponseObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiResponseObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiResponseObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiSchemaObject) MarshalJSON() ([]byte, error) {
+	type alias openapiSchemaObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiSchemaObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiSchemaObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiParameterObject) MarshalJSON() ([]byte, error) {
+	type alias openapiParameterObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiParameterObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiParameterObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func (so openapiTagObject) MarshalJSON() ([]byte, error) {
+	type alias openapiTagObject
+	return extensionMarshalJSON(alias(so), so.extensions)
+}
+
+func (so openapiTagObject) MarshalYAML() (interface{}, error) {
+	type Alias openapiTagObject
+
+	return struct {
+		Extension map[string]interface{} `yaml:",inline"`
+		Alias     `yaml:",inline"`
+	}{
+		Extension: extensionsToMap(so.extensions),
+		Alias:     Alias(so),
+	}, nil
+}
+
+func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error) {
+	// To append arbitrary keys to the struct we'll render into json,
+	// we're creating another struct that embeds the original one, and
+	// its extra fields:
+	//
+	// The struct will look like
+	// struct {
+	//   *openapiCore
+	//   XGrpcGatewayFoo json.RawMessage `json:"x-grpc-gateway-foo"`
+	//   XGrpcGatewayBar json.RawMessage `json:"x-grpc-gateway-bar"`
+	// }
+	// and thus render into what we want -- the JSON of openapiCore with the
+	// extensions appended.
+	fields := []reflect.StructField{
+		{ // embedded
+			Name:      "Embedded",
+			Type:      reflect.TypeOf(so),
+			Anonymous: true,
+		},
+	}
+	for _, ext := range extensions {
+		fields = append(fields, reflect.StructField{
+			Name: fieldName(ext.key),
+			Type: reflect.TypeOf(ext.value),
+			Tag:  reflect.StructTag(fmt.Sprintf("json:\"%s\"", ext.key)),
+		})
+	}
+
+	t := reflect.StructOf(fields)
+	s := reflect.New(t).Elem()
+	s.Field(0).Set(reflect.ValueOf(so))
+	for _, ext := range extensions {
+		s.FieldByName(fieldName(ext.key)).Set(reflect.ValueOf(ext.value))
+	}
+	return json.Marshal(s.Interface())
+}
+
+// encodeOpenAPI converts OpenAPI file obj to pluginpb.CodeGeneratorResponse_File
+func encodeOpenAPI(file *wrapper, format Format) (*descriptor.ResponseFile, error) {
+	var contentBuf bytes.Buffer
+	enc, err := format.NewEncoder(&contentBuf)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := enc.Encode(*file.swagger); err != nil {
+		return nil, err
+	}
+
+	name := file.fileName
+	ext := filepath.Ext(name)
+	base := strings.TrimSuffix(name, ext)
+	output := fmt.Sprintf("%s.swagger."+string(format), base)
+	return &descriptor.ResponseFile{
+		CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{
+			Name:    proto.String(output),
+			Content: proto.String(contentBuf.String()),
+		},
+	}, nil
+}
+
+func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.ResponseFile, error) {
+	var files []*descriptor.ResponseFile
+	if g.reg.IsAllowMerge() {
+		var mergedTarget *descriptor.File
+		// try to find proto leader
+		for _, f := range targets {
+			if proto.HasExtension(f.Options, openapioptions.E_Openapiv2Swagger) {
+				mergedTarget = f
+				break
+			}
+		}
+		// merge protos to leader
+		for _, f := range targets {
+			if mergedTarget == nil {
+				mergedTarget = f
+			} else if mergedTarget != f {
+				mergedTarget.Enums = append(mergedTarget.Enums, f.Enums...)
+				mergedTarget.Messages = append(mergedTarget.Messages, f.Messages...)
+				mergedTarget.Services = append(mergedTarget.Services, f.Services...)
+			}
+		}
+
+		targets = nil
+		targets = append(targets, mergedTarget)
+	}
+
+	var openapis []*wrapper
+	for _, file := range targets {
+		if grpclog.V(1) {
+			grpclog.Infof("Processing %s", file.GetName())
+		}
+		swagger, err := applyTemplate(param{File: file, reg: g.reg})
+		if errors.Is(err, errNoTargetService) {
+			if grpclog.V(1) {
+				grpclog.Infof("%s: %v", file.GetName(), err)
+			}
+			continue
+		}
+		if err != nil {
+			return nil, err
+		}
+		openapis = append(openapis, &wrapper{
+			fileName: file.GetName(),
+			swagger:  swagger,
+		})
+	}
+
+	if g.reg.IsAllowMerge() {
+		targetOpenAPI := mergeTargetFile(openapis, g.reg.GetMergeFileName())
+		if !g.reg.IsPreserveRPCOrder() {
+			targetOpenAPI.swagger.sortPathsAlphabetically()
+		}
+		f, err := encodeOpenAPI(targetOpenAPI, g.format)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encode OpenAPI for %s: %w", g.reg.GetMergeFileName(), err)
+		}
+		files = append(files, f)
+		if grpclog.V(1) {
+			grpclog.Infof("New OpenAPI file will emit")
+		}
+	} else {
+		for _, file := range openapis {
+			if !g.reg.IsPreserveRPCOrder() {
+				file.swagger.sortPathsAlphabetically()
+			}
+			f, err := encodeOpenAPI(file, g.format)
+			if err != nil {
+				return nil, fmt.Errorf("failed to encode OpenAPI for %s: %w", file.fileName, err)
+			}
+			files = append(files, f)
+			if grpclog.V(1) {
+				grpclog.Infof("New OpenAPI file will emit")
+			}
+		}
+	}
+	return files, nil
+}
+
+func (so openapiSwaggerObject) sortPathsAlphabetically() {
+	sort.Slice(so.Paths, func(i, j int) bool {
+		return so.Paths[i].Path < so.Paths[j].Path
+	})
+}
+
+// AddErrorDefs Adds google.rpc.Status and google.protobuf.Any
+// to registry (used for error-related API responses)
+func AddErrorDefs(reg *descriptor.Registry) error {
+	// load internal protos
+	any := protodesc.ToFileDescriptorProto((&anypb.Any{}).ProtoReflect().Descriptor().ParentFile())
+	any.SourceCodeInfo = new(descriptorpb.SourceCodeInfo)
+	status := protodesc.ToFileDescriptorProto((&statuspb.Status{}).ProtoReflect().Descriptor().ParentFile())
+	status.SourceCodeInfo = new(descriptorpb.SourceCodeInfo)
+	return reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{
+			any,
+			status,
+		},
+	})
+}
+
+func extensionsToMap(extensions []extension) map[string]interface{} {
+	m := make(map[string]interface{}, len(extensions))
+
+	for _, v := range extensions {
+		m[v.key] = RawExample(v.value)
+	}
+
+	return m
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/generator_test.go b/protoc-gen-openapiv3/internal/genopenapi/generator_test.go
new file mode 100644
index 00000000000..c9d6c687b8c
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/generator_test.go
@@ -0,0 +1,1940 @@
+package genopenapi_test
+
+import (
+	"bytes"
+	"os"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/internal/genopenapi"
+	"gopkg.in/yaml.v3"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/descriptorpb"
+	"google.golang.org/protobuf/types/pluginpb"
+)
+
+func TestGenerate_YAML(t *testing.T) {
+	t.Parallel()
+
+	req := &pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{{
+			Name:    proto.String("file.proto"),
+			Package: proto.String("example"),
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("goexample/v1;goexample"),
+			},
+		}},
+		FileToGenerate: []string{
+			"file.proto",
+		},
+	}
+
+	resp := requireGenerate(t, req, genopenapi.FormatYAML, false, false)
+	if len(resp) != 1 {
+		t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+	}
+
+	var p map[string]interface{}
+	err := yaml.Unmarshal([]byte(resp[0].GetContent()), &p)
+	if err != nil {
+		t.Fatalf("failed to unmarshall yaml: %s", err)
+	}
+}
+
+func TestGenerateExtension(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+				options: {
+					[grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field]: {
+						description: "This is bar"
+						extensions: {
+							key: "x-go-default"
+							value: {
+								string_value: "0.5s"
+							}
+						}
+					}
+				}
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, false, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			if !strings.Contains(content, "x-go-default") {
+				t.Fatal("x-go-default not found in content message")
+			}
+		})
+	}
+}
+
+func TestGenerateYAML(t *testing.T) {
+	t.Parallel()
+
+	tests := []struct {
+		name           string
+		inputProtoText string
+		wantYAML       string
+	}{
+		{
+			// It tests https://github.com/grpc-ecosystem/grpc-gateway/issues/3557.
+			name:           "path item object",
+			inputProtoText: "testdata/generator/path_item_object.prototext",
+			wantYAML:       "testdata/generator/path_item_object.swagger.yaml",
+		},
+	}
+
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
+
+			b, err := os.ReadFile(tt.inputProtoText)
+			if err != nil {
+				t.Fatal(err)
+			}
+			var req pluginpb.CodeGeneratorRequest
+			if err := prototext.Unmarshal(b, &req); err != nil {
+				t.Fatal(err)
+			}
+
+			resp := requireGenerate(t, &req, genopenapi.FormatYAML, false, true)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+			got := resp[0].GetContent()
+
+			want, err := os.ReadFile(tt.wantYAML)
+			if err != nil {
+				t.Fatal(err)
+			}
+			diff := cmp.Diff(string(want), got)
+			if diff != "" {
+				t.Fatalf("content not match\n%s", diff)
+			}
+		})
+	}
+}
+
+func requireGenerate(
+	tb testing.TB,
+	req *pluginpb.CodeGeneratorRequest,
+	format genopenapi.Format,
+	preserveRPCOrder bool,
+	allowMerge bool,
+) []*descriptor.ResponseFile {
+	tb.Helper()
+
+	reg := descriptor.NewRegistry()
+	reg.SetPreserveRPCOrder(preserveRPCOrder)
+	reg.SetAllowMerge(allowMerge)
+
+	if err := reg.Load(req); err != nil {
+		tb.Fatalf("failed to load request: %s", err)
+	}
+
+	var targets []*descriptor.File
+	for _, target := range req.FileToGenerate {
+		f, err := reg.LookupFile(target)
+		if err != nil {
+			tb.Fatalf("failed to lookup file: %s", err)
+		}
+
+		targets = append(targets, f)
+	}
+
+	g := genopenapi.New(reg, format)
+
+	resp, err := g.Generate(targets)
+	switch {
+	case err != nil:
+		tb.Fatalf("failed to generate targets: %s", err)
+	case len(resp) != len(targets) && !allowMerge:
+		tb.Fatalf("invalid count, expected: %d, actual: %d", len(targets), len(resp))
+	}
+
+	return resp
+}
+
+func TestGeneratedYAMLIndent(t *testing.T) {
+	// It tests https://github.com/grpc-ecosystem/grpc-gateway/issues/2745.
+	const in = `
+	file_to_generate: "exampleproto/v1/exampleproto.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/exampleproto.proto"
+		package: "repro"
+		message_type: {
+			name: "RollupRequest"
+			field: {
+				name: "type"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_ENUM
+				type_name: ".repro.RollupType"
+				json_name: "type"
+			}
+		}
+		message_type: {
+			name: "RollupResponse"
+		}
+		enum_type: {
+			name: "RollupType"
+			value: {
+				name: "UNKNOWN_ROLLUP"
+				number: 0
+			}
+			value: {
+				name: "APPLE"
+				number: 1
+			}
+			value: {
+				name: "BANANA"
+				number: 2
+			}
+			value: {
+				name: "CARROT"
+				number: 3
+			}
+		}
+		service: {
+			name: "Repro"
+			method: {
+				name: "GetRollup"
+				input_type: ".repro.RollupRequest"
+				output_type: ".repro.RollupResponse"
+				options: {
+					[google.api.http]: {
+						get: "/rollup"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "repro/foobar"
+		}
+		source_code_info: {
+			location: {
+				path: 5
+				path: 0
+				path: 2
+				path: 1
+				span: 24
+				span: 4
+				span: 14
+				leading_comments: " Apples are good\n"
+			}
+			location: {
+				path: 5
+				path: 0
+				path: 2
+				path: 3
+				span: 28
+				span: 4
+				span: 15
+				leading_comments: " Carrots are mediocre\n"
+			}
+		}
+		syntax: "proto3"
+	}
+	`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	resp := requireGenerate(t, &req, genopenapi.FormatYAML, false, false)
+	if len(resp) != 1 {
+		t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+	}
+
+	content := resp[0].GetContent()
+
+	err := yaml.Unmarshal([]byte(content), map[string]interface{}{})
+	if err != nil {
+		t.Log(content)
+		t.Fatalf("got invalid yaml: %s", err)
+	}
+}
+
+func TestGenerateRPCOrderPreserved(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, true, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/b/first", "/a/second", "/c/third"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+
+}
+
+func TestGenerateRPCOrderNotPreserved(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, false, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/a/second", "/b/first", "/c/third"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+
+}
+
+func TestGenerateRPCOrderPreservedMultipleServices(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestServiceOne"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		service: {
+			name: "TestServiceTwo"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/g/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, true, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/d/first", "/e/second", "/c/third", "/b/first", "/a/second", "/g/third"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderNotPreservedMultipleServices(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestServiceOne"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		service: {
+			name: "TestServiceTwo"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/g/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, false, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/d/first", "/e/second", "/c/third", "/b/first", "/a/second", "/g/third"}
+			sort.Strings(expectedPaths)
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderPreservedMergeFiles(t *testing.T) {
+	t.Parallel()
+
+	const in1 = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/cpath"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/bpath"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/apath"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	const in2 = `
+	file_to_generate: "exampleproto/v2/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v2/example.proto"
+		package: "example.v2"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/f/fpath"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/epath"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/dpath"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v2;exampleproto"
+		}
+	}`
+
+	var req1, req2 pluginpb.CodeGeneratorRequest
+
+	if err := prototext.Unmarshal([]byte(in1), &req1); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+	if err := prototext.Unmarshal([]byte(in2), &req2); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	req1.ProtoFile = append(req1.ProtoFile, req2.ProtoFile...)
+	req1.FileToGenerate = append(req1.FileToGenerate, req2.FileToGenerate...)
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req1, format, true, true)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/c/cpath", "/b/bpath", "/a/apath", "/f/fpath", "/e/epath", "/d/dpath"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderNotPreservedMergeFiles(t *testing.T) {
+	t.Parallel()
+
+	const in1 = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/cpath"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/bpath"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/apath"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	const in2 = `
+	file_to_generate: "exampleproto/v2/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v2/example.proto"
+		package: "example.v2"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/f/fpath"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/epath"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/dpath"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v2;exampleproto"
+		}
+	}`
+
+	var req1, req2 pluginpb.CodeGeneratorRequest
+
+	if err := prototext.Unmarshal([]byte(in1), &req1); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+	if err := prototext.Unmarshal([]byte(in2), &req2); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	req1.ProtoFile = append(req1.ProtoFile, req2.ProtoFile...)
+	req1.FileToGenerate = append(req1.FileToGenerate, req2.FileToGenerate...)
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req1, format, false, true)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/c/cpath", "/b/bpath", "/a/apath", "/f/fpath", "/e/epath", "/d/dpath"}
+			sort.Strings(expectedPaths)
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderPreservedAdditionalBindings(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+						additional_bindings {
+							get: "/a/additional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+						additional_bindings {
+							get: "/z/zAdditional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+						additional_bindings {
+							get: "/b/bAdditional"
+						}
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, true, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/b/first", "/a/additional", "/a/second", "/z/zAdditional", "/c/third", "/b/bAdditional"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOneOfFieldBodyAdditionalBindings(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			oneof_decl: {
+				name: "foo"
+			}
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+				oneof_index: 0
+			}
+			field: {
+				name: "baz"
+				number: 2
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+				oneof_index: 0
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						post: "/b/foo"
+						body: "*"
+						additional_bindings {
+							post: "/b/foo/bar"
+							body: "bar"
+						}
+						additional_bindings {
+							post: "/b/foo/baz"
+							body: "baz"
+						}
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, true, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/b/foo", "/b/foo/bar", "/b/foo/baz"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+
+			// The input message only contains oneof fields, so no other fields should be mapped to the query.
+			if strings.Contains(content, "query") {
+				t.Fatalf("Found query in content, expected not to find any")
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderNotPreservedAdditionalBindings(t *testing.T) {
+	t.Parallel()
+
+	const in = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+						additional_bindings {
+							get: "/a/additional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+						additional_bindings {
+							get: "/z/zAdditional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+						additional_bindings {
+							get: "/b/bAdditional"
+						}
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	var req pluginpb.CodeGeneratorRequest
+	if err := prototext.Unmarshal([]byte(in), &req); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req, format, false, false)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/b/first", "/a/additional", "/a/second", "/z/zAdditional", "/c/third", "/b/bAdditional"}
+			sort.Strings(expectedPaths)
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderPreservedMergeFilesAdditionalBindingsMultipleServices(t *testing.T) {
+	t.Parallel()
+
+	const in1 = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestServiceOne"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		service: {
+			name: "TestServiceTwo"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/g/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	const in2 = `
+	file_to_generate: "exampleproto/v2/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v2/example.proto"
+		package: "example.v2"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/bpath"
+						additional_bindings {
+							get: "/a/additional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/apath"
+						additional_bindings {
+							get: "/z/zAdditional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/cpath"
+						additional_bindings {
+							get: "/b/bAdditional"
+						}
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v2;exampleproto"
+		}
+	}`
+
+	var req1, req2 pluginpb.CodeGeneratorRequest
+
+	if err := prototext.Unmarshal([]byte(in1), &req1); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+	if err := prototext.Unmarshal([]byte(in2), &req2); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	req1.ProtoFile = append(req1.ProtoFile, req2.ProtoFile...)
+	req1.FileToGenerate = append(req1.FileToGenerate, req2.FileToGenerate...)
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req1, format, true, true)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/d/first", "/e/second", "/c/third",
+				"/b/first", "/a/second", "/g/third", "/b/bpath", "/a/additional",
+				"/a/apath", "/z/zAdditional", "/c/cpath", "/b/bAdditional"}
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+func TestGenerateRPCOrderNotPreservedMergeFilesAdditionalBindingsMultipleServices(t *testing.T) {
+	t.Parallel()
+
+	const in1 = `
+	file_to_generate: "exampleproto/v1/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v1/example.proto"
+		package: "example.v1"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestServiceOne"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/d/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/e/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/third"
+					}
+				}
+			}
+		}
+		service: {
+			name: "TestServiceTwo"
+			method: {
+				name: "Test1"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/first"
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/second"
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v1.Foo"
+				output_type: ".example.v1.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/g/third"
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v1;exampleproto"
+		}
+	}`
+
+	const in2 = `
+	file_to_generate: "exampleproto/v2/example.proto"
+	parameter: "output_format=yaml,allow_delete_body=true"
+	proto_file: {
+		name: "exampleproto/v2/example.proto"
+		package: "example.v2"
+		message_type: {
+			name: "Foo"
+			field: {
+				name: "bar"
+				number: 1
+				label: LABEL_OPTIONAL
+				type: TYPE_STRING
+				json_name: "bar"
+			}
+		}
+		service: {
+			name: "TestService"
+			method: {
+				name: "Test1"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/b/bpath"
+						additional_bindings {
+							get: "/a/additional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test2"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/a/apath"
+						additional_bindings {
+							get: "/z/zAdditional"
+						}
+					}
+				}
+			}
+			method: {
+				name: "Test3"
+				input_type: ".example.v2.Foo"
+				output_type: ".example.v2.Foo"
+				options: {
+					[google.api.http]: {
+						get: "/c/cpath"
+						additional_bindings {
+							get: "/b/bAdditional"
+						}
+					}
+				}
+			}
+		}
+		options: {
+			go_package: "exampleproto/v2;exampleproto"
+		}
+	}`
+
+	var req1, req2 pluginpb.CodeGeneratorRequest
+
+	if err := prototext.Unmarshal([]byte(in1), &req1); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+	if err := prototext.Unmarshal([]byte(in2), &req2); err != nil {
+		t.Fatalf("failed to marshall yaml: %s", err)
+	}
+
+	req1.ProtoFile = append(req1.ProtoFile, req2.ProtoFile...)
+	req1.FileToGenerate = append(req1.FileToGenerate, req2.FileToGenerate...)
+	formats := [...]genopenapi.Format{
+		genopenapi.FormatJSON,
+		genopenapi.FormatYAML,
+	}
+
+	for _, format := range formats {
+		format := format
+		t.Run(string(format), func(t *testing.T) {
+			t.Parallel()
+
+			resp := requireGenerate(t, &req1, format, false, true)
+			if len(resp) != 1 {
+				t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
+			}
+
+			content := resp[0].GetContent()
+
+			t.Log(content)
+
+			contentsSlice := strings.Fields(content)
+			expectedPaths := []string{"/d/first", "/e/second", "/c/third",
+				"/b/first", "/a/second", "/g/third", "/b/bpath", "/a/additional",
+				"/a/apath", "/z/zAdditional", "/c/cpath", "/b/bAdditional"}
+			sort.Strings(expectedPaths)
+
+			foundPaths := []string{}
+			for _, contentValue := range contentsSlice {
+				findExpectedPaths(&foundPaths, expectedPaths, contentValue)
+			}
+
+			if allPresent := reflect.DeepEqual(foundPaths, expectedPaths); !allPresent {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, expectedPaths)
+			}
+		})
+	}
+}
+
+// Tries to find expected paths from a provided substring and store them in the foundPaths
+// slice.
+func findExpectedPaths(foundPaths *[]string, expectedPaths []string, potentialPath string) {
+	seenPaths := map[string]struct{}{}
+
+	// foundPaths may not be empty when this function is called multiple times,
+	// so we add them to seenPaths map to avoid duplicates.
+	for _, path := range *foundPaths {
+		seenPaths[path] = struct{}{}
+	}
+
+	for _, path := range expectedPaths {
+		_, pathAlreadySeen := seenPaths[path]
+		if strings.Contains(potentialPath, path) && !pathAlreadySeen {
+			*foundPaths = append(*foundPaths, path)
+			seenPaths[path] = struct{}{}
+		}
+	}
+}
+
+func TestFindExpectedPaths(t *testing.T) {
+	t.Parallel()
+
+	testCases := [...]struct {
+		testName           string
+		requiredPaths      []string
+		potentialPath      string
+		expectedPathsFound []string
+	}{
+		{
+			testName:           "One potential path present",
+			requiredPaths:      []string{"/d/first", "/e/second", "/c/third", "/b/first"},
+			potentialPath:      "[{\"path: \"/d/first\"",
+			expectedPathsFound: []string{"/d/first"},
+		},
+		{
+			testName:           "No potential Paths present",
+			requiredPaths:      []string{"/d/first", "/e/second", "/c/third", "/b/first"},
+			potentialPath:      "[{\"path: \"/z/zpath\"",
+			expectedPathsFound: []string{},
+		},
+		{
+			testName:           "Multiple potential paths present",
+			requiredPaths:      []string{"/d/first", "/e/second", "/c/third", "/b/first", "/d/first"},
+			potentialPath:      "[{\"path: \"/d/first\"someData\"/c/third\"someData\"/b/third\"",
+			expectedPathsFound: []string{"/d/first", "/c/third"},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(tc.testName, func(t *testing.T) {
+			t.Parallel()
+
+			foundPaths := []string{}
+			findExpectedPaths(&foundPaths, tc.requiredPaths, tc.potentialPath)
+			if correctPathsFound := reflect.DeepEqual(foundPaths, tc.expectedPathsFound); !correctPathsFound {
+				t.Fatalf("Found paths differed from expected paths. Got: %#v, want %#v", foundPaths, tc.expectedPathsFound)
+			}
+		})
+	}
+}
+
+func TestGenerateXGoType(t *testing.T) {
+	t.Parallel()
+
+	tests := []struct {
+		name           string
+		inputProtoText string
+		wantYAML       string
+	}{
+		{
+			name:           "x-go-type extension",
+			inputProtoText: "testdata/generator/x_go_type.prototext",
+			wantYAML:       "testdata/generator/x_go_type.swagger.yaml",
+		},
+	}
+
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
+
+			b, err := os.ReadFile(tt.inputProtoText)
+			if err != nil {
+				t.Fatal(err)
+			}
+			var req pluginpb.CodeGeneratorRequest
+			if err := prototext.Unmarshal(b, &req); err != nil {
+				t.Fatal(err)
+			}
+
+			reg := descriptor.NewRegistry()
+			reg.SetGenerateXGoType(true)
+			if err := reg.Load(&req); err != nil {
+				t.Fatalf("failed to load request: %s", err)
+			}
+
+			var targets []*descriptor.File
+			for _, target := range req.FileToGenerate {
+				f, err := reg.LookupFile(target)
+				if err != nil {
+					t.Fatalf("failed to lookup file: %s", err)
+				}
+				targets = append(targets, f)
+			}
+
+			g := genopenapi.New(reg, genopenapi.FormatYAML)
+			resp, err := g.Generate(targets)
+			if err != nil {
+				t.Fatalf("failed to generate: %s", err)
+			}
+
+			if len(resp) != 1 {
+				t.Fatalf("expected 1 file, got %d", len(resp))
+			}
+
+			want, err := os.ReadFile(tt.wantYAML)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			var gotMap, wantMap map[string]interface{}
+			if err := yaml.Unmarshal([]byte(resp[0].GetContent()), &gotMap); err != nil {
+				t.Fatalf("failed to unmarshal generated YAML: %v", err)
+			}
+			if err := yaml.Unmarshal(want, &wantMap); err != nil {
+				t.Fatalf("failed to unmarshal expected YAML: %v", err)
+			}
+
+			gotYAML, err := yaml.Marshal(gotMap)
+			if err != nil {
+				t.Fatalf("failed to marshal got YAML: %v", err)
+			}
+			wantYAML, err := yaml.Marshal(wantMap)
+			if err != nil {
+				t.Fatalf("failed to marshal want YAML: %v", err)
+			}
+
+			if !bytes.Equal(gotYAML, wantYAML) {
+				t.Errorf("YAMLs don't match:\ngot:\n%s\nwant:\n%s", gotYAML, wantYAML)
+			}
+		})
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/helpers.go b/protoc-gen-openapiv3/internal/genopenapi/helpers.go
new file mode 100644
index 00000000000..3eb0921b449
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/helpers.go
@@ -0,0 +1,36 @@
+//go:build go1.12
+// +build go1.12
+
+package genopenapi
+
+import (
+	"strings"
+
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+)
+
+func fieldName(k string) string {
+	return strings.ReplaceAll(cases.Title(language.AmericanEnglish).String(k), "-", "_")
+}
+
+// this method will filter the same fields and return the unique one
+func getUniqueFields(schemaFieldsRequired []string, fieldsRequired []string) []string {
+	var unique []string
+	var index *int
+
+	for j, schemaFieldRequired := range schemaFieldsRequired {
+		index = nil
+		for i, fieldRequired := range fieldsRequired {
+			i := i
+			if schemaFieldRequired == fieldRequired {
+				index = &i
+				break
+			}
+		}
+		if index == nil {
+			unique = append(unique, schemaFieldsRequired[j])
+		}
+	}
+	return unique
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/helpers_go111_old.go b/protoc-gen-openapiv3/internal/genopenapi/helpers_go111_old.go
new file mode 100644
index 00000000000..d2b504a9ab8
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/helpers_go111_old.go
@@ -0,0 +1,10 @@
+//go:build !go1.12
+// +build !go1.12
+
+package genopenapi
+
+import "strings"
+
+func fieldName(k string) string {
+	return strings.Replace(strings.Title(k), "-", "_", -1)
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/helpers_test.go b/protoc-gen-openapiv3/internal/genopenapi/helpers_test.go
new file mode 100644
index 00000000000..f27f589cb1c
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/helpers_test.go
@@ -0,0 +1,66 @@
+package genopenapi
+
+import (
+	"reflect"
+	"testing"
+)
+
+func Test_getUniqueFields(t *testing.T) {
+	type args struct {
+		schemaFieldsRequired []string
+		fieldsRequired       []string
+	}
+	var tests = []struct {
+		name string
+		args args
+		want []string
+	}{
+		{
+			name: "test_1",
+			args: args{
+				schemaFieldsRequired: []string{"Field_1", "Field_2", "Field_3"},
+				fieldsRequired:       []string{"Field_2"},
+			},
+			want: []string{"Field_1", "Field_3"},
+		},
+		{
+			name: "test_2",
+			args: args{
+				schemaFieldsRequired: []string{"Field_1", "Field_2", "Field_3"},
+				fieldsRequired:       []string{"Field_3"},
+			},
+			want: []string{"Field_1", "Field_2"},
+		},
+		{
+			name: "test_3",
+			args: args{
+				schemaFieldsRequired: []string{"Field_1", "Field_2", "Field_3"},
+				fieldsRequired:       []string{"Field_4"},
+			},
+			want: []string{"Field_1", "Field_2", "Field_3"},
+		},
+		{
+			name: "test_4",
+			args: args{
+				schemaFieldsRequired: []string{"Field_1", "Field_2", "Field_3", "Field_4", "Field_5", "Field_6"},
+				fieldsRequired:       []string{"Field_6", "Field_4", "Field_1"},
+			},
+			want: []string{"Field_2", "Field_3", "Field_5"},
+		},
+		{
+			name: "test_5",
+			args: args{
+				schemaFieldsRequired: []string{"Field_1", "Field_2", "Field_3"},
+				fieldsRequired:       []string{},
+			},
+			want: []string{"Field_1", "Field_2", "Field_3"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getUniqueFields(tt.args.schemaFieldsRequired, tt.args.fieldsRequired); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("getUniqueFields() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/naming.go b/protoc-gen-openapiv3/internal/genopenapi/naming.go
new file mode 100644
index 00000000000..2a9ac069036
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/naming.go
@@ -0,0 +1,141 @@
+package genopenapi
+
+import (
+	"reflect"
+	"regexp"
+	"strings"
+)
+
+// LookupNamingStrategy looks up the given naming strategy and returns the naming
+// strategy function for it. The naming strategy function takes in the list of all
+// fully-qualified proto message names, and returns a mapping from fully-qualified
+// name to OpenAPI name.
+func LookupNamingStrategy(strategyName string) func([]string) map[string]string {
+	switch strings.ToLower(strategyName) {
+	case "fqn":
+		return resolveNamesFQN
+	case "legacy":
+		return resolveNamesLegacy
+	case "simple":
+		return resolveNamesSimple
+	case "package":
+		return resolveNamesPackage
+	}
+	return nil
+}
+
+// resolveNamesFQN uses the fully-qualified proto message name as the
+// OpenAPI name, stripping the leading dot.
+func resolveNamesFQN(messages []string) map[string]string {
+	uniqueNames := make(map[string]string, len(messages))
+	for _, p := range messages {
+		// strip leading dot from proto fqn
+		uniqueNames[p] = p[1:]
+	}
+	return uniqueNames
+}
+
+// resolveNamesLegacy takes the names of all proto messages and generates unique references by
+// applying the legacy heuristics for deriving unique names: starting from the bottom of the name hierarchy, it
+// determines the minimum number of components necessary to yield a unique name, adds one
+// to that number, and then concatenates those last components with no separator in between
+// to form a unique name.
+//
+// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with fully
+// qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `bCD`.
+func resolveNamesLegacy(messages []string) map[string]string {
+	return resolveNamesUniqueWithContext(messages, 1, "", false)
+}
+
+// resolveNamesSimple takes the names of all proto messages and generates unique references by using a simple
+// heuristic: starting from the bottom of the name hierarchy, it determines the minimum
+// number of components necessary to yield a unique name, and then concatenates those last
+// components with a "." separator in between to form a unique name.
+//
+// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with
+// fully qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `C.D`.
+func resolveNamesSimple(messages []string) map[string]string {
+	return resolveNamesUniqueWithContext(messages, 0, ".", false)
+}
+
+// resolveNamesPackage takes the names of all proto messages and generates unique references by
+// starting with the package-scoped name (with nested message types qualified by their containing
+// "parent" types), and then following the "simple" heuristic above to add package name components
+// until each message has a unique name with a "." between each component.
+//
+// E.g., if the fully qualified name is `.a.b.C.D`, the name is `C.D` unless there is another
+// package-scoped name ending in "C.D", in  which case it would be `b.C.D` (unless that also
+// conflicted, in which case the name would be the fully-qualified `a.b.C`).
+func resolveNamesPackage(messages []string) map[string]string {
+	return resolveNamesUniqueWithContext(messages, 0, ".", true)
+}
+
+// For the "package" naming strategy, we rely on the convention that package names are lowercase
+// but message names are capitalized.
+var pkgEndRegexp = regexp.MustCompile(`\.[A-Z]`)
+
+// Take the names of every proto message and generates a unique reference by:
+// first, separating each message name into its components by splitting at dots. Then,
+// take the shortest suffix slice from each components slice that is unique among all
+// messages, and convert it into a component name by taking extraContext additional
+// components into consideration and joining all components with componentSeparator.
+func resolveNamesUniqueWithContext(messages []string, extraContext int, componentSeparator string, qualifyNestedMessages bool) map[string]string {
+	packagesByDepth := make(map[int][][]string)
+	uniqueNames := make(map[string]string)
+
+	hierarchy := func(pkg string) []string {
+		if !qualifyNestedMessages {
+			return strings.Split(pkg, ".")
+		}
+		pkgEnd := pkgEndRegexp.FindStringIndex(pkg)
+		if pkgEnd == nil {
+			// Fall back to non-qualified behavior if search based on convention fails.
+			return strings.Split(pkg, ".")
+		}
+		// Return each package component as an element, followed by the full message name
+		// (potentially qualified, if nested) as a single element.
+		qualifiedPkgName := pkg[:pkgEnd[0]]
+		nestedTypeName := pkg[pkgEnd[0]+1:]
+		return append(strings.Split(qualifiedPkgName, "."), nestedTypeName)
+	}
+
+	for _, p := range messages {
+		h := hierarchy(p)
+		for depth := range h {
+			if _, ok := packagesByDepth[depth]; !ok {
+				packagesByDepth[depth] = make([][]string, 0)
+			}
+			packagesByDepth[depth] = append(packagesByDepth[depth], h[len(h)-depth:])
+		}
+	}
+
+	count := func(list [][]string, item []string) int {
+		i := 0
+		for _, element := range list {
+			if reflect.DeepEqual(element, item) {
+				i++
+			}
+		}
+		return i
+	}
+
+	for _, p := range messages {
+		h := hierarchy(p)
+		depth := 0
+		for ; depth < len(h); depth++ {
+			// depth + extraContext > 0 ensures that we only break for values of depth when the
+			// resulting slice of name components is non-empty. Otherwise, we would return the
+			// empty string as the concise unique name is len(messages) == 1 (which is
+			// technically correct).
+			if depth+extraContext > 0 && count(packagesByDepth[depth], h[len(h)-depth:]) == 1 {
+				break
+			}
+		}
+		start := len(h) - depth - extraContext
+		if start < 0 {
+			start = 0
+		}
+		uniqueNames[p] = strings.Join(h[start:], componentSeparator)
+	}
+	return uniqueNames
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/naming_test.go b/protoc-gen-openapiv3/internal/genopenapi/naming_test.go
new file mode 100644
index 00000000000..22fa5ae9b55
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/naming_test.go
@@ -0,0 +1,63 @@
+package genopenapi
+
+import "testing"
+
+func TestNaming(t *testing.T) {
+	type expectedNames struct {
+		fqn, legacy, simple, pkg string
+	}
+	messageNameToExpected := map[string]expectedNames{
+		".A":     {"A", "A", "A", "A"},
+		".a.B.C": {"a.B.C", "aBC", "B.C", "B.C"},
+		".a.D.C": {"a.D.C", "aDC", "D.C", "D.C"},
+		".a.E.F": {"a.E.F", "aEF", "a.E.F", "a.E.F"},
+		".b.E.F": {"b.E.F", "bEF", "b.E.F", "b.E.F"},
+		".c.G.H": {"c.G.H", "GH", "H", "G.H"},
+	}
+
+	allMessageNames := make([]string, 0, len(messageNameToExpected))
+	for msgName := range messageNameToExpected {
+		allMessageNames = append(allMessageNames, msgName)
+	}
+
+	t.Run("fqn", func(t *testing.T) {
+		uniqueNames := resolveNamesFQN(allMessageNames)
+		for _, msgName := range allMessageNames {
+			expected := messageNameToExpected[msgName].fqn
+			actual := uniqueNames[msgName]
+			if expected != actual {
+				t.Errorf("fqn unique name %q does not match expected name %q", actual, expected)
+			}
+		}
+	})
+	t.Run("legacy", func(t *testing.T) {
+		uniqueNames := resolveNamesLegacy(allMessageNames)
+		for _, msgName := range allMessageNames {
+			expected := messageNameToExpected[msgName].legacy
+			actual := uniqueNames[msgName]
+			if expected != actual {
+				t.Errorf("legacy unique name %q does not match expected name %q", actual, expected)
+			}
+		}
+	})
+	t.Run("simple", func(t *testing.T) {
+		uniqueNames := resolveNamesSimple(allMessageNames)
+		for _, msgName := range allMessageNames {
+			expected := messageNameToExpected[msgName].simple
+			actual := uniqueNames[msgName]
+			if expected != actual {
+				t.Errorf("simple unique name %q does not match expected name %q", actual, expected)
+			}
+		}
+	})
+	t.Run("package", func(t *testing.T) {
+		uniqueNames := resolveNamesPackage(allMessageNames)
+		for _, msgName := range allMessageNames {
+			expected := messageNameToExpected[msgName].pkg
+			actual := uniqueNames[msgName]
+			if expected != actual {
+				t.Errorf("package unique name %q does not match expected name %q", actual, expected)
+			}
+		}
+	})
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/template.go b/protoc-gen-openapiv3/internal/genopenapi/template.go
new file mode 100644
index 00000000000..312e834c9ab
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/template.go
@@ -0,0 +1,3469 @@
+package genopenapi
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+	"net/textproto"
+	"os"
+	"reflect"
+	"regexp"
+	"slices"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+	"text/template"
+	"time"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options"
+	"google.golang.org/genproto/googleapis/api/annotations"
+	"google.golang.org/genproto/googleapis/api/visibility"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/descriptorpb"
+	"google.golang.org/protobuf/types/known/structpb"
+)
+
+// The OpenAPI specification does not allow for more than one endpoint with the same HTTP method and path.
+// This prevents multiple gRPC service methods from sharing the same stripped version of the path and method.
+// For example: `GET /v1/{name=organizations/*}/roles` and `GET /v1/{name=users/*}/roles` both get stripped to `GET /v1/{name}/roles`.
+// We must make the URL unique by adding a suffix and an incrementing index to each path parameter
+// to differentiate the endpoints.
+// Since path parameter names do not affect the request contents (i.e. they're replaced in the path)
+// this will be hidden from the real grpc gateway consumer.
+const pathParamUniqueSuffixDeliminator = "_"
+
+const paragraphDeliminator = "\n\n"
+
+// wktSchemas are the schemas of well-known-types.
+// The schemas must match with the behavior of the JSON unmarshaler in
+// https://github.com/protocolbuffers/protobuf-go/blob/v1.25.0/encoding/protojson/well_known_types.go
+var wktSchemas = map[string]schemaCore{
+	".google.protobuf.FieldMask": {
+		Type: "string",
+	},
+	".google.protobuf.Timestamp": {
+		Type:   "string",
+		Format: "date-time",
+	},
+	".google.protobuf.Duration": {
+		Type: "string",
+	},
+	".google.protobuf.StringValue": {
+		Type: "string",
+	},
+	".google.protobuf.BytesValue": {
+		Type:   "string",
+		Format: "byte",
+	},
+	".google.protobuf.Int32Value": {
+		Type:   "integer",
+		Format: "int32",
+	},
+	".google.protobuf.UInt32Value": {
+		Type:   "integer",
+		Format: "int64",
+	},
+	".google.protobuf.Int64Value": {
+		Type:   "string",
+		Format: "int64",
+	},
+	".google.protobuf.UInt64Value": {
+		Type:   "string",
+		Format: "uint64",
+	},
+	".google.protobuf.FloatValue": {
+		Type:   "number",
+		Format: "float",
+	},
+	".google.protobuf.DoubleValue": {
+		Type:   "number",
+		Format: "double",
+	},
+	".google.protobuf.BoolValue": {
+		Type: "boolean",
+	},
+	".google.protobuf.Empty": {
+		Type: "object",
+	},
+	".google.protobuf.Struct": {
+		Type: "object",
+	},
+	".google.protobuf.Value": {},
+	".google.protobuf.ListValue": {
+		Type: "array",
+		Items: (*openapiItemsObject)(&openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+		}),
+	},
+	".google.protobuf.NullValue": {
+		Type: "string",
+	},
+}
+
+func listEnumNames(reg *descriptor.Registry, enum *descriptor.Enum) interface{} {
+	var names []string
+	for _, value := range enum.GetValue() {
+		if !isVisible(getEnumValueVisibilityOption(value), reg) {
+			continue
+		}
+		if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 {
+			continue
+		}
+		names = append(names, value.GetName())
+	}
+
+	if len(names) > 0 {
+		return names
+	}
+
+	return nil
+}
+
+func listEnumNumbers(reg *descriptor.Registry, enum *descriptor.Enum) interface{} {
+	var numbers []int
+	for _, value := range enum.GetValue() {
+		if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 {
+			continue
+		}
+		if !isVisible(getEnumValueVisibilityOption(value), reg) {
+			continue
+		}
+		numbers = append(numbers, int(value.GetNumber()))
+	}
+
+	if len(numbers) > 0 {
+		return numbers
+	}
+
+	return nil
+}
+
+func getEnumDefault(reg *descriptor.Registry, enum *descriptor.Enum) interface{} {
+	if !reg.GetOmitEnumDefaultValue() {
+		for _, value := range enum.GetValue() {
+			if value.GetNumber() == 0 {
+				if !isVisible(getEnumValueVisibilityOption(value), reg) {
+					return nil
+				}
+				return value.GetName()
+			}
+		}
+	}
+	return nil
+}
+
+func getEnumDefaultNumber(reg *descriptor.Registry, enum *descriptor.Enum) interface{} {
+	if !reg.GetOmitEnumDefaultValue() {
+		for _, value := range enum.GetValue() {
+			if value.GetNumber() == 0 {
+				return int(value.GetNumber())
+			}
+		}
+	}
+	return nil
+}
+
+// messageToQueryParameters converts a message to a list of OpenAPI query parameters.
+func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, httpMethod string) (params []openapiParameterObject, err error) {
+	for _, field := range message.Fields {
+		// When body is set to oneof field, we want to skip other fields in the oneof group.
+		if isBodySameOneOf(body, field) {
+			continue
+		}
+
+		if !isVisible(getFieldVisibilityOption(field), reg) {
+			continue
+		}
+		if reg.GetAllowPatchFeature() && field.GetTypeName() == ".google.protobuf.FieldMask" && field.GetName() == "update_mask" && httpMethod == "PATCH" && len(body.FieldPath) != 0 {
+			continue
+		}
+
+		p, err := queryParams(message, field, "", reg, pathParams, body, reg.GetRecursiveDepth())
+		if err != nil {
+			return nil, err
+		}
+		params = append(params, p...)
+	}
+	return params, nil
+}
+
+func isBodySameOneOf(body *descriptor.Body, field *descriptor.Field) bool {
+	if field.OneofIndex == nil {
+		return false
+	}
+
+	if body == nil || len(body.FieldPath) == 0 {
+		return false
+	}
+
+	if body.FieldPath[0].Target.OneofIndex == nil {
+		return false
+	}
+
+	return *body.FieldPath[0].Target.OneofIndex == *field.OneofIndex
+}
+
+// queryParams converts a field to a list of OpenAPI query parameters recursively through the use of nestedQueryParams.
+func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, recursiveCount int) (params []openapiParameterObject, err error) {
+	return nestedQueryParams(message, field, prefix, reg, pathParams, body, newCycleChecker(recursiveCount))
+}
+
+type cycleChecker struct {
+	m     map[string]int
+	count int
+}
+
+func newCycleChecker(recursive int) *cycleChecker {
+	return &cycleChecker{
+		m:     make(map[string]int),
+		count: recursive,
+	}
+}
+
+// Check returns whether name is still within recursion
+// toleration
+func (c *cycleChecker) Check(name string) bool {
+	count, ok := c.m[name]
+	count += 1
+	isCycle := count > c.count
+
+	if isCycle {
+		return false
+	}
+
+	// provision map entry if not available
+	if !ok {
+		c.m[name] = 1
+		return true
+	}
+
+	c.m[name] = count
+
+	return true
+}
+
+func (c *cycleChecker) Branch() *cycleChecker {
+	copy := &cycleChecker{
+		count: c.count,
+		m:     make(map[string]int, len(c.m)),
+	}
+
+	for k, v := range c.m {
+		copy.m[k] = v
+	}
+
+	return copy
+}
+
+// nestedQueryParams converts a field to a list of OpenAPI query parameters recursively.
+// This function is a helper function for queryParams, that keeps track of cyclical message references
+// through the use of
+//
+//	touched map[string]int
+//
+// If a cycle is discovered, an error is returned, as cyclical data structures are dangerous
+// in query parameters.
+func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, cycle *cycleChecker) (params []openapiParameterObject, err error) {
+	// make sure the parameter is not already listed as a path parameter
+	for _, pathParam := range pathParams {
+		if pathParam.Target == field {
+			return nil, nil
+		}
+	}
+	// make sure the parameter is not already listed as a body parameter
+	if body != nil {
+		if body.FieldPath == nil {
+			return nil, nil
+		}
+		for _, fieldPath := range body.FieldPath {
+			if fieldPath.Target == field {
+				return nil, nil
+			}
+		}
+	}
+	schema := schemaOfField(field, reg, nil)
+	fieldType := field.GetTypeName()
+	if message.File != nil {
+		comments := fieldProtoComments(reg, message, field)
+		if err := updateOpenAPIDataFromComments(reg, &schema, message, comments, false); err != nil {
+			return nil, err
+		}
+	}
+
+	isEnum := field.GetType() == descriptorpb.FieldDescriptorProto_TYPE_ENUM
+	items := schema.Items
+	if schema.Type != "" || isEnum {
+		if schema.Type == "object" {
+			location := ""
+			if ix := strings.LastIndex(field.Message.FQMN(), "."); ix > 0 {
+				location = field.Message.FQMN()[0:ix]
+			}
+			if m, err := reg.LookupMsg(location, field.GetTypeName()); err == nil {
+				if opt := m.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
+					k := m.GetField()[0]
+					kType, err := getMapParamKey(k.GetType())
+					if err != nil {
+						return nil, err
+					}
+					// This will generate a query in the format map_name[key_type]
+					fName := fmt.Sprintf("%s[%s]", *field.Name, kType)
+					field.Name = proto.String(fName)
+					schema.Type = schema.AdditionalProperties.schemaCore.Type
+				}
+			}
+		}
+		if items != nil && (items.Type == "" || items.Type == "object") && !isEnum {
+			return nil, nil // TODO: currently, mapping object in query parameter is not supported
+		}
+		desc := mergeDescription(schema)
+
+		// verify if the field is required
+		required := false
+		for _, fieldName := range schema.Required {
+			if fieldName == reg.FieldName(field) {
+				required = true
+				break
+			}
+		}
+		// verify if the field is required in message options
+		if messageSchema, err := extractSchemaOptionFromMessageDescriptor(message.DescriptorProto); err == nil {
+			for _, fieldName := range messageSchema.GetJsonSchema().GetRequired() {
+				// Required fields can be field names or json_name values
+				if fieldName == field.GetJsonName() || fieldName == field.GetName() {
+					required = true
+					break
+				}
+			}
+		}
+
+		param := openapiParameterObject{
+			Description: desc,
+			In:          "query",
+			Default:     schema.Default,
+			Type:        schema.Type,
+			Items:       schema.Items,
+			Format:      schema.Format,
+			Pattern:     schema.Pattern,
+			Required:    required,
+			UniqueItems: schema.UniqueItems,
+			extensions:  schema.extensions,
+			Enum:        schema.Enum,
+		}
+		if param.Type == "array" {
+			param.CollectionFormat = "multi"
+		}
+
+		param.Name = prefix + reg.FieldName(field)
+
+		if isEnum {
+			enum, err := reg.LookupEnum("", fieldType)
+			if err != nil {
+				return nil, fmt.Errorf("unknown enum type %s", fieldType)
+			}
+			if items != nil { // array
+				param.Items = &openapiItemsObject{
+					schemaCore: schemaCore{
+						Type: "string",
+						Enum: listEnumNames(reg, enum),
+					},
+				}
+				if reg.GetEnumsAsInts() {
+					param.Items.Type = "integer"
+					param.Items.Enum = listEnumNumbers(reg, enum)
+				}
+			} else {
+				param.Type = "string"
+				param.Enum = listEnumNames(reg, enum)
+				param.Default = getEnumDefault(reg, enum)
+				if reg.GetEnumsAsInts() {
+					param.Type = "integer"
+					param.Enum = listEnumNumbers(reg, enum)
+					param.Default = getEnumDefaultNumber(reg, enum)
+				}
+			}
+			valueComments := enumValueProtoComments(reg, enum)
+			if valueComments != "" {
+				param.Description = strings.TrimLeft(param.Description+"\n\n "+valueComments, "\n")
+			}
+		}
+		return []openapiParameterObject{param}, nil
+	}
+
+	// nested type, recurse
+	msg, err := reg.LookupMsg("", fieldType)
+	if err != nil {
+		return nil, fmt.Errorf("unknown message type %s", fieldType)
+	}
+
+	// Check for cyclical message reference:
+	if ok := cycle.Check(*msg.Name); !ok {
+		return nil, fmt.Errorf("exceeded recursive count (%d) for query parameter %q", cycle.count, fieldType)
+	}
+
+	// Construct a new map with the message name so a cycle further down the recursive path can be detected.
+	// Do not keep anything in the original touched reference and do not pass that reference along.  This will
+	// prevent clobbering adjacent records while recursing.
+	touchedOut := cycle.Branch()
+
+	for _, nestedField := range msg.Fields {
+		if !isVisible(getFieldVisibilityOption(nestedField), reg) {
+			continue
+		}
+
+		fieldName := reg.FieldName(field)
+		p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, body, touchedOut)
+		if err != nil {
+			return nil, err
+		}
+		params = append(params, p...)
+	}
+	return params, nil
+}
+
+func getMapParamKey(t descriptorpb.FieldDescriptorProto_Type) (string, error) {
+	tType, f, ok := primitiveSchema(t)
+	if !ok || f == "byte" || f == "float" || f == "double" {
+		return "", fmt.Errorf("unsupported type: %q", f)
+	}
+	return tType, nil
+}
+
+// findServicesMessagesAndEnumerations discovers all messages and enums defined in the RPC methods of the service.
+func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descriptor.Registry, m messageMap, ms messageMap, e enumMap, refs refMap) {
+	for _, svc := range s {
+		if !isVisible(getServiceVisibilityOption(svc), reg) {
+			continue
+		}
+
+		for _, meth := range svc.Methods {
+			// Request may be fully included in query
+			{
+				if !isVisible(getMethodVisibilityOption(meth), reg) {
+					continue
+				}
+
+				swgReqName, ok := fullyQualifiedNameToOpenAPIName(meth.RequestType.FQMN(), reg)
+				if !ok {
+					grpclog.Errorf("couldn't resolve OpenAPI name for FQMN %q", meth.RequestType.FQMN())
+					continue
+				}
+				if _, ok := refs[fmt.Sprintf("#/definitions/%s", swgReqName)]; ok {
+					if !skipRenderingRef(meth.RequestType.FQMN()) {
+						m[swgReqName] = meth.RequestType
+					}
+				}
+			}
+
+			swgRspName, ok := fullyQualifiedNameToOpenAPIName(meth.ResponseType.FQMN(), reg)
+			if !ok && !skipRenderingRef(meth.ResponseType.FQMN()) {
+				grpclog.Errorf("couldn't resolve OpenAPI name for FQMN %q", meth.ResponseType.FQMN())
+				continue
+			}
+
+			findNestedMessagesAndEnumerations(meth.RequestType, reg, m, e)
+
+			if !skipRenderingRef(meth.ResponseType.FQMN()) {
+				m[swgRspName] = meth.ResponseType
+			}
+			findNestedMessagesAndEnumerations(meth.ResponseType, reg, m, e)
+		}
+	}
+}
+
+// findNestedMessagesAndEnumerations those can be generated by the services.
+func findNestedMessagesAndEnumerations(message *descriptor.Message, reg *descriptor.Registry, m messageMap, e enumMap) {
+	// Iterate over all the fields that
+	for _, t := range message.Fields {
+		if !isVisible(getFieldVisibilityOption(t), reg) {
+			continue
+		}
+
+		fieldType := t.GetTypeName()
+		// If the type is an empty string then it is a proto primitive
+		if fieldType != "" {
+			if _, ok := m[fieldType]; !ok {
+				msg, err := reg.LookupMsg("", fieldType)
+				if err != nil {
+					enum, err := reg.LookupEnum("", fieldType)
+					if err != nil {
+						panic(err)
+					}
+					e[fieldType] = enum
+					continue
+				}
+				m[fieldType] = msg
+				findNestedMessagesAndEnumerations(msg, reg, m, e)
+			}
+		}
+	}
+}
+
+func skipRenderingRef(refName string) bool {
+	_, ok := wktSchemas[refName]
+	return ok
+}
+
+func renderMessageAsDefinition(msg *descriptor.Message, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) {
+	schema := openapiSchemaObject{
+		schemaCore: schemaCore{
+			Type: "object",
+		},
+	}
+
+	if reg.GetGenerateXGoType() && msg.File.GoPkg.Path != "" {
+		if schema.extensions == nil {
+			schema.extensions = []extension{}
+		}
+		goTypeName := msg.GetName()
+
+		goTypeName = casing.JSONCamelCase(goTypeName)
+		schema.extensions = append(schema.extensions, extension{
+			key: "x-go-type",
+			value: json.RawMessage(`{
+                "import": {
+                    "package": "` + msg.File.GoPkg.Path + `"
+                },
+                "type": "` + goTypeName + `"
+            }`),
+		})
+	}
+
+	msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index))
+	if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil {
+		return openapiSchemaObject{}, err
+	}
+	opts, err := getMessageOpenAPIOption(reg, msg)
+	if err != nil {
+		return openapiSchemaObject{}, err
+	}
+	if opts != nil {
+		protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg)
+
+		// Warning: Make sure not to overwrite any fields already set on the schema type.
+		schema.ExternalDocs = protoSchema.ExternalDocs
+		schema.ReadOnly = protoSchema.ReadOnly
+		schema.MultipleOf = protoSchema.MultipleOf
+		schema.Maximum = protoSchema.Maximum
+		schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum
+		schema.Minimum = protoSchema.Minimum
+		schema.ExclusiveMinimum = protoSchema.ExclusiveMinimum
+		schema.MaxLength = protoSchema.MaxLength
+		schema.MinLength = protoSchema.MinLength
+		schema.Pattern = protoSchema.Pattern
+		schema.Default = protoSchema.Default
+		schema.MaxItems = protoSchema.MaxItems
+		schema.MinItems = protoSchema.MinItems
+		schema.UniqueItems = protoSchema.UniqueItems
+		schema.MaxProperties = protoSchema.MaxProperties
+		schema.MinProperties = protoSchema.MinProperties
+		schema.Required = protoSchema.Required
+		schema.XNullable = protoSchema.XNullable
+		schema.extensions = protoSchema.extensions
+		if protoSchema.schemaCore.Type != "" || protoSchema.schemaCore.Ref != "" {
+			schema.schemaCore = protoSchema.schemaCore
+		}
+		if protoSchema.Title != "" {
+			schema.Title = protoSchema.Title
+		}
+		if protoSchema.Description != "" {
+			schema.Description = protoSchema.Description
+		}
+		if protoSchema.Example != nil {
+			schema.Example = protoSchema.Example
+		}
+	}
+
+	schema.Required = filterOutExcludedFields(schema.Required, pathParams)
+
+	for _, f := range msg.Fields {
+		if !isVisible(getFieldVisibilityOption(f), reg) {
+			continue
+		}
+
+		if shouldExcludeField(f.GetName(), pathParams) {
+			continue
+		}
+		subPathParams := subPathParams(f.GetName(), pathParams)
+		fieldSchema, err := renderFieldAsDefinition(f, reg, customRefs, subPathParams)
+		if err != nil {
+			return openapiSchemaObject{}, err
+		}
+		comments := fieldProtoComments(reg, msg, f)
+		if err := updateOpenAPIDataFromComments(reg, &fieldSchema, f, comments, false); err != nil {
+			return openapiSchemaObject{}, err
+		}
+
+		if requiredIdx := find(schema.Required, *f.Name); requiredIdx != -1 && reg.GetUseJSONNamesForFields() {
+			schema.Required[requiredIdx] = f.GetJsonName()
+		}
+
+		if fieldSchema.Required != nil {
+			schema.Required = getUniqueFields(schema.Required, fieldSchema.Required)
+			schema.Required = append(schema.Required, fieldSchema.Required...)
+			// To avoid populating both the field schema require and message schema require, unset the field schema require.
+			// See issue #2635.
+			fieldSchema.Required = nil
+		}
+
+		if reg.GetUseAllOfForRefs() {
+			if fieldSchema.Ref != "" {
+				// Per the JSON Reference syntax: Any members other than "$ref" in a JSON Reference object SHALL be ignored.
+				// https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3
+				// However, use allOf to specify Title/Description/Example/readOnly fields.
+				if fieldSchema.Title != "" || fieldSchema.Description != "" || len(fieldSchema.Example) > 0 || fieldSchema.ReadOnly {
+					fieldSchema = openapiSchemaObject{
+						Title:       fieldSchema.Title,
+						Description: fieldSchema.Description,
+						schemaCore: schemaCore{
+							Example: fieldSchema.Example,
+						},
+						ReadOnly: fieldSchema.ReadOnly,
+						AllOf:    []allOfEntry{{Ref: fieldSchema.Ref}},
+					}
+				} else {
+					fieldSchema = openapiSchemaObject{schemaCore: schemaCore{Ref: fieldSchema.Ref}}
+				}
+			}
+		}
+
+		kv := keyVal{Value: fieldSchema}
+		kv.Key = reg.FieldName(f)
+		if schema.Properties == nil {
+			schema.Properties = &openapiSchemaObjectProperties{}
+		}
+		*schema.Properties = append(*schema.Properties, kv)
+	}
+
+	if msg.FQMN() == ".google.protobuf.Any" {
+		transformAnyForJSON(&schema, reg.GetUseJSONNamesForFields())
+	}
+
+	return schema, nil
+}
+
+func renderFieldAsDefinition(f *descriptor.Field, reg *descriptor.Registry, refs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) {
+	if len(pathParams) == 0 {
+		return schemaOfField(f, reg, refs), nil
+	}
+	location := ""
+	if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 {
+		location = f.Message.FQMN()[0:ix]
+	}
+	msg, err := reg.LookupMsg(location, f.GetTypeName())
+	if err != nil {
+		return openapiSchemaObject{}, err
+	}
+	schema, err := renderMessageAsDefinition(msg, reg, refs, pathParams)
+	if err != nil {
+		return openapiSchemaObject{}, err
+	}
+	comments := fieldProtoComments(reg, f.Message, f)
+	if len(comments) > 0 {
+		// Use title and description from field instead of nested message if present.
+		paragraphs := strings.Split(comments, paragraphDeliminator)
+		schema.Title = strings.TrimSpace(paragraphs[0])
+		schema.Description = strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator))
+	}
+
+	// to handle case where path param is present inside the field of descriptorpb.FieldDescriptorProto_TYPE_MESSAGE type
+	// it still needs to consider the behaviour of the field which was being done by schemaOfField() in case there are no path params
+	if j, err := getFieldBehaviorOption(reg, f); err == nil {
+		updateSwaggerObjectFromFieldBehavior(&schema, j, reg, f)
+	}
+
+	return schema, nil
+}
+
+// transformAnyForJSON should be called when the schema object represents a google.protobuf.Any, and will replace the
+// Properties slice with a single value for '@type'. We mutate the incorrectly named field so that we inherit the same
+// documentation as specified on the original field in the protobuf descriptors.
+func transformAnyForJSON(schema *openapiSchemaObject, useJSONNames bool) {
+	var typeFieldName string
+	if useJSONNames {
+		typeFieldName = "typeUrl"
+	} else {
+		typeFieldName = "type_url"
+	}
+
+	for _, property := range *schema.Properties {
+		if property.Key == typeFieldName {
+			schema.AdditionalProperties = &openapiSchemaObject{}
+			schema.Properties = &openapiSchemaObjectProperties{keyVal{
+				Key:   "@type",
+				Value: property.Value,
+			}}
+			break
+		}
+	}
+}
+
+func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) error {
+	for name, msg := range messages {
+		swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg)
+		if !ok {
+			return fmt.Errorf("can't resolve OpenAPI name from %q", msg.FQMN())
+		}
+		if skipRenderingRef(name) {
+			continue
+		}
+
+		if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
+			continue
+		}
+		var err error
+		d[swgName], err = renderMessageAsDefinition(msg, reg, customRefs, pathParams)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// isVisible checks if a field/RPC is visible based on the visibility restriction
+// combined with the `visibility_restriction_selectors`.
+// Elements with an overlap on `visibility_restriction_selectors` are visible, those without are not visible.
+// Elements without `google.api.VisibilityRule` annotations entirely are always visible.
+func isVisible(r *visibility.VisibilityRule, reg *descriptor.Registry) bool {
+	if r == nil {
+		return true
+	}
+
+	restrictions := strings.Split(strings.TrimSpace(r.Restriction), ",")
+	// No restrictions results in the element always being visible
+	if len(restrictions) == 0 {
+		return true
+	}
+
+	for _, restriction := range restrictions {
+		if reg.GetVisibilityRestrictionSelectors()[strings.TrimSpace(restriction)] {
+			return true
+		}
+	}
+
+	return false
+}
+
+func shouldExcludeField(name string, excluded []descriptor.Parameter) bool {
+	for _, p := range excluded {
+		if len(p.FieldPath) == 1 && name == p.FieldPath[0].Name {
+			return true
+		}
+	}
+	return false
+}
+
+func filterOutExcludedFields(fields []string, excluded []descriptor.Parameter) []string {
+	var filtered []string
+	for _, f := range fields {
+		if !shouldExcludeField(f, excluded) {
+			filtered = append(filtered, f)
+		}
+	}
+	return filtered
+}
+
+// schemaOfField returns a OpenAPI Schema Object for a protobuf field.
+func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) openapiSchemaObject {
+	const (
+		singular = 0
+		array    = 1
+		object   = 2
+	)
+	var (
+		core      schemaCore
+		aggregate int
+	)
+
+	fd := f.FieldDescriptorProto
+	location := ""
+	if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 {
+		location = f.Message.FQMN()[0:ix]
+	}
+	if m, err := reg.LookupMsg(location, f.GetTypeName()); err == nil {
+		if opt := m.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
+			fd = m.GetField()[1]
+			aggregate = object
+		}
+	}
+	if fd.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED {
+		aggregate = array
+	}
+
+	var props *openapiSchemaObjectProperties
+
+	switch ft := fd.GetType(); ft {
+	case descriptorpb.FieldDescriptorProto_TYPE_ENUM, descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP:
+		if wktSchema, ok := wktSchemas[fd.GetTypeName()]; ok {
+			core = wktSchema
+			if fd.GetTypeName() == ".google.protobuf.Empty" {
+				props = &openapiSchemaObjectProperties{}
+			}
+		} else {
+			swgRef, ok := fullyQualifiedNameToOpenAPIName(fd.GetTypeName(), reg)
+			if !ok {
+				panic(fmt.Sprintf("can't resolve OpenAPI ref from typename %q", fd.GetTypeName()))
+			}
+			core = schemaCore{
+				Ref: "#/definitions/" + swgRef,
+			}
+			if refs != nil {
+				refs[fd.GetTypeName()] = struct{}{}
+			}
+		}
+	default:
+		ftype, format, ok := primitiveSchema(ft)
+		if ok {
+			core = schemaCore{Type: ftype, Format: format}
+		} else {
+			core = schemaCore{Type: ft.String(), Format: "UNKNOWN"}
+		}
+	}
+
+	ret := openapiSchemaObject{}
+
+	switch aggregate {
+	case array:
+		if _, ok := wktSchemas[fd.GetTypeName()]; !ok && fd.GetType() == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE {
+			core.Type = "object"
+		}
+		ret = openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type:  "array",
+				Items: (*openapiItemsObject)(&openapiSchemaObject{schemaCore: core}),
+			},
+		}
+	case object:
+		ret = openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+			AdditionalProperties: &openapiSchemaObject{Properties: props, schemaCore: core},
+		}
+	default:
+		ret = openapiSchemaObject{
+			schemaCore: core,
+			Properties: props,
+		}
+	}
+
+	if j, err := getFieldOpenAPIOption(reg, f); err == nil {
+		updateswaggerObjectFromJSONSchema(&ret, j, reg, f)
+	}
+
+	if j, err := getFieldBehaviorOption(reg, f); err == nil {
+		updateSwaggerObjectFromFieldBehavior(&ret, j, reg, f)
+	}
+
+	for i, required := range ret.Required {
+		if required == f.GetName() {
+			ret.Required[i] = reg.FieldName(f)
+		}
+	}
+
+	slices.Sort(ret.Required)
+	ret.Required = slices.Compact(ret.Required)
+
+	if reg.GetProto3OptionalNullable() && f.GetProto3Optional() {
+		ret.XNullable = true
+	}
+
+	return ret
+}
+
+// primitiveSchema returns a pair of "Type" and "Format" in JSON Schema for
+// the given primitive field type.
+// The last return parameter is true iff the field type is actually primitive.
+func primitiveSchema(t descriptorpb.FieldDescriptorProto_Type) (ftype, format string, ok bool) {
+	switch t {
+	case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE:
+		return "number", "double", true
+	case descriptorpb.FieldDescriptorProto_TYPE_FLOAT:
+		return "number", "float", true
+	case descriptorpb.FieldDescriptorProto_TYPE_INT64:
+		return "string", "int64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_UINT64:
+		// 64bit integer types are marshaled as string in the default JSONPb marshaler.
+		// TODO(yugui) Add an option to declare 64bit integers as int64.
+		//
+		// NOTE: uint64 is not a predefined format of integer type in OpenAPI spec.
+		// So we cannot expect that uint64 is commonly supported by OpenAPI processor.
+		return "string", "uint64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_INT32:
+		return "integer", "int32", true
+	case descriptorpb.FieldDescriptorProto_TYPE_FIXED64:
+		// Ditto.
+		return "string", "uint64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_FIXED32:
+		// Ditto.
+		return "integer", "int64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_BOOL:
+		// NOTE: in OpenAPI specification, format should be empty on boolean type
+		return "boolean", "", true
+	case descriptorpb.FieldDescriptorProto_TYPE_STRING:
+		// NOTE: in OpenAPI specification, can be empty on string type
+		// see: https://swagger.io/specification/v2/#data-types
+		return "string", "", true
+	case descriptorpb.FieldDescriptorProto_TYPE_BYTES:
+		return "string", "byte", true
+	case descriptorpb.FieldDescriptorProto_TYPE_UINT32:
+		// Ditto.
+		return "integer", "int64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_SFIXED32:
+		return "integer", "int32", true
+	case descriptorpb.FieldDescriptorProto_TYPE_SFIXED64:
+		return "string", "int64", true
+	case descriptorpb.FieldDescriptorProto_TYPE_SINT32:
+		return "integer", "int32", true
+	case descriptorpb.FieldDescriptorProto_TYPE_SINT64:
+		return "string", "int64", true
+	default:
+		return "", "", false
+	}
+}
+
+// renderEnumerationsAsDefinition inserts enums into the definitions object.
+func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap) {
+	for _, enum := range enums {
+		swgName, ok := fullyQualifiedNameToOpenAPIName(enum.FQEN(), reg)
+		if !ok {
+			panic(fmt.Sprintf("can't resolve OpenAPI name from FQEN %q", enum.FQEN()))
+		}
+		enumComments := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index))
+
+		// it may be necessary to sort the result of the GetValue function.
+		enumNames := listEnumNames(reg, enum)
+		defaultValue := getEnumDefault(reg, enum)
+		valueComments := enumValueProtoComments(reg, enum)
+		if valueComments != "" {
+			enumComments = strings.TrimLeft(enumComments+"\n\n "+valueComments, "\n")
+		}
+		enumSchemaObject := openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type:    "string",
+				Enum:    enumNames,
+				Default: defaultValue,
+			},
+		}
+
+		if reg.GetEnumsAsInts() {
+			enumSchemaObject.Type = "integer"
+			enumSchemaObject.Format = "int32"
+			enumSchemaObject.Default = getEnumDefaultNumber(reg, enum)
+			enumSchemaObject.Enum = listEnumNumbers(reg, enum)
+		}
+		opts, err := getEnumOpenAPIOption(reg, enum)
+		if err != nil {
+			panic(err)
+		}
+		if opts != nil {
+			protoSchema := openapiSchemaFromProtoEnumSchema(opts, reg, customRefs, enum)
+			// Warning: Make sure not to overwrite any fields already set on the schema type.
+			// This is only a subset of the fields from JsonSchema since most of them only apply to arrays or objects not enums
+			enumSchemaObject.ExternalDocs = protoSchema.ExternalDocs
+			enumSchemaObject.ReadOnly = protoSchema.ReadOnly
+			enumSchemaObject.extensions = protoSchema.extensions
+			if protoSchema.Type != "" || protoSchema.Ref != "" {
+				enumSchemaObject.schemaCore = protoSchema.schemaCore
+			}
+			if protoSchema.Title != "" {
+				enumSchemaObject.Title = protoSchema.Title
+			}
+			if protoSchema.Description != "" {
+				enumSchemaObject.Description = protoSchema.Description
+			}
+			if protoSchema.Example != nil {
+				enumSchemaObject.Example = protoSchema.Example
+			}
+		}
+		if err := updateOpenAPIDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil {
+			panic(err)
+		}
+
+		d[swgName] = enumSchemaObject
+	}
+}
+
+// Take in a FQMN or FQEN and return a OpenAPI safe version of the FQMN and
+// a boolean indicating if FQMN was properly resolved.
+func fullyQualifiedNameToOpenAPIName(fqn string, reg *descriptor.Registry) (string, bool) {
+	registriesSeenMutex.Lock()
+	defer registriesSeenMutex.Unlock()
+	if mapping, present := registriesSeen[reg]; present {
+		ret, ok := mapping[fqn]
+		return ret, ok
+	}
+	mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), append(reg.GetAllFQENs(), reg.GetAllFQMethNs()...)...), reg.GetOpenAPINamingStrategy())
+	registriesSeen[reg] = mapping
+	ret, ok := mapping[fqn]
+	return ret, ok
+}
+
+// Lookup message type by location.name and return an openapiv2-safe version
+// of its FQMN.
+func lookupMsgAndOpenAPIName(location, name string, reg *descriptor.Registry) (*descriptor.Message, string, error) {
+	msg, err := reg.LookupMsg(location, name)
+	if err != nil {
+		return nil, "", err
+	}
+	swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg)
+	if !ok {
+		return nil, "", fmt.Errorf("can't map OpenAPI name from FQMN %q", msg.FQMN())
+	}
+	return msg, swgName, nil
+}
+
+// registriesSeen is used to memoise calls to resolveFullyQualifiedNameToOpenAPINames so
+// we don't repeat it unnecessarily, since it can take some time.
+var (
+	registriesSeen      = map[*descriptor.Registry]map[string]string{}
+	registriesSeenMutex sync.Mutex
+)
+
+// Take the names of every proto message and generate a unique reference for each, according to the given strategy.
+func resolveFullyQualifiedNameToOpenAPINames(messages []string, namingStrategy string) map[string]string {
+	strategyFn := LookupNamingStrategy(namingStrategy)
+	if strategyFn == nil {
+		return nil
+	}
+	return strategyFn(messages)
+}
+
+var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*)([^}]*)}")
+
+// templateToParts splits a URL template into path segments for use by `partsToOpenAPIPath` and `partsToRegexpMap`.
+//
+// Parameters:
+//   - path:	The URL template as defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto
+//   - reg:	The descriptor registry used to read compiler flags
+//   - fields:	The fields of the request message, only used when `useJSONNamesForFields` is true
+//   - msgs:	The Messages of the service binding, only used when `useJSONNamesForFields` is true
+//
+// Returns:
+//
+//	The path segments of the URL template.
+func templateToParts(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) []string {
+	// It seems like the right thing to do here is to just use
+	// strings.Split(path, "/") but that breaks badly when you hit a url like
+	// /{my_field=prefix/*}/ and end up with 2 sections representing my_field.
+	// Instead do the right thing and write a small pushdown (counter) automata
+	// for it.
+	var parts []string
+	depth := 0
+	buffer := ""
+	for i, char := range path {
+		switch char {
+		case '{':
+			// Push on the stack
+			depth++
+			buffer += string(char)
+		case '}':
+			if depth == 0 {
+				panic("Encountered } without matching { before it.")
+			}
+			// Pop from the stack
+			depth--
+			if !reg.GetUseJSONNamesForFields() {
+				buffer += string(char)
+				continue
+			}
+			paramNameProto := strings.SplitN(buffer[1:], "=", 2)[0]
+			paramNameCamelCase := lowerCamelCase(paramNameProto, fields, msgs)
+			buffer = strings.Join([]string{"{", paramNameCamelCase, buffer[len(paramNameProto)+1:], "}"}, "")
+		case '/':
+			if depth == 0 {
+				parts = append(parts, buffer)
+				buffer = ""
+				// Since the stack was empty when we hit the '/' we are done with this
+				// section.
+				continue
+			}
+			buffer += string(char)
+		case ':':
+			if depth == 0 {
+				// Only treat this as a verb if we're at the end of the path or
+				// if there are no more path segments (only more literals after the colon)
+				remainingPath := path[i:]
+				if !strings.Contains(remainingPath, "/") {
+					parts = append(parts, buffer)
+					verbSegment := remainingPath
+					if reg.GetUseJSONNamesForFields() {
+						verbSegment = processParametersInSegment(verbSegment, fields, msgs)
+					}
+					parts = append(parts, verbSegment)
+					return parts
+				}
+			}
+			buffer += string(char)
+		default:
+			buffer += string(char)
+		}
+	}
+
+	// Now append the last element to parts
+	parts = append(parts, buffer)
+
+	return parts
+}
+
+// processParametersInSegment processes a path segment (like ":verb/{param}") to convert
+// parameter names to camelCase while preserving the overall structure
+func processParametersInSegment(segment string, fields []*descriptor.Field, msgs []*descriptor.Message) string {
+	result := segment
+	depth := 0
+	var paramStart int
+	for i, char := range segment {
+		switch char {
+		case '{':
+			if depth == 0 {
+				paramStart = i
+			}
+			depth++
+		case '}':
+			depth--
+			if depth == 0 {
+				paramContent := segment[paramStart+1 : i]
+				paramNameProto := strings.SplitN(paramContent, "=", 2)[0]
+				paramNameCamelCase := lowerCamelCase(paramNameProto, fields, msgs)
+
+				oldParam := "{" + paramContent + "}"
+				newParam := "{" + paramNameCamelCase
+				if strings.Contains(paramContent, "=") {
+					newParam += paramContent[len(paramNameProto):]
+				}
+				newParam += "}"
+
+				result = strings.Replace(result, oldParam, newParam, 1)
+			}
+		}
+	}
+	return result
+}
+
+// partsToOpenAPIPath converts each path part of the form /path/{string_value=strprefix/*} which is defined in
+// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto to the OpenAPI expected form /path/{string_value}.
+// For example this would replace the path segment of "{foo=bar/*}" with "{foo}" or "prefix{bang=bash/**}" with "prefix{bang}".
+// OpenAPI 2 only allows simple path parameters with the constraints on that parameter specified in the OpenAPI
+// schema's "pattern" instead of in the path parameter itself.
+func partsToOpenAPIPath(parts []string, overrides map[string]string) string {
+	for index, part := range parts {
+		part = canRegexp.ReplaceAllString(part, "{$1}")
+
+		if override, ok := overrides[part]; ok {
+			part = override
+		}
+		parts[index] = part
+	}
+	if last := len(parts) - 1; strings.HasPrefix(parts[last], ":") {
+		// Last item is a verb (":" LITERAL).
+		return strings.Join(parts[:last], "/") + parts[last]
+	}
+	return strings.Join(parts, "/")
+}
+
+// partsToRegexpMap returns a map of parameter name to ECMA 262 patterns
+// which is what the "pattern" field on an OpenAPI parameter expects.
+// See https://swagger.io/specification/v2/ (Parameter Object) and
+// https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+// The expression is generated based on expressions defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto
+// "Path Template Syntax" section which allow for a "param_name=foobar/*/bang/**" style expressions inside
+// the path parameter placeholders that indicate constraints on the values of those parameters.
+// This function will scan the split parts of a path template for parameters and
+// outputs a map of the name of the parameter to a ECMA regular expression.  See the http.proto file for descriptions
+// of the supported syntax. This function will ignore any path parameters that don't contain a "=" after the
+// parameter name.  For supported parameters, we assume "*" represent all characters except "/" as it's
+// intended to match a single path element and we assume "**" matches any character as it's intended to match multiple
+// path elements.
+// For example "{name=organizations/*/roles/*}" would produce the regular expression for the "name" parameter of
+// "organizations/[^/]+/roles/[^/]+" or "{bar=bing/*/bang/**}" would produce the regular expression for the "bar"
+// parameter of "bing/[^/]+/bang/.+".
+//
+// Note that OpenAPI does not actually support path parameters with "/", see https://github.com/OAI/OpenAPI-Specification/issues/892
+func partsToRegexpMap(parts []string) map[string]string {
+	regExps := make(map[string]string)
+	for _, part := range parts {
+		if strings.Contains(part, "/") {
+			grpclog.Warningf("Path parameter %q contains '/', which is not supported in OpenAPI", part)
+		}
+		if submatch := canRegexp.FindStringSubmatch(part); len(submatch) > 2 {
+			if strings.HasPrefix(submatch[2], "=") { // this part matches the standard and should be made into a regular expression
+				// assume the string's characters other than "**" and "*" are literals (not necessarily a good assumption 100% of the times, but it will support most use cases)
+				regex := submatch[2][1:]
+				regex = strings.ReplaceAll(regex, "**", ".+")   // ** implies any character including "/"
+				regex = strings.ReplaceAll(regex, "*", "[^/]+") // * implies any character except "/"
+				regExps[submatch[1]] = regex
+			}
+		}
+	}
+	return regExps
+}
+
+func renderServiceTags(services []*descriptor.Service, reg *descriptor.Registry) []openapiTagObject {
+	var tags []openapiTagObject
+	for _, svc := range services {
+		if !isVisible(getServiceVisibilityOption(svc), reg) {
+			continue
+		}
+		tagName := svc.GetName()
+		if pkg := svc.File.GetPackage(); pkg != "" && reg.IsIncludePackageInTags() {
+			tagName = pkg + "." + tagName
+		}
+
+		tag := openapiTagObject{
+			Name: tagName,
+		}
+
+		opts, err := getServiceOpenAPIOption(reg, svc)
+		if err != nil {
+			grpclog.Error(err)
+			return nil
+		}
+		if opts != nil {
+			tag.Description = opts.Description
+			if reg.GetUseGoTemplate() {
+				tag.Description = goTemplateComments(tag.Description, svc, reg)
+			}
+			if opts.ExternalDocs != nil {
+				tag.ExternalDocs = &openapiExternalDocumentationObject{
+					Description: opts.ExternalDocs.Description,
+					URL:         opts.ExternalDocs.Url,
+				}
+				if reg.GetUseGoTemplate() {
+					tag.ExternalDocs.Description = goTemplateComments(opts.ExternalDocs.Description, svc, reg)
+				}
+			}
+			if opts.GetName() != "" {
+				tag.Name = opts.GetName()
+			}
+		}
+		tags = append(tags, tag)
+	}
+	return tags
+}
+
+// expandPathPatterns searches the URI parts for path parameters with pattern and when the pattern contains a sub-path,
+// it expands the pattern into the URI parts and adds the new path parameters to the pathParams slice.
+//
+// Parameters:
+//   - pathParts:	the URI parts parsed from the path template with `templateToParts` function
+//   - pathParams: the path parameters of the service binding
+//
+// Returns:
+//
+//	The modified pathParts and pathParams slice.
+func expandPathPatterns(pathParts []string, pathParams []descriptor.Parameter, reg *descriptor.Registry) ([]string, []descriptor.Parameter) {
+	expandedPathParts := []string{}
+	modifiedPathParams := pathParams
+	for _, pathPart := range pathParts {
+		if !strings.HasPrefix(pathPart, "{") || !strings.HasSuffix(pathPart, "}") {
+			expandedPathParts = append(expandedPathParts, pathPart)
+			continue
+		}
+		woBraces := pathPart[1 : len(pathPart)-1]
+		paramPattern := strings.SplitN(woBraces, "=", 2)
+		if len(paramPattern) != 2 {
+			expandedPathParts = append(expandedPathParts, pathPart)
+			continue
+		}
+		paramName := paramPattern[0]
+		pattern := paramPattern[1]
+		if pattern == "*" {
+			expandedPathParts = append(expandedPathParts, pathPart)
+			continue
+		}
+		pathParamIndex := slices.IndexFunc(modifiedPathParams, func(p descriptor.Parameter) bool {
+			if !reg.GetUseJSONNamesForFields() {
+				return p.FieldPath.String() == paramName
+			}
+			fieldPath := casing.JSONCamelCase(p.FieldPath.String())
+			return fieldPath == paramName
+		})
+		if pathParamIndex == -1 {
+			panic(fmt.Sprintf("Path parameter %q not found in path parameters", paramName))
+		}
+		pathParam := modifiedPathParams[pathParamIndex]
+		patternParts := strings.Split(pattern, "/")
+		for _, patternPart := range patternParts {
+			if patternPart != "*" {
+				expandedPathParts = append(expandedPathParts, patternPart)
+				continue
+			}
+			lastPart := expandedPathParts[len(expandedPathParts)-1]
+			paramName := strings.TrimSuffix(lastPart, "s")
+			if reg.GetUseJSONNamesForFields() {
+				paramName = casing.JSONCamelCase(paramName)
+			}
+			expandedPathParts = append(expandedPathParts, "{"+paramName+"}")
+			newParam := descriptor.Parameter{
+				Target: &descriptor.Field{
+					FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+						Name: proto.String(paramName),
+						Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					},
+					Message:           pathParam.Target.Message,
+					FieldMessage:      pathParam.Target.FieldMessage,
+					ForcePrefixedName: pathParam.Target.ForcePrefixedName,
+				},
+				FieldPath: []descriptor.FieldPathComponent{{
+					Name:   paramName,
+					Target: nil,
+				}},
+				Method: nil,
+			}
+			modifiedPathParams = append(modifiedPathParams, newParam)
+			if pathParamIndex != -1 {
+				// the new parameter from the pattern replaces the old path parameter
+				modifiedPathParams = append(modifiedPathParams[:pathParamIndex], modifiedPathParams[pathParamIndex+1:]...)
+				pathParamIndex = -1
+			}
+		}
+	}
+	return expandedPathParts, modifiedPathParams
+}
+
+func renderServices(services []*descriptor.Service, paths *openapiPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message, defs openapiDefinitionsObject) error {
+	// Correctness of svcIdx and methIdx depends on 'services' containing the services in the same order as the 'file.Service' array.
+	svcBaseIdx := 0
+	var lastFile *descriptor.File = nil
+	for svcIdx, svc := range services {
+		if svc.File != lastFile {
+			lastFile = svc.File
+			svcBaseIdx = svcIdx
+		}
+
+		if !isVisible(getServiceVisibilityOption(svc), reg) {
+			continue
+		}
+
+		for methIdx, meth := range svc.Methods {
+			if !isVisible(getMethodVisibilityOption(meth), reg) {
+				continue
+			}
+
+			deprecated := reg.GetEnableRpcDeprecation() && meth.GetOptions().GetDeprecated()
+
+			for bIdx, b := range meth.Bindings {
+				operationFunc := operationForMethod(b.HTTPMethod)
+				// Iterate over all the OpenAPI parameters
+				parameters := openapiParametersObject{}
+				// split the path template into its parts
+				parts := templateToParts(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)
+				pathParams := b.PathParams
+				if reg.GetExpandSlashedPathPatterns() {
+					parts, pathParams = expandPathPatterns(parts, pathParams, reg)
+				}
+				// extract any constraints specified in the path placeholders into ECMA regular expressions
+				pathParamRegexpMap := partsToRegexpMap(parts)
+				// Keep track of path parameter overrides
+				pathParamNames := make(map[string]string)
+				for _, parameter := range pathParams {
+
+					var paramType, paramFormat, desc, collectionFormat string
+					var defaultValue interface{}
+					var enumNames interface{}
+					var items *openapiItemsObject
+					var minItems *int
+					var extensions []extension
+					switch pt := parameter.Target.GetType(); pt {
+					case descriptorpb.FieldDescriptorProto_TYPE_GROUP, descriptorpb.FieldDescriptorProto_TYPE_MESSAGE:
+						if descriptor.IsWellKnownType(parameter.Target.GetTypeName()) {
+							if parameter.IsRepeated() {
+								return errors.New("only primitive and enum types are allowed in repeated path parameters")
+							}
+							schema := schemaOfField(parameter.Target, reg, customRefs)
+							paramType = schema.Type
+							paramFormat = schema.Format
+							desc = schema.Description
+							defaultValue = schema.Default
+							extensions = schema.extensions
+						} else {
+							return errors.New("only primitive and well-known types are allowed in path parameters")
+						}
+					case descriptorpb.FieldDescriptorProto_TYPE_ENUM:
+						enum, err := reg.LookupEnum("", parameter.Target.GetTypeName())
+						if err != nil {
+							return err
+						}
+						paramType = "string"
+						paramFormat = ""
+						enumNames = listEnumNames(reg, enum)
+						if reg.GetEnumsAsInts() {
+							paramType = "integer"
+							paramFormat = ""
+							enumNames = listEnumNumbers(reg, enum)
+						}
+
+						schema := schemaOfField(parameter.Target, reg, customRefs)
+						desc = schema.Description
+						defaultValue = schema.Default
+						extensions = schema.extensions
+					default:
+						var ok bool
+						paramType, paramFormat, ok = primitiveSchema(pt)
+						if !ok {
+							return fmt.Errorf("unknown field type %v", pt)
+						}
+
+						schema := schemaOfField(parameter.Target, reg, customRefs)
+						desc = schema.Description
+						defaultValue = schema.Default
+						extensions = schema.extensions
+						// If there is no mandatory format based on the field,
+						// allow it to be overridden by the user
+						if paramFormat == "" {
+							paramFormat = schema.Format
+						}
+					}
+
+					if parameter.IsRepeated() {
+						core := schemaCore{Type: paramType, Format: paramFormat}
+						if parameter.IsEnum() {
+							core.Enum = enumNames
+							enumNames = nil
+						}
+						items = (*openapiItemsObject)(&openapiSchemaObject{schemaCore: core})
+						paramType = "array"
+						paramFormat = ""
+						collectionFormat = reg.GetRepeatedPathParamSeparatorName()
+						minItems = new(int)
+						*minItems = 1
+					}
+
+					if desc == "" {
+						desc = fieldProtoComments(reg, parameter.Target.Message, parameter.Target)
+					}
+					parameterString := parameter.String()
+					if reg.GetUseJSONNamesForFields() {
+						parameterString = lowerCamelCase(parameterString, meth.RequestType.Fields, msgs)
+					}
+					var pattern string
+					if regExp, ok := pathParamRegexpMap[parameterString]; ok {
+						pattern = regExp
+					}
+					if fc := getFieldConfiguration(reg, parameter.Target); fc != nil {
+						pathParamName := fc.GetPathParamName()
+						if pathParamName != "" && pathParamName != parameterString {
+							pathParamNames["{"+parameterString+"}"] = "{" + pathParamName + "}"
+							parameterString, _, _ = strings.Cut(pathParamName, "=")
+						}
+					}
+					parameters = append(parameters, openapiParameterObject{
+						Name:        parameterString,
+						Description: desc,
+						In:          "path",
+						Required:    true,
+						Default:     defaultValue,
+						// Parameters in gRPC-Gateway can only be strings?
+						Type:             paramType,
+						Format:           paramFormat,
+						Enum:             enumNames,
+						Items:            items,
+						CollectionFormat: collectionFormat,
+						MinItems:         minItems,
+						Pattern:          pattern,
+						extensions:       extensions,
+					})
+				}
+				// Now check if there is a body parameter
+				if b.Body != nil {
+					// Recursively render fields as definitions as long as they contain path parameters.
+					// Special case for top level body if we don't have a body field.
+					var schema openapiSchemaObject
+					desc := ""
+					var bodyFieldName string
+					schema = openapiSchemaObject{
+						schemaCore: schemaCore{},
+					}
+					if len(b.Body.FieldPath) == 0 {
+						// No field for body, use type.
+						bodyFieldName = "body"
+						wknSchemaCore, isWkn := wktSchemas[meth.RequestType.FQMN()]
+						if isWkn {
+							schema.schemaCore = wknSchemaCore
+							// Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher.
+							if meth.RequestType.FQMN() == ".google.protobuf.Empty" {
+								schema.Properties = &openapiSchemaObjectProperties{}
+							}
+						} else {
+							messageSchema, err := renderMessageAsDefinition(meth.RequestType, reg, customRefs, b.PathParams)
+							if err != nil {
+								return err
+							}
+							if len(b.PathParams) == 0 {
+								if err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg); err != nil {
+									return err
+								}
+								desc = messageSchema.Description
+							} else {
+								if meth.Name != nil {
+									methFQN, ok := fullyQualifiedNameToOpenAPIName(meth.FQMN(), reg)
+									if !ok {
+										panic(fmt.Errorf("failed to resolve method FQN: '%s'", meth.FQMN()))
+									}
+									defName := methFQN + "Body"
+									schema.Ref = fmt.Sprintf("#/definitions/%s", defName)
+									defs[defName] = messageSchema
+								} else {
+									schema = messageSchema
+									if schema.Properties == nil || len(*schema.Properties) == 0 {
+										grpclog.Warningf("created a body with 0 properties in the message, this might be unintended: %s", *meth.RequestType)
+									}
+								}
+							}
+						}
+					} else {
+						// Body field path is limited to one path component. From google.api.HttpRule.body:
+						// "NOTE: the referred field must be present at the top-level of the request message type."
+						// Ref: https://github.com/googleapis/googleapis/blob/b3397f5febbf21dfc69b875ddabaf76bee765058/google/api/http.proto#L350-L352
+						if len(b.Body.FieldPath) > 1 {
+							return fmt.Errorf("body of request %q is not a top level field: '%v'", meth.Service.GetName(), b.Body.FieldPath)
+						}
+						bodyField := b.Body.FieldPath[0]
+						if reg.GetUseJSONNamesForFields() {
+							bodyFieldName = lowerCamelCase(bodyField.Name, meth.RequestType.Fields, msgs)
+						} else {
+							bodyFieldName = bodyField.Name
+						}
+						// Align pathParams with body field path.
+						pathParams := subPathParams(bodyField.Name, b.PathParams)
+						var err error
+						schema, err = renderFieldAsDefinition(bodyField.Target, reg, customRefs, pathParams)
+						if err != nil {
+							return err
+						}
+						if schema.Title != "" {
+							desc = mergeDescription(schema)
+						} else {
+							desc = fieldProtoComments(reg, bodyField.Target.Message, bodyField.Target)
+						}
+					}
+
+					if meth.GetClientStreaming() {
+						desc += " (streaming inputs)"
+					}
+					parameters = append(parameters, openapiParameterObject{
+						Name:        bodyFieldName,
+						Description: desc,
+						In:          "body",
+						Required:    true,
+						Schema:      &schema,
+					})
+				}
+
+				// add the parameters to the query string
+				queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body, b.HTTPMethod)
+				if err != nil {
+					return err
+				}
+				parameters = append(parameters, queryParams...)
+
+				path := partsToOpenAPIPath(parts, pathParamNames)
+
+				pathItemObject, ok := getPathItemObject(*paths, path)
+
+				if !ok {
+					pathItemObject = openapiPathItemObject{}
+				} else {
+					// handle case where we have an existing mapping for the same path and method
+					existingOperationObject := operationFunc(&pathItemObject)
+					if existingOperationObject != nil {
+						var firstPathParameter *openapiParameterObject
+						var firstParamIndex int
+						for index, param := range parameters {
+							param := param
+							if param.In == "path" {
+								firstPathParameter = ¶m
+								firstParamIndex = index
+								break
+							}
+						}
+						if firstPathParameter == nil {
+							// Without a path parameter, there is nothing to vary to support multiple mappings of the same path/method.
+							// Previously this did not log an error and only overwrote the mapping, we now log the error but
+							// still overwrite the mapping
+							grpclog.Errorf("Duplicate mapping for path %s %s", b.HTTPMethod, path)
+						} else {
+							newPathCount := 0
+							var newPath string
+							var newPathElement string
+							// Iterate until there is not an existing operation that matches the same escaped path.
+							// Most of the time this will only be a single iteration, but a large API could technically have
+							// a pretty large amount of these if it used similar patterns for all its functions.
+							for existingOperationObject != nil {
+								newPathCount += 1
+								newPathElement = firstPathParameter.Name + pathParamUniqueSuffixDeliminator + strconv.Itoa(newPathCount)
+								newPath = strings.ReplaceAll(path, "{"+firstPathParameter.Name+"}", "{"+newPathElement+"}")
+
+								if newPathItemObject, ok := getPathItemObject(*paths, newPath); ok {
+									existingOperationObject = operationFunc(&newPathItemObject)
+								} else {
+									existingOperationObject = nil
+								}
+							}
+							// update the pathItemObject we are adding to with the new path
+							pathItemObject, _ = getPathItemObject(*paths, newPath)
+							firstPathParameter.Name = newPathElement
+							path = newPath
+							parameters[firstParamIndex] = *firstPathParameter
+						}
+					}
+				}
+
+				methProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method")
+				desc := "A successful response."
+				var responseSchema openapiSchemaObject
+
+				if b.ResponseBody == nil || len(b.ResponseBody.FieldPath) == 0 {
+					responseSchema = openapiSchemaObject{
+						schemaCore: schemaCore{},
+					}
+
+					// Don't link to a full definition for
+					// empty; it's overly verbose.
+					// schema.Properties{} renders it as
+					// well, without a definition
+					wknSchemaCore, isWkn := wktSchemas[meth.ResponseType.FQMN()]
+					if !isWkn {
+						if err := responseSchema.setRefFromFQN(meth.ResponseType.FQMN(), reg); err != nil {
+							return err
+						}
+					} else {
+						responseSchema.schemaCore = wknSchemaCore
+
+						// Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher.
+						if meth.ResponseType.FQMN() == ".google.protobuf.Empty" {
+							responseSchema.Properties = &openapiSchemaObjectProperties{}
+						}
+					}
+				} else {
+					// This is resolving the value of response_body in the google.api.HttpRule
+					lastField := b.ResponseBody.FieldPath[len(b.ResponseBody.FieldPath)-1]
+					responseSchema = schemaOfField(lastField.Target, reg, customRefs)
+					if responseSchema.Description != "" {
+						desc = responseSchema.Description
+					} else {
+						desc = fieldProtoComments(reg, lastField.Target.Message, lastField.Target)
+					}
+				}
+				if meth.GetServerStreaming() {
+					desc += "(streaming responses)"
+					responseSchema.Type = "object"
+					swgRef, _ := fullyQualifiedNameToOpenAPIName(meth.ResponseType.FQMN(), reg)
+					responseSchema.Title = "Stream result of " + swgRef
+
+					props := openapiSchemaObjectProperties{
+						keyVal{
+							Key: "result",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Ref: responseSchema.Ref,
+								},
+							},
+						},
+					}
+					if !reg.GetDisableDefaultErrors() {
+						statusDef, hasStatus := fullyQualifiedNameToOpenAPIName(".google.rpc.Status", reg)
+						if hasStatus {
+							props = append(props, keyVal{
+								Key: "error",
+								Value: openapiSchemaObject{
+									schemaCore: schemaCore{
+										Ref: fmt.Sprintf("#/definitions/%s", statusDef),
+									},
+								},
+							})
+						}
+					}
+
+					// Special case HttpBody responses, they will be unformatted bytes
+					if meth.ResponseType.FQMN() == ".google.api.HttpBody" {
+						responseSchema.Type = "string"
+						responseSchema.Format = "binary"
+						responseSchema.Title = "Free form byte stream"
+						// The error response is still JSON, but technically the full response
+						// is still unformatted, so don't include the error response structure.
+						props = nil
+					}
+
+					responseSchema.Properties = &props
+					responseSchema.Ref = ""
+				}
+
+				operationObject := &openapiOperationObject{
+					Parameters: parameters,
+					Responses:  openapiResponsesObject{},
+					Deprecated: deprecated,
+				}
+
+				if !reg.GetDisableDefaultResponses() {
+					operationObject.Responses["200"] = openapiResponseObject{
+						Description: desc,
+						Schema:      responseSchema,
+						Headers:     openapiHeadersObject{},
+					}
+				}
+
+				if !reg.GetDisableServiceTags() {
+					tag := svc.GetName()
+					if pkg := svc.File.GetPackage(); pkg != "" && reg.IsIncludePackageInTags() {
+						tag = pkg + "." + tag
+					}
+					operationObject.Tags = []string{tag}
+				}
+
+				if !reg.GetDisableDefaultErrors() {
+					errDef, hasErrDef := fullyQualifiedNameToOpenAPIName(".google.rpc.Status", reg)
+					if hasErrDef {
+						// https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responses-object
+						operationObject.Responses["default"] = openapiResponseObject{
+							Description: "An unexpected error response.",
+							Schema: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Ref: fmt.Sprintf("#/definitions/%s", errDef),
+								},
+							},
+						}
+					}
+				}
+				operationObject.OperationID = fmt.Sprintf("%s_%s", svc.GetName(), meth.GetName())
+				if reg.GetSimpleOperationIDs() {
+					operationObject.OperationID = meth.GetName()
+				}
+				if bIdx != 0 {
+					// OperationID must be unique in an OpenAPI v2 definition.
+					operationObject.OperationID += strconv.Itoa(bIdx + 1)
+				}
+
+				// Fill reference map with referenced request messages
+				for _, param := range operationObject.Parameters {
+					if param.Schema != nil && param.Schema.Ref != "" {
+						requestResponseRefs[param.Schema.Ref] = struct{}{}
+					}
+				}
+
+				methComments := protoComments(reg, svc.File, nil, "Service", int32(svcIdx-svcBaseIdx), methProtoPath, int32(methIdx))
+				if err := updateOpenAPIDataFromComments(reg, operationObject, meth, methComments, false); err != nil {
+					panic(err)
+				}
+
+				svcOpts, err := getServiceOpenAPIOption(reg, svc)
+				if err != nil {
+					grpclog.Error(err)
+					return err
+				}
+
+				// Set Tag with the user-defined service name
+				if svcOpts.GetName() != "" {
+					operationObject.Tags = []string{svcOpts.GetName()}
+				}
+
+				opts, err := getMethodOpenAPIOption(reg, meth)
+				if opts != nil {
+					if err != nil {
+						panic(err)
+					}
+					operationObject.ExternalDocs = protoExternalDocumentationToOpenAPIExternalDocumentation(opts.ExternalDocs, reg, meth)
+
+					if opts.Deprecated {
+						operationObject.Deprecated = true
+					}
+
+					if opts.Summary != "" {
+						operationObject.Summary = opts.Summary
+					}
+					if opts.Description != "" {
+						operationObject.Description = opts.Description
+					}
+					if len(opts.Tags) > 0 {
+						operationObject.Tags = make([]string, len(opts.Tags))
+						copy(operationObject.Tags, opts.Tags)
+					}
+					if opts.OperationId != "" {
+						operationObject.OperationID = opts.OperationId
+					}
+					if opts.Security != nil {
+						newSecurity := []openapiSecurityRequirementObject{}
+						if operationObject.Security != nil {
+							newSecurity = *operationObject.Security
+						}
+						for _, secReq := range opts.Security {
+							newSecReq := openapiSecurityRequirementObject{}
+							for secReqKey, secReqValue := range secReq.SecurityRequirement {
+								if secReqValue == nil {
+									continue
+								}
+
+								newSecReqValue := make([]string, len(secReqValue.Scope))
+								copy(newSecReqValue, secReqValue.Scope)
+								newSecReq[secReqKey] = newSecReqValue
+							}
+
+							if len(newSecReq) > 0 {
+								newSecurity = append(newSecurity, newSecReq)
+							}
+						}
+						operationObject.Security = &newSecurity
+					}
+					if opts.Responses != nil {
+						for name, resp := range opts.Responses {
+							// Merge response data into default response if available.
+							respObj := operationObject.Responses[name]
+							if resp.Description != "" {
+								respObj.Description = resp.Description
+							}
+							if resp.Schema != nil {
+								respObj.Schema = openapiSchemaFromProtoSchema(resp.Schema, reg, customRefs, meth)
+							}
+							if resp.Examples != nil {
+								respObj.Examples = openapiExamplesFromProtoExamples(resp.Examples)
+							}
+							if resp.Headers != nil {
+								hdrs, err := processHeaders(resp.Headers)
+								if err != nil {
+									return err
+								}
+								respObj.Headers = hdrs
+							}
+							if resp.Extensions != nil {
+								exts, err := processExtensions(resp.Extensions)
+								if err != nil {
+									return err
+								}
+								respObj.extensions = exts
+							}
+							operationObject.Responses[name] = respObj
+						}
+					}
+
+					if opts.Extensions != nil {
+						exts, err := processExtensions(opts.Extensions)
+						if err != nil {
+							return err
+						}
+						operationObject.extensions = exts
+					}
+
+					if len(opts.Consumes) > 0 {
+						operationObject.Consumes = make([]string, len(opts.Consumes))
+						copy(operationObject.Consumes, opts.Consumes)
+					}
+
+					if len(opts.Produces) > 0 {
+						operationObject.Produces = make([]string, len(opts.Produces))
+						copy(operationObject.Produces, opts.Produces)
+					}
+
+					if params := opts.Parameters; params != nil && len(params.Headers) > 0 {
+						for _, header := range params.Headers {
+							param := openapiParameterObject{
+								In:          "header",
+								Name:        header.Name,
+								Description: header.Description,
+								Required:    header.Required,
+								Format:      header.Format,
+							}
+
+							switch header.Type {
+							case openapi_options.HeaderParameter_STRING:
+								param.Type = "string"
+							case openapi_options.HeaderParameter_NUMBER:
+								param.Type = "number"
+							case openapi_options.HeaderParameter_INTEGER:
+								param.Type = "integer"
+							case openapi_options.HeaderParameter_BOOLEAN:
+								param.Type = "boolean"
+							default:
+								return fmt.Errorf("invalid header parameter type: %+v", header.Type)
+							}
+
+							operationObject.Parameters = append(operationObject.Parameters, param)
+						}
+					}
+
+					// TODO(ivucica): add remaining fields of operation object
+				}
+
+				switch b.HTTPMethod {
+				case "DELETE":
+					pathItemObject.Delete = operationObject
+				case "GET":
+					pathItemObject.Get = operationObject
+				case "POST":
+					pathItemObject.Post = operationObject
+				case "PUT":
+					pathItemObject.Put = operationObject
+				case "PATCH":
+					pathItemObject.Patch = operationObject
+				case "HEAD":
+					pathItemObject.Head = operationObject
+				case "OPTIONS":
+					pathItemObject.Options = operationObject
+				}
+
+				updatePaths(paths, path, pathItemObject)
+			}
+		}
+	}
+
+	// Success! return nil on the error object
+	return nil
+}
+
+// Returns the openapiPathItemObject associated with a path. If path is not present, returns
+// empty openapiPathItemObject and false.
+func getPathItemObject(paths openapiPathsObject, path string) (openapiPathItemObject, bool) {
+	for _, pathData := range paths {
+		if pathData.Path == path {
+			return pathData.PathItemObject, true
+		}
+	}
+
+	return openapiPathItemObject{}, false
+}
+
+// If a path already exists in openapiPathsObject, updates that path's openapiPathItemObject. If not,
+// appends a new path and openapiPathItemObject to the openapiPathsObject.
+func updatePaths(paths *openapiPathsObject, path string, pathItemObject openapiPathItemObject) {
+	for i, p := range *paths {
+		if p.Path == path {
+			(*paths)[i].PathItemObject = pathItemObject
+			return
+		}
+	}
+	*paths = append(*paths, pathData{
+		Path:           path,
+		PathItemObject: pathItemObject,
+	})
+}
+
+func mergeDescription(schema openapiSchemaObject) string {
+	desc := schema.Description
+	if schema.Title != "" { // join title because title of parameter object will be ignored
+		desc = strings.TrimSpace(schema.Title + paragraphDeliminator + schema.Description)
+	}
+	return desc
+}
+
+func operationForMethod(httpMethod string) func(*openapiPathItemObject) *openapiOperationObject {
+	switch httpMethod {
+	case "GET":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Get }
+	case "POST":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Post }
+	case "PUT":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Put }
+	case "DELETE":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Delete }
+	case "PATCH":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Patch }
+	case "HEAD":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Head }
+	case "OPTIONS":
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Options }
+	default:
+		return func(obj *openapiPathItemObject) *openapiOperationObject { return nil }
+	}
+}
+
+// This function is called with a param which contains the entire definition of a method.
+func applyTemplate(p param) (*openapiSwaggerObject, error) {
+	// Create the basic template object. This is the object that everything is
+	// defined off of.
+	s := openapiSwaggerObject{
+		// OpenAPI 2.0 is the version of this document
+		Swagger:     "2.0",
+		Consumes:    []string{"application/json"},
+		Produces:    []string{"application/json"},
+		Paths:       openapiPathsObject{},
+		Definitions: make(openapiDefinitionsObject),
+		Info: openapiInfoObject{
+			Title:   *p.File.Name,
+			Version: "version not set",
+		},
+	}
+
+	// Loops through all the services and their exposed GET/POST/PUT/DELETE definitions
+	// and create entries for all of them.
+	// Also adds custom user specified references to second map.
+	requestResponseRefs, customRefs := refMap{}, refMap{}
+	if err := renderServices(p.Services, &s.Paths, p.reg, requestResponseRefs, customRefs, p.Messages, s.Definitions); err != nil {
+		panic(err)
+	}
+
+	messages := messageMap{}
+	streamingMessages := messageMap{}
+	enums := enumMap{}
+
+	if !p.reg.GetDisableDefaultErrors() {
+		// Add the error type to the message map
+		runtimeError, swgRef, err := lookupMsgAndOpenAPIName("google.rpc", "Status", p.reg)
+		if err == nil {
+			messages[swgRef] = runtimeError
+		} else {
+			// just in case there is an error looking up runtimeError
+			grpclog.Error(err)
+		}
+	}
+
+	// Find all the service's messages and enumerations that are defined (recursively)
+	// and write request, response and other custom (but referenced) types out as definition objects.
+	findServicesMessagesAndEnumerations(p.Services, p.reg, messages, streamingMessages, enums, requestResponseRefs)
+	if err := renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs, nil); err != nil {
+		return nil, err
+	}
+	renderEnumerationsAsDefinition(enums, s.Definitions, p.reg, requestResponseRefs)
+
+	// File itself might have some comments and metadata.
+	packageProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package")
+	packageComments := protoComments(p.reg, p.File, nil, "Package", packageProtoPath)
+	if err := updateOpenAPIDataFromComments(p.reg, &s, p, packageComments, true); err != nil {
+		return nil, err
+	}
+
+	// There may be additional options in the OpenAPI option in the proto.
+	spb, err := getFileOpenAPIOption(p.reg, p.File)
+	if err != nil {
+		return nil, err
+	}
+	if spb != nil {
+		if spb.Swagger != "" {
+			s.Swagger = spb.Swagger
+		}
+		if spb.Info != nil {
+			if spb.Info.Title != "" {
+				s.Info.Title = spb.Info.Title
+			}
+			if spb.Info.Description != "" {
+				s.Info.Description = spb.Info.Description
+			}
+			if spb.Info.TermsOfService != "" {
+				s.Info.TermsOfService = spb.Info.TermsOfService
+			}
+			if spb.Info.Version != "" {
+				s.Info.Version = spb.Info.Version
+			}
+			if spb.Info.Contact != nil {
+				if s.Info.Contact == nil {
+					s.Info.Contact = &openapiContactObject{}
+				}
+				if spb.Info.Contact.Name != "" {
+					s.Info.Contact.Name = spb.Info.Contact.Name
+				}
+				if spb.Info.Contact.Url != "" {
+					s.Info.Contact.URL = spb.Info.Contact.Url
+				}
+				if spb.Info.Contact.Email != "" {
+					s.Info.Contact.Email = spb.Info.Contact.Email
+				}
+			}
+			if spb.Info.License != nil {
+				if s.Info.License == nil {
+					s.Info.License = &openapiLicenseObject{}
+				}
+				if spb.Info.License.Name != "" {
+					s.Info.License.Name = spb.Info.License.Name
+				}
+				if spb.Info.License.Url != "" {
+					s.Info.License.URL = spb.Info.License.Url
+				}
+			}
+			if spb.Info.Extensions != nil {
+				exts, err := processExtensions(spb.Info.Extensions)
+				if err != nil {
+					return nil, err
+				}
+				s.Info.extensions = exts
+			}
+		}
+		if spb.Host != "" {
+			s.Host = spb.Host
+		}
+		if spb.BasePath != "" {
+			s.BasePath = spb.BasePath
+		}
+		if len(spb.Schemes) > 0 {
+			s.Schemes = make([]string, len(spb.Schemes))
+			for i, scheme := range spb.Schemes {
+				s.Schemes[i] = strings.ToLower(scheme.String())
+			}
+		}
+		if len(spb.Consumes) > 0 {
+			s.Consumes = make([]string, len(spb.Consumes))
+			copy(s.Consumes, spb.Consumes)
+		}
+		if len(spb.Produces) > 0 {
+			s.Produces = make([]string, len(spb.Produces))
+			copy(s.Produces, spb.Produces)
+		}
+		if spb.SecurityDefinitions != nil && spb.SecurityDefinitions.Security != nil {
+			if s.SecurityDefinitions == nil {
+				s.SecurityDefinitions = openapiSecurityDefinitionsObject{}
+			}
+			for secDefKey, secDefValue := range spb.SecurityDefinitions.Security {
+				var newSecDefValue openapiSecuritySchemeObject
+				if oldSecDefValue, ok := s.SecurityDefinitions[secDefKey]; !ok {
+					newSecDefValue = openapiSecuritySchemeObject{}
+				} else {
+					newSecDefValue = oldSecDefValue
+				}
+				if secDefValue.Type != openapi_options.SecurityScheme_TYPE_INVALID {
+					switch secDefValue.Type {
+					case openapi_options.SecurityScheme_TYPE_BASIC:
+						newSecDefValue.Type = "basic"
+					case openapi_options.SecurityScheme_TYPE_API_KEY:
+						newSecDefValue.Type = "apiKey"
+					case openapi_options.SecurityScheme_TYPE_OAUTH2:
+						newSecDefValue.Type = "oauth2"
+					}
+				}
+				if secDefValue.Description != "" {
+					newSecDefValue.Description = secDefValue.Description
+				}
+				if secDefValue.Name != "" {
+					newSecDefValue.Name = secDefValue.Name
+				}
+				if secDefValue.In != openapi_options.SecurityScheme_IN_INVALID {
+					switch secDefValue.In {
+					case openapi_options.SecurityScheme_IN_QUERY:
+						newSecDefValue.In = "query"
+					case openapi_options.SecurityScheme_IN_HEADER:
+						newSecDefValue.In = "header"
+					}
+				}
+				if secDefValue.Flow != openapi_options.SecurityScheme_FLOW_INVALID {
+					switch secDefValue.Flow {
+					case openapi_options.SecurityScheme_FLOW_IMPLICIT:
+						newSecDefValue.Flow = "implicit"
+					case openapi_options.SecurityScheme_FLOW_PASSWORD:
+						newSecDefValue.Flow = "password"
+					case openapi_options.SecurityScheme_FLOW_APPLICATION:
+						newSecDefValue.Flow = "application"
+					case openapi_options.SecurityScheme_FLOW_ACCESS_CODE:
+						newSecDefValue.Flow = "accessCode"
+					}
+				}
+				if secDefValue.AuthorizationUrl != "" {
+					newSecDefValue.AuthorizationURL = secDefValue.AuthorizationUrl
+				}
+				if secDefValue.TokenUrl != "" {
+					newSecDefValue.TokenURL = secDefValue.TokenUrl
+				}
+				if secDefValue.Scopes != nil {
+					if newSecDefValue.Scopes == nil {
+						newSecDefValue.Scopes = openapiScopesObject{}
+					}
+					for scopeKey, scopeDesc := range secDefValue.Scopes.Scope {
+						newSecDefValue.Scopes[scopeKey] = scopeDesc
+					}
+				}
+				if secDefValue.Extensions != nil {
+					exts, err := processExtensions(secDefValue.Extensions)
+					if err != nil {
+						return nil, err
+					}
+					newSecDefValue.extensions = exts
+				}
+				s.SecurityDefinitions[secDefKey] = newSecDefValue
+			}
+		}
+		if spb.Security != nil {
+			var newSecurity []openapiSecurityRequirementObject
+			if s.Security != nil {
+				newSecurity = s.Security
+			}
+			for _, secReq := range spb.Security {
+				newSecReq := openapiSecurityRequirementObject{}
+				for secReqKey, secReqValue := range secReq.SecurityRequirement {
+					if secReqValue == nil {
+						return nil, fmt.Errorf("malformed security requirement spec for key %q; value is required", secReqKey)
+					}
+					newSecReqValue := make([]string, len(secReqValue.Scope))
+					copy(newSecReqValue, secReqValue.Scope)
+					newSecReq[secReqKey] = newSecReqValue
+				}
+				newSecurity = append(newSecurity, newSecReq)
+			}
+			s.Security = newSecurity
+		}
+		s.ExternalDocs = protoExternalDocumentationToOpenAPIExternalDocumentation(spb.ExternalDocs, p.reg, spb)
+		// Populate all Paths with Responses set at top level,
+		// preferring Responses already set over those at the top level.
+		if spb.Responses != nil {
+			for _, verbs := range s.Paths {
+				var maps []openapiResponsesObject
+				if verbs.PathItemObject.Delete != nil {
+					maps = append(maps, verbs.PathItemObject.Delete.Responses)
+				}
+				if verbs.PathItemObject.Get != nil {
+					maps = append(maps, verbs.PathItemObject.Get.Responses)
+				}
+				if verbs.PathItemObject.Post != nil {
+					maps = append(maps, verbs.PathItemObject.Post.Responses)
+				}
+				if verbs.PathItemObject.Put != nil {
+					maps = append(maps, verbs.PathItemObject.Put.Responses)
+				}
+				if verbs.PathItemObject.Patch != nil {
+					maps = append(maps, verbs.PathItemObject.Patch.Responses)
+				}
+
+				for k, v := range spb.Responses {
+					for _, respMap := range maps {
+						if _, ok := respMap[k]; ok {
+							// Don't overwrite already existing Responses
+							continue
+						}
+						respMap[k] = openapiResponseObject{
+							Description: v.Description,
+							Schema:      openapiSchemaFromProtoSchema(v.Schema, p.reg, customRefs, nil),
+							Examples:    openapiExamplesFromProtoExamples(v.Examples),
+						}
+					}
+				}
+			}
+		}
+
+		if spb.Extensions != nil {
+			exts, err := processExtensions(spb.Extensions)
+			if err != nil {
+				return nil, err
+			}
+			s.extensions = exts
+		}
+
+		if spb.Tags != nil {
+			for _, v := range spb.Tags {
+				newTag := openapiTagObject{}
+				newTag.Name = v.Name
+				newTag.Description = v.Description
+				if p.reg.GetUseGoTemplate() {
+					newTag.Description = goTemplateComments(newTag.Description, nil, p.reg)
+				}
+				if v.ExternalDocs != nil {
+					newTag.ExternalDocs = &openapiExternalDocumentationObject{
+						Description: v.ExternalDocs.Description,
+						URL:         v.ExternalDocs.Url,
+					}
+					if p.reg.GetUseGoTemplate() {
+						newTag.ExternalDocs.Description = goTemplateComments(v.ExternalDocs.Description, nil, p.reg)
+					}
+				}
+				if v.Extensions != nil {
+					exts, err := processExtensions(v.Extensions)
+					if err != nil {
+						return nil, err
+					}
+					newTag.extensions = exts
+				}
+				s.Tags = append(s.Tags, newTag)
+			}
+		}
+
+		// Additional fields on the OpenAPI v2 spec's "OpenAPI" object
+		// should be added here, once supported in the proto.
+	}
+
+	if !p.reg.GetDisableServiceTags() {
+		s.Tags = mergeTags(s.Tags, renderServiceTags(p.Services, p.reg))
+	}
+
+	// Finally add any references added by users that aren't
+	// otherwise rendered.
+	if err := addCustomRefs(s.Definitions, p.reg, customRefs); err != nil {
+		return nil, err
+	}
+
+	return &s, nil
+}
+
+func mergeTags(existingTags []openapiTagObject, tags []openapiTagObject) []openapiTagObject {
+	for _, tag := range tags {
+		matched := false
+		for i, existingTag := range existingTags {
+			if existingTag.Name == tag.Name {
+				if existingTag.Description == "" {
+					existingTags[i].Description = tag.Description
+				}
+				if existingTag.ExternalDocs == nil {
+					existingTags[i].ExternalDocs = tag.ExternalDocs
+				} else if tag.ExternalDocs != nil {
+					if existingTag.ExternalDocs.Description == "" {
+						existingTags[i].ExternalDocs.Description = tag.ExternalDocs.Description
+					}
+					if existingTag.ExternalDocs.URL == "" {
+						existingTags[i].ExternalDocs.URL = tag.ExternalDocs.URL
+					}
+				}
+				if existingTag.extensions == nil {
+					existingTags[i].extensions = tag.extensions
+				} else if tag.extensions != nil {
+					for _, ext := range tag.extensions {
+						matchedExt := false
+						for _, existingExt := range existingTag.extensions {
+							if existingExt.key == ext.key {
+								matchedExt = true
+								break
+							}
+						}
+						if !matchedExt {
+							existingTags[i].extensions = append(existingTags[i].extensions, ext)
+						}
+					}
+				}
+				matched = true
+				break
+			}
+		}
+		if !matched {
+			existingTags = append(existingTags, tag)
+		}
+	}
+	return existingTags
+}
+
+func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error) {
+	exts := make([]extension, 0, len(inputExts))
+	for k, v := range inputExts {
+		if !strings.HasPrefix(k, "x-") {
+			return nil, fmt.Errorf("extension keys need to start with \"x-\": %q", k)
+		}
+		ext, err := (&protojson.MarshalOptions{Indent: "  "}).Marshal(v)
+		if err != nil {
+			return nil, err
+		}
+		exts = append(exts, extension{key: k, value: ext})
+	}
+	sort.Slice(exts, func(i, j int) bool { return exts[i].key < exts[j].key })
+	return exts, nil
+}
+
+func validateHeaderTypeAndFormat(headerType, format string) error {
+	// The type of the object. The value MUST be one of "string", "number", "integer", "boolean", or "array"
+	// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+	// Note: currently not implementing array as we are only implementing this in the operation response context
+	switch headerType {
+	// the format property is an open string-valued property, and can have any value to support documentation needs
+	// primary check for format is to ensure that the number/integer formats are extensions of the specified type
+	// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#dataTypeFormat
+	case "string":
+		return nil
+	case "number":
+		switch format {
+		case "uint",
+			"uint8",
+			"uint16",
+			"uint32",
+			"uint64",
+			"int",
+			"int8",
+			"int16",
+			"int32",
+			"int64",
+			"float",
+			"float32",
+			"float64",
+			"complex64",
+			"complex128",
+			"double",
+			"byte",
+			"rune",
+			"uintptr",
+			"":
+			return nil
+		default:
+			return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType)
+		}
+	case "integer":
+		switch format {
+		case "uint",
+			"uint8",
+			"uint16",
+			"uint32",
+			"uint64",
+			"int",
+			"int8",
+			"int16",
+			"int32",
+			"int64",
+			"":
+			return nil
+		default:
+			return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType)
+		}
+	case "boolean":
+		return nil
+	}
+	return fmt.Errorf("the provided header type %q is not supported", headerType)
+}
+
+func validateDefaultValueTypeAndFormat(headerType string, defaultValue string, format string) error {
+	switch headerType {
+	case "string":
+		if !isQuotedString(defaultValue) {
+			return fmt.Errorf("the provided default value %q does not match provider type %q, or is not properly quoted with escaped quotations", defaultValue, headerType)
+		}
+		switch format {
+		case "date-time":
+			unquoteTime := strings.Trim(defaultValue, `"`)
+			if _, err := time.Parse(time.RFC3339, unquoteTime); err != nil {
+				return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue)
+			}
+		case "date":
+			const layoutRFC3339Date = "2006-01-02"
+			unquoteDate := strings.Trim(defaultValue, `"`)
+			if _, err := time.Parse(layoutRFC3339Date, unquoteDate); err != nil {
+				return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue)
+			}
+		}
+	case "number":
+		if err := isJSONNumber(defaultValue, headerType); err != nil {
+			return err
+		}
+	case "integer":
+		switch format {
+		case "int32":
+			if _, err := strconv.ParseInt(defaultValue, 0, 32); err != nil {
+				return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format)
+			}
+		case "uint32":
+			if _, err := strconv.ParseUint(defaultValue, 0, 32); err != nil {
+				return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format)
+			}
+		case "int64":
+			if _, err := strconv.ParseInt(defaultValue, 0, 64); err != nil {
+				return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format)
+			}
+		case "uint64":
+			if _, err := strconv.ParseUint(defaultValue, 0, 64); err != nil {
+				return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format)
+			}
+		default:
+			if _, err := strconv.ParseInt(defaultValue, 0, 64); err != nil {
+				return fmt.Errorf("the provided default value %q does not match provided type %q", defaultValue, headerType)
+			}
+		}
+	case "boolean":
+		if !isBool(defaultValue) {
+			return fmt.Errorf("the provided default value %q does not match provider type %q", defaultValue, headerType)
+		}
+	}
+	return nil
+}
+
+func isQuotedString(s string) bool {
+	return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
+}
+
+func isJSONNumber(s string, t string) error {
+	val, err := strconv.ParseFloat(s, 64)
+	if err != nil {
+		return fmt.Errorf("the provided default value %q does not match provider type %q", s, t)
+	}
+	// Floating point values that cannot be represented as sequences of digits (such as Infinity and NaN) are not permitted.
+	// See: https://tools.ietf.org/html/rfc4627#section-2.4
+	if math.IsInf(val, 0) || math.IsNaN(val) {
+		return fmt.Errorf("the provided number %q is not a valid JSON number", s)
+	}
+
+	return nil
+}
+
+func isBool(s string) bool {
+	// Unable to use strconv.ParseBool because it returns truthy values https://golang.org/pkg/strconv/#example_ParseBool
+	// per https://swagger.io/specification/v2/#data-types
+	// type: boolean represents two values: true and false. Note that truthy and falsy values such as "true", "", 0 or null are not considered boolean values.
+	return s == "true" || s == "false"
+}
+
+func processHeaders(inputHdrs map[string]*openapi_options.Header) (openapiHeadersObject, error) {
+	hdrs := make(map[string]openapiHeaderObject, len(inputHdrs))
+	for k, v := range inputHdrs {
+		header := textproto.CanonicalMIMEHeaderKey(k)
+		ret := openapiHeaderObject{
+			Description: v.Description,
+			Format:      v.Format,
+			Pattern:     v.Pattern,
+		}
+		if err := validateHeaderTypeAndFormat(v.Type, v.Format); err != nil {
+			return nil, err
+		}
+		ret.Type = v.Type
+		if v.Default != "" {
+			if err := validateDefaultValueTypeAndFormat(v.Type, v.Default, v.Format); err != nil {
+				return nil, err
+			}
+			ret.Default = RawExample(v.Default)
+		}
+		hdrs[header] = ret
+	}
+	return hdrs, nil
+}
+
+func removeInternalComments(comment string) string {
+	c := []string{}
+	for len(comment) > 0 {
+		open := strings.SplitN(comment, "(--", 2)
+		if len(open) == 1 {
+			c = append(c, open[0])
+			break
+		}
+		ex := strings.TrimRight(open[0], " \t")
+		// Trim only one line prior to all spaces
+		switch {
+		case strings.HasSuffix(ex, "\r\n"):
+			ex = strings.TrimSuffix(ex, "\r\n")
+		case strings.HasSuffix(ex, "\n"):
+			ex = strings.TrimSuffix(ex, "\n")
+		}
+		if ex != "" {
+			c = append(c, ex)
+		}
+		comment = open[1]
+
+		close := strings.SplitN(comment, "--)", 2)
+		if len(close) > 1 {
+			comment = close[1]
+		} else {
+			break
+		}
+	}
+	return strings.Join(c, "")
+}
+
+// updateOpenAPIDataFromComments updates a OpenAPI object based on a comment
+// from the proto file.
+//
+// First paragraph of a comment is used for summary. Remaining paragraphs of
+// a comment are used for description. If 'Summary' field is not present on
+// the passed swaggerObject, the summary and description are joined by \n\n.
+//
+// If there is a field named 'Info', its 'Summary' and 'Description' fields
+// will be updated instead.
+//
+// If there is no 'Summary', the same behavior will be attempted on 'Title',
+// but only if the last character is not a period.
+func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject interface{}, data interface{}, comment string, isPackageObject bool) error {
+	if len(comment) == 0 {
+		return nil
+	}
+
+	// Checks whether the "ignore_comments" flag is set to true
+	if reg.GetIgnoreComments() {
+		return nil
+	}
+
+	// Checks whether the "remove_internal_comments" flag is set to true
+	if reg.GetRemoveInternalComments() {
+		comment = removeInternalComments(comment)
+	}
+
+	// Checks whether the "use_go_templates" flag is set to true
+	if reg.GetUseGoTemplate() {
+		comment = goTemplateComments(comment, data, reg)
+	}
+
+	// Figure out what to apply changes to.
+	swaggerObjectValue := reflect.ValueOf(swaggerObject)
+	infoObjectValue := swaggerObjectValue.Elem().FieldByName("Info")
+	if !infoObjectValue.CanSet() {
+		// No such field? Apply summary and description directly to
+		// passed object.
+		infoObjectValue = swaggerObjectValue.Elem()
+	}
+
+	// Figure out which properties to update.
+	summaryValue := infoObjectValue.FieldByName("Summary")
+	descriptionValue := infoObjectValue.FieldByName("Description")
+	readOnlyValue := infoObjectValue.FieldByName("ReadOnly")
+
+	if readOnlyValue.Kind() == reflect.Bool && readOnlyValue.CanSet() && strings.Contains(comment, "Output only.") {
+		readOnlyValue.Set(reflect.ValueOf(true))
+	}
+
+	usingTitle := false
+	if !summaryValue.CanSet() {
+		summaryValue = infoObjectValue.FieldByName("Title")
+		usingTitle = true
+	}
+
+	paragraphs := strings.Split(comment, paragraphDeliminator)
+
+	// If there is a summary (or summary-equivalent) and it's empty, use the first
+	// paragraph as summary, and the rest as description.
+	if summaryValue.CanSet() {
+		summary := strings.TrimSpace(paragraphs[0])
+		description := strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator))
+		if !usingTitle || (len(summary) > 0 && summary[len(summary)-1] != '.') {
+			// overrides the schema value only if it's empty
+			// keep the comment precedence when updating the package definition
+			if summaryValue.Len() == 0 || isPackageObject {
+				summaryValue.Set(reflect.ValueOf(summary))
+			}
+			if len(description) > 0 {
+				if !descriptionValue.CanSet() {
+					return errors.New("encountered object type with a summary, but no description")
+				}
+				// overrides the schema value only if it's empty
+				// keep the comment precedence when updating the package definition
+				if descriptionValue.Len() == 0 || isPackageObject {
+					descriptionValue.Set(reflect.ValueOf(description))
+				}
+			}
+			return nil
+		}
+	}
+
+	// There was no summary field on the swaggerObject. Try to apply the
+	// whole comment into description if the OpenAPI object description is empty.
+	if descriptionValue.CanSet() {
+		if descriptionValue.Len() == 0 || isPackageObject {
+			descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, paragraphDeliminator)))
+		}
+		return nil
+	}
+
+	return errors.New("no description nor summary property")
+}
+
+func fieldProtoComments(reg *descriptor.Registry, msg *descriptor.Message, field *descriptor.Field) string {
+	protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.DescriptorProto)(nil)), "Field")
+	for i, f := range msg.Fields {
+		if f == field {
+			return protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index), protoPath, int32(i))
+		}
+	}
+	return ""
+}
+
+func enumValueProtoComments(reg *descriptor.Registry, enum *descriptor.Enum) string {
+	protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.EnumDescriptorProto)(nil)), "Value")
+	var comments []string
+	for idx, value := range enum.GetValue() {
+		if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 {
+			continue
+		}
+		if !isVisible(getEnumValueVisibilityOption(value), reg) {
+			continue
+		}
+		name := value.GetName()
+		if reg.GetEnumsAsInts() {
+			name = strconv.Itoa(int(value.GetNumber()))
+		}
+		if str := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index), protoPath, int32(idx)); str != "" {
+			comments = append(comments, name+": "+str)
+		}
+	}
+	if len(comments) > 0 {
+		return "- " + strings.Join(comments, "\n - ")
+	}
+	return ""
+}
+
+func protoComments(reg *descriptor.Registry, file *descriptor.File, outers []string, typeName string, typeIndex int32, fieldPaths ...int32) string {
+	if file.SourceCodeInfo == nil {
+		fmt.Fprintln(os.Stderr, file.GetName(), "descriptor.File should not contain nil SourceCodeInfo")
+		return ""
+	}
+
+	outerPaths := make([]int32, len(outers))
+	for i := range outers {
+		location := ""
+		if file.Package != nil {
+			location = file.GetPackage()
+		}
+
+		msg, err := reg.LookupMsg(location, strings.Join(outers[:i+1], "."))
+		if err != nil {
+			panic(err)
+		}
+		outerPaths[i] = int32(msg.Index)
+	}
+
+	for _, loc := range file.SourceCodeInfo.Location {
+		if !isProtoPathMatches(loc.Path, outerPaths, typeName, typeIndex, fieldPaths) {
+			continue
+		}
+		comments := ""
+		if loc.LeadingComments != nil {
+			comments = strings.TrimRight(*loc.LeadingComments, "\n")
+			comments = strings.TrimSpace(comments)
+			// TODO(ivucica): this is a hack to fix "// " being interpreted as "//".
+			// perhaps we should:
+			// - split by \n
+			// - determine if every (but first and last) line begins with " "
+			// - trim every line only if that is the case
+			// - join by \n
+			comments = strings.ReplaceAll(comments, "\n ", "\n")
+			comments = removeInternalComments(comments)
+		}
+		if loc.TrailingComments != nil {
+			trailing := strings.TrimSpace(*loc.TrailingComments)
+			if comments == "" {
+				comments = trailing
+			} else {
+				comments += "\n\n" + trailing
+			}
+		}
+		return comments
+	}
+	return ""
+}
+
+func goTemplateComments(comment string, data interface{}, reg *descriptor.Registry) string {
+	var temp bytes.Buffer
+	tpl, err := template.New("").Funcs(template.FuncMap{
+		// Allows importing documentation from a file
+		"import": func(name string) string {
+			file, err := os.ReadFile(name)
+			if err != nil {
+				return err.Error()
+			}
+			// Runs template over imported file
+			return goTemplateComments(string(file), data, reg)
+		},
+		// Grabs title and description from a field
+		"fieldcomments": func(msg *descriptor.Message, field *descriptor.Field) string {
+			return strings.ReplaceAll(fieldProtoComments(reg, msg, field), "\n", "
")
+		},
+		"arg": func(name string) string {
+			if v, f := reg.GetGoTemplateArgs()[name]; f {
+				return v
+			}
+			return fmt.Sprintf("goTemplateArg %s not found", name)
+		},
+	}).Parse(comment)
+	if err != nil {
+		// If there is an error parsing the templating insert the error as string in the comment
+		// to make it easier to debug the template error
+		return err.Error()
+	}
+	if err := tpl.Execute(&temp, data); err != nil {
+		// If there is an error executing the templating insert the error as string in the comment
+		// to make it easier to debug the error
+		return err.Error()
+	}
+	return temp.String()
+}
+
+var (
+	messageProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "MessageType")
+	nestedProtoPath  = protoPathIndex(reflect.TypeOf((*descriptorpb.DescriptorProto)(nil)), "NestedType")
+	packageProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package")
+	serviceProtoPath = protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Service")
+	methodProtoPath  = protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method")
+)
+
+func isProtoPathMatches(paths []int32, outerPaths []int32, typeName string, typeIndex int32, fieldPaths []int32) bool {
+	if typeName == "Package" && typeIndex == packageProtoPath {
+		// path for package comments is just [2], and all the other processing
+		// is too complex for it.
+		if len(paths) == 0 || typeIndex != paths[0] {
+			return false
+		}
+		return true
+	}
+
+	if len(paths) != len(outerPaths)*2+2+len(fieldPaths) {
+		return false
+	}
+
+	if typeName == "Method" {
+		if paths[0] != serviceProtoPath || paths[2] != methodProtoPath {
+			return false
+		}
+		paths = paths[2:]
+	} else {
+		typeNameDescriptor := reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil))
+
+		if len(outerPaths) > 0 {
+			if paths[0] != messageProtoPath || paths[1] != outerPaths[0] {
+				return false
+			}
+			paths = paths[2:]
+			outerPaths = outerPaths[1:]
+
+			for i, v := range outerPaths {
+				if paths[i*2] != nestedProtoPath || paths[i*2+1] != v {
+					return false
+				}
+			}
+			paths = paths[len(outerPaths)*2:]
+
+			if typeName == "MessageType" {
+				typeName = "NestedType"
+			}
+			typeNameDescriptor = reflect.TypeOf((*descriptorpb.DescriptorProto)(nil))
+		}
+
+		if paths[0] != protoPathIndex(typeNameDescriptor, typeName) || paths[1] != typeIndex {
+			return false
+		}
+		paths = paths[2:]
+	}
+
+	for i, v := range fieldPaths {
+		if paths[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
+// protoPathIndex returns a path component for google.protobuf.descriptor.SourceCode_Location.
+//
+// Specifically, it returns an id as generated from descriptor proto which
+// can be used to determine what type the id following it in the path is.
+// For example, if we are trying to locate comments related to a field named
+// `Address` in a message named `Person`, the path will be:
+//
+//	[4, a, 2, b]
+//
+// While `a` gets determined by the order in which the messages appear in
+// the proto file, and `b` is the field index specified in the proto
+// file itself, the path actually needs to specify that `a` refers to a
+// message and not, say, a service; and  that `b` refers to a field and not
+// an option.
+//
+// protoPathIndex figures out the values 4 and 2 in the above example. Because
+// messages are top level objects, the value of 4 comes from field id for
+// `MessageType` inside `google.protobuf.descriptor.FileDescriptor` message.
+// This field has a message type `google.protobuf.descriptor.DescriptorProto`.
+// And inside message `DescriptorProto`, there is a field named `Field` with id
+// 2.
+//
+// Some code generators seem to be hardcoding these values; this method instead
+// interprets them from `descriptor.proto`-derived Go source as necessary.
+func protoPathIndex(descriptorType reflect.Type, what string) int32 {
+	field, ok := descriptorType.Elem().FieldByName(what)
+	if !ok {
+		panic(fmt.Errorf("could not find protobuf descriptor type id for %s", what))
+	}
+	pbtag := field.Tag.Get("protobuf")
+	if pbtag == "" {
+		panic(fmt.Errorf("no Go tag 'protobuf' on protobuf descriptor for %s", what))
+	}
+	path, err := strconv.ParseInt(strings.Split(pbtag, ",")[1], 10, 32)
+	if err != nil {
+		panic(fmt.Errorf("protobuf descriptor id for %s cannot be converted to a number: %s", what, err.Error()))
+	}
+	return int32(path)
+}
+
+// extractOperationOptionFromMethodDescriptor extracts the message of type
+// openapi_options.Operation from a given proto method's descriptor.
+func extractOperationOptionFromMethodDescriptor(meth *descriptorpb.MethodDescriptorProto) (*openapi_options.Operation, error) {
+	if meth.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(meth.Options, openapi_options.E_Openapiv2Operation) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(meth.Options, openapi_options.E_Openapiv2Operation)
+	opts, ok := ext.(*openapi_options.Operation)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want an Operation", ext)
+	}
+	return opts, nil
+}
+
+// extractSchemaOptionFromMessageDescriptor extracts the message of type
+// openapi_options.Schema from a given proto message's descriptor.
+func extractSchemaOptionFromMessageDescriptor(msg *descriptorpb.DescriptorProto) (*openapi_options.Schema, error) {
+	if msg.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(msg.Options, openapi_options.E_Openapiv2Schema) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(msg.Options, openapi_options.E_Openapiv2Schema)
+	opts, ok := ext.(*openapi_options.Schema)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a Schema", ext)
+	}
+	return opts, nil
+}
+
+// extractEnumSchemaOptionFromEnumDescriptor extracts the message of type
+// openapi_options.EnumSchema from a given proto enum's descriptor.
+func extractEnumSchemaOptionFromEnumDescriptor(enum *descriptorpb.EnumDescriptorProto) (*openapi_options.EnumSchema, error) {
+	if enum.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(enum.Options, openapi_options.E_Openapiv2Enum) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(enum.Options, openapi_options.E_Openapiv2Enum)
+	opts, ok := ext.(*openapi_options.EnumSchema)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a EnumSchema", ext)
+	}
+	return opts, nil
+}
+
+// extractTagOptionFromServiceDescriptor extracts the tag of type
+// openapi_options.Tag from a given proto service's descriptor.
+func extractTagOptionFromServiceDescriptor(svc *descriptorpb.ServiceDescriptorProto) (*openapi_options.Tag, error) {
+	if svc.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(svc.Options, openapi_options.E_Openapiv2Tag) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(svc.Options, openapi_options.E_Openapiv2Tag)
+	opts, ok := ext.(*openapi_options.Tag)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a Tag", ext)
+	}
+	return opts, nil
+}
+
+// extractOpenAPIOptionFromFileDescriptor extracts the message of type
+// openapi_options.OpenAPI from a given proto method's descriptor.
+func extractOpenAPIOptionFromFileDescriptor(file *descriptorpb.FileDescriptorProto) (*openapi_options.Swagger, error) {
+	if file.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(file.Options, openapi_options.E_Openapiv2Swagger) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(file.Options, openapi_options.E_Openapiv2Swagger)
+	opts, ok := ext.(*openapi_options.Swagger)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a OpenAPI object", ext)
+	}
+	return opts, nil
+}
+
+func extractJSONSchemaFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) (*openapi_options.JSONSchema, error) {
+	if fd.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(fd.Options, openapi_options.E_Openapiv2Field) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(fd.Options, openapi_options.E_Openapiv2Field)
+	opts, ok := ext.(*openapi_options.JSONSchema)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a JSONSchema object", ext)
+	}
+	return opts, nil
+}
+
+func extractFieldBehaviorFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) ([]annotations.FieldBehavior, error) {
+	if fd.Options == nil {
+		return nil, nil
+	}
+	if !proto.HasExtension(fd.Options, annotations.E_FieldBehavior) {
+		return nil, nil
+	}
+	ext := proto.GetExtension(fd.Options, annotations.E_FieldBehavior)
+	opts, ok := ext.([]annotations.FieldBehavior)
+	if !ok {
+		return nil, fmt.Errorf("extension is %T; want a []FieldBehavior object", ext)
+	}
+	return opts, nil
+}
+
+func getFieldVisibilityOption(fd *descriptor.Field) *visibility.VisibilityRule {
+	if fd.Options == nil {
+		return nil
+	}
+	if !proto.HasExtension(fd.Options, visibility.E_FieldVisibility) {
+		return nil
+	}
+	ext := proto.GetExtension(fd.Options, visibility.E_FieldVisibility)
+	opts, ok := ext.(*visibility.VisibilityRule)
+	if !ok {
+		return nil
+	}
+	return opts
+}
+
+func getServiceVisibilityOption(fd *descriptor.Service) *visibility.VisibilityRule {
+	if fd.Options == nil {
+		return nil
+	}
+	if !proto.HasExtension(fd.Options, visibility.E_ApiVisibility) {
+		return nil
+	}
+	ext := proto.GetExtension(fd.Options, visibility.E_ApiVisibility)
+	opts, ok := ext.(*visibility.VisibilityRule)
+	if !ok {
+		return nil
+	}
+	return opts
+}
+
+func getMethodVisibilityOption(fd *descriptor.Method) *visibility.VisibilityRule {
+	if fd.Options == nil {
+		return nil
+	}
+	if !proto.HasExtension(fd.Options, visibility.E_MethodVisibility) {
+		return nil
+	}
+	ext := proto.GetExtension(fd.Options, visibility.E_MethodVisibility)
+	opts, ok := ext.(*visibility.VisibilityRule)
+	if !ok {
+		return nil
+	}
+	return opts
+}
+
+func getEnumValueVisibilityOption(fd *descriptorpb.EnumValueDescriptorProto) *visibility.VisibilityRule {
+	if fd.Options == nil {
+		return nil
+	}
+	if !proto.HasExtension(fd.Options, visibility.E_ValueVisibility) {
+		return nil
+	}
+	ext := proto.GetExtension(fd.Options, visibility.E_ValueVisibility)
+	opts, ok := ext.(*visibility.VisibilityRule)
+	if !ok {
+		return nil
+	}
+	return opts
+}
+
+func getMethodOpenAPIOption(reg *descriptor.Registry, meth *descriptor.Method) (*openapi_options.Operation, error) {
+	opts, err := extractOperationOptionFromMethodDescriptor(meth.MethodDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	if opts != nil {
+		return opts, nil
+	}
+	opts, ok := reg.GetOpenAPIMethodOptionv3(meth.FQMN())
+	if !ok {
+		return nil, nil
+	}
+	return opts, nil
+}
+
+func getMessageOpenAPIOption(reg *descriptor.Registry, msg *descriptor.Message) (*openapi_options.Schema, error) {
+	opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	if opts != nil {
+		return opts, nil
+	}
+	opts, ok := reg.GetOpenAPIMessageOptionv3(msg.FQMN())
+	if !ok {
+		return nil, nil
+	}
+	return opts, nil
+}
+
+func getEnumOpenAPIOption(reg *descriptor.Registry, enum *descriptor.Enum) (*openapi_options.EnumSchema, error) {
+	opts, err := extractEnumSchemaOptionFromEnumDescriptor(enum.EnumDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	return opts, nil
+}
+
+func getServiceOpenAPIOption(reg *descriptor.Registry, svc *descriptor.Service) (*openapi_options.Tag, error) {
+	if opts, ok := reg.GetOpenAPIServiceOptionv3(svc.FQSN()); ok {
+		return opts, nil
+	}
+	opts, err := extractTagOptionFromServiceDescriptor(svc.ServiceDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	return opts, nil
+}
+
+func getFileOpenAPIOption(reg *descriptor.Registry, file *descriptor.File) (*openapi_options.Swagger, error) {
+	opts, err := extractOpenAPIOptionFromFileDescriptor(file.FileDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	if opts != nil {
+		return opts, nil
+	}
+	opts, ok := reg.GetOpenAPIFileOptionv3(*file.Name)
+	if !ok {
+		return nil, nil
+	}
+	return opts, nil
+}
+
+func getFieldOpenAPIOption(reg *descriptor.Registry, fd *descriptor.Field) (*openapi_options.JSONSchema, error) {
+	opts, err := extractJSONSchemaFromFieldDescriptor(fd.FieldDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	if opts != nil {
+		return opts, nil
+	}
+	opts, ok := reg.GetOpenAPIFieldOptionv3(fd.FQFN())
+	if !ok {
+		return nil, nil
+	}
+	return opts, nil
+}
+
+func getFieldBehaviorOption(reg *descriptor.Registry, fd *descriptor.Field) ([]annotations.FieldBehavior, error) {
+	opts, err := extractFieldBehaviorFromFieldDescriptor(fd.FieldDescriptorProto)
+	if err != nil {
+		return nil, err
+	}
+	if opts != nil {
+		return opts, nil
+	}
+	return opts, nil
+}
+
+func protoJSONSchemaToOpenAPISchemaCore(j *openapi_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore {
+	ret := schemaCore{}
+
+	if j.GetRef() != "" {
+		openapiName, ok := fullyQualifiedNameToOpenAPIName(j.GetRef(), reg)
+		if ok {
+			ret.Ref = "#/definitions/" + openapiName
+			if refs != nil {
+				refs[j.GetRef()] = struct{}{}
+			}
+		} else {
+			ret.Ref += j.GetRef()
+		}
+	} else {
+		f, t := protoJSONSchemaTypeToFormat(j.GetType())
+		ret.Format = f
+		ret.Type = t
+	}
+
+	return ret
+}
+
+func updateswaggerObjectFromJSONSchema(s *openapiSchemaObject, j *openapi_options.JSONSchema, reg *descriptor.Registry, data interface{}) {
+	s.Title = j.GetTitle()
+	s.Description = j.GetDescription()
+	if reg.GetUseGoTemplate() {
+		s.Title = goTemplateComments(s.Title, data, reg)
+		s.Description = goTemplateComments(s.Description, data, reg)
+	}
+	if s.Type == "array" {
+		s.Items.MaxLength = j.GetMaxLength()
+		s.Items.MinLength = j.GetMinLength()
+		s.Items.Pattern = j.GetPattern()
+		s.Items.Default = j.GetDefault()
+		s.Items.MaxProperties = j.GetMaxProperties()
+		s.Items.MinProperties = j.GetMinProperties()
+		s.Items.Required = j.GetRequired()
+		s.Items.Minimum = j.GetMinimum()
+		s.Items.Maximum = j.GetMaximum()
+		s.Items.ReadOnly = j.GetReadOnly()
+		s.Items.MultipleOf = j.GetMultipleOf()
+		s.Items.ExclusiveMaximum = j.GetExclusiveMaximum()
+		s.Items.ExclusiveMinimum = j.GetExclusiveMinimum()
+		s.Items.Enum = j.GetEnum()
+
+		if j.GetDefault() == "" {
+			s.Items.Default = nil
+		}
+		if len(j.GetEnum()) == 0 {
+			s.Items.Enum = nil
+		}
+		if j.GetFormat() != "" {
+			s.Items.Format = j.GetFormat()
+		}
+	} else {
+		s.MaxLength = j.GetMaxLength()
+		s.MinLength = j.GetMinLength()
+		s.Pattern = j.GetPattern()
+		s.Default = j.GetDefault()
+		s.MaxProperties = j.GetMaxProperties()
+		s.MinProperties = j.GetMinProperties()
+		s.Required = j.GetRequired()
+		s.Minimum = j.GetMinimum()
+		s.Maximum = j.GetMaximum()
+		s.ReadOnly = j.GetReadOnly()
+		s.MultipleOf = j.GetMultipleOf()
+		s.ExclusiveMaximum = j.GetExclusiveMaximum()
+		s.ExclusiveMinimum = j.GetExclusiveMinimum()
+		s.Enum = j.GetEnum()
+
+		if j.GetDefault() == "" {
+			s.Default = nil
+		}
+		if len(j.GetEnum()) == 0 {
+			s.Enum = nil
+		}
+		if j.GetFormat() != "" {
+			s.Format = j.GetFormat()
+		}
+	}
+	s.UniqueItems = j.GetUniqueItems()
+	s.MaxItems = j.GetMaxItems()
+	s.MinItems = j.GetMinItems()
+
+	if j.GetExtensions() != nil {
+		exts, err := processExtensions(j.GetExtensions())
+		if err != nil {
+			panic(err)
+		}
+		s.extensions = exts
+	}
+	if overrideType := j.GetType(); len(overrideType) > 0 {
+		s.Type = strings.ToLower(overrideType[0].String())
+	}
+	if j.GetExample() != "" {
+		s.Example = RawExample(j.GetExample())
+	}
+}
+
+func updateSwaggerObjectFromFieldBehavior(s *openapiSchemaObject, j []annotations.FieldBehavior, reg *descriptor.Registry, field *descriptor.Field) {
+	required := false
+	if reg.GetUseProto3FieldSemantics() {
+		required = !field.GetProto3Optional()
+	}
+	for _, fb := range j {
+		switch fb {
+		case annotations.FieldBehavior_REQUIRED:
+			required = true
+		case annotations.FieldBehavior_OUTPUT_ONLY:
+			s.ReadOnly = true
+		case annotations.FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED:
+		case annotations.FieldBehavior_OPTIONAL:
+			required = false
+		case annotations.FieldBehavior_INPUT_ONLY:
+			// OpenAPI v3 supports a writeOnly property, but this is not supported in Open API v2
+		case annotations.FieldBehavior_IMMUTABLE:
+		}
+	}
+	if required {
+		if reg.GetUseJSONNamesForFields() {
+			s.Required = append(s.Required, *field.JsonName)
+		} else {
+			s.Required = append(s.Required, *field.Name)
+		}
+	}
+}
+
+func openapiSchemaFromProtoEnumSchema(s *openapi_options.EnumSchema, reg *descriptor.Registry, refs refMap, data interface{}) openapiSchemaObject {
+	ret := openapiSchemaObject{
+		ExternalDocs: protoExternalDocumentationToOpenAPIExternalDocumentation(s.GetExternalDocs(), reg, data),
+	}
+	jsonSchema := &openapi_options.JSONSchema{
+		Ref:         s.Ref,
+		Title:       s.Title,
+		Extensions:  s.Extensions,
+		Description: s.Description,
+		Default:     s.Default,
+		ReadOnly:    s.ReadOnly,
+		Example:     s.Example,
+	}
+	ret.schemaCore = protoJSONSchemaToOpenAPISchemaCore(jsonSchema, reg, refs)
+	updateswaggerObjectFromJSONSchema(&ret, jsonSchema, reg, data)
+	return ret
+}
+
+func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Registry, refs refMap, data interface{}) openapiSchemaObject {
+	ret := openapiSchemaObject{
+		ExternalDocs: protoExternalDocumentationToOpenAPIExternalDocumentation(s.GetExternalDocs(), reg, data),
+	}
+
+	ret.schemaCore = protoJSONSchemaToOpenAPISchemaCore(s.GetJsonSchema(), reg, refs)
+	updateswaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data)
+
+	if s != nil && s.Example != "" {
+		ret.Example = RawExample(s.Example)
+	}
+
+	return ret
+}
+
+func openapiExamplesFromProtoExamples(in map[string]string) map[string]interface{} {
+	if len(in) == 0 {
+		return nil
+	}
+	out := make(map[string]interface{}, len(in))
+	for mimeType, exampleStr := range in {
+		switch mimeType {
+		case "application/json":
+			// JSON example objects are rendered raw.
+			out[mimeType] = RawExample(exampleStr)
+		default:
+			// All other mimetype examples are rendered as strings.
+			out[mimeType] = exampleStr
+		}
+	}
+	return out
+}
+
+func protoJSONSchemaTypeToFormat(in []openapi_options.JSONSchema_JSONSchemaSimpleTypes) (string, string) {
+	if len(in) == 0 {
+		return "", ""
+	}
+
+	// Can't support more than 1 type, just return the first element.
+	// This is due to an inconsistency in the design of the openapiv2 proto
+	// and that used in schemaCore. schemaCore uses the v3 definition of types,
+	// which only allows a single string, while the openapiv2 proto uses the OpenAPI v2
+	// definition, which defers to the JSON schema definition, which allows a string or an array.
+	// Sources:
+	// https://swagger.io/specification/#itemsObject
+	// https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.2
+	switch in[0] {
+	case openapi_options.JSONSchema_UNKNOWN, openapi_options.JSONSchema_NULL:
+		return "", ""
+	case openapi_options.JSONSchema_OBJECT:
+		return "object", ""
+	case openapi_options.JSONSchema_ARRAY:
+		return "array", ""
+	case openapi_options.JSONSchema_BOOLEAN:
+		// NOTE: in OpenAPI specification, format should be empty on boolean type
+		return "boolean", ""
+	case openapi_options.JSONSchema_INTEGER:
+		return "integer", "int32"
+	case openapi_options.JSONSchema_NUMBER:
+		return "number", "double"
+	case openapi_options.JSONSchema_STRING:
+		// NOTE: in OpenAPI specification, format should be empty on string type
+		return "string", ""
+	default:
+		// Maybe panic?
+		return "", ""
+	}
+}
+
+func protoExternalDocumentationToOpenAPIExternalDocumentation(in *openapi_options.ExternalDocumentation, reg *descriptor.Registry, data interface{}) *openapiExternalDocumentationObject {
+	if in == nil {
+		return nil
+	}
+
+	if reg.GetUseGoTemplate() {
+		in.Description = goTemplateComments(in.Description, data, reg)
+	}
+
+	return &openapiExternalDocumentationObject{
+		Description: in.Description,
+		URL:         in.Url,
+	}
+}
+
+func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) error {
+	if len(refs) == 0 {
+		return nil
+	}
+	msgMap := make(messageMap)
+	enumMap := make(enumMap)
+	for ref := range refs {
+		swgName, swgOk := fullyQualifiedNameToOpenAPIName(ref, reg)
+		if !swgOk {
+			grpclog.Errorf("can't resolve OpenAPI name from CustomRef %q", ref)
+			continue
+		}
+		if _, ok := d[swgName]; ok {
+			// Skip already existing definitions
+			delete(refs, ref)
+			continue
+		}
+		msg, err := reg.LookupMsg("", ref)
+		if err == nil {
+			msgMap[swgName] = msg
+			continue
+		}
+		enum, err := reg.LookupEnum("", ref)
+		if err == nil {
+			enumMap[swgName] = enum
+			continue
+		}
+
+		// ?? Should be either enum or msg
+	}
+	if err := renderMessagesAsDefinition(msgMap, d, reg, refs, nil); err != nil {
+		return err
+	}
+	renderEnumerationsAsDefinition(enumMap, d, reg, refs)
+
+	// Run again in case any new refs were added
+	return addCustomRefs(d, reg, refs)
+}
+
+func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descriptor.Message) string {
+	for _, oneField := range fields {
+		if oneField.GetName() == fieldName {
+			return oneField.GetJsonName()
+		}
+	}
+	messageNameToFieldsToJSONName := make(map[string]map[string]string, len(msgs))
+	fieldNameToType := make(map[string]string)
+	for _, msg := range msgs {
+		fieldNameToJSONName := make(map[string]string)
+		for _, oneField := range msg.GetField() {
+			fieldNameToJSONName[oneField.GetName()] = oneField.GetJsonName()
+			fieldNameToType[oneField.GetName()] = oneField.GetTypeName()
+		}
+		messageNameToFieldsToJSONName[msg.GetName()] = fieldNameToJSONName
+	}
+	if strings.Contains(fieldName, ".") {
+		fieldNames := strings.Split(fieldName, ".")
+		fieldNamesWithCamelCase := make([]string, 0)
+		for i := 0; i < len(fieldNames)-1; i++ {
+			fieldNamesWithCamelCase = append(fieldNamesWithCamelCase, casing.JSONCamelCase(fieldNames[i]))
+		}
+		prefix := strings.Join(fieldNamesWithCamelCase, ".")
+		reservedJSONName := getReservedJSONName(fieldName, messageNameToFieldsToJSONName, fieldNameToType)
+		if reservedJSONName != "" {
+			return prefix + "." + reservedJSONName
+		}
+	}
+	return casing.JSONCamelCase(fieldName)
+}
+
+func getReservedJSONName(fieldName string, messageNameToFieldsToJSONName map[string]map[string]string, fieldNameToType map[string]string) string {
+	if len(strings.Split(fieldName, ".")) == 2 {
+		fieldNames := strings.Split(fieldName, ".")
+		firstVariable := fieldNames[0]
+		firstType := fieldNameToType[firstVariable]
+		firstTypeShortNames := strings.Split(firstType, ".")
+		firstTypeShortName := firstTypeShortNames[len(firstTypeShortNames)-1]
+		return messageNameToFieldsToJSONName[firstTypeShortName][fieldNames[1]]
+	}
+	fieldNames := strings.Split(fieldName, ".")
+	return getReservedJSONName(strings.Join(fieldNames[1:], "."), messageNameToFieldsToJSONName, fieldNameToType)
+}
+
+func find(a []string, x string) int {
+	// This is a linear search but we are dealing with a small number of fields
+	for i, n := range a {
+		if x == n {
+			return i
+		}
+	}
+	return -1
+}
+
+// Make a deep copy of the outer parameters that has paramName as the first component,
+// but remove the first component of the field path.
+func subPathParams(paramName string, outerParams []descriptor.Parameter) []descriptor.Parameter {
+	var innerParams []descriptor.Parameter
+	for _, p := range outerParams {
+		if len(p.FieldPath) > 1 && p.FieldPath[0].Name == paramName {
+			subParam := descriptor.Parameter{
+				FieldPath: p.FieldPath[1:],
+				Target:    p.Target,
+				Method:    p.Method,
+			}
+			innerParams = append(innerParams, subParam)
+		}
+	}
+	return innerParams
+}
+
+func getFieldConfiguration(reg *descriptor.Registry, fd *descriptor.Field) *openapi_options.JSONSchema_FieldConfiguration {
+	if j, err := getFieldOpenAPIOption(reg, fd); err == nil {
+		return j.GetFieldConfiguration()
+	}
+	return nil
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/template_fuzz_test.go b/protoc-gen-openapiv3/internal/genopenapi/template_fuzz_test.go
new file mode 100644
index 00000000000..c8a164988f0
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/template_fuzz_test.go
@@ -0,0 +1,26 @@
+//go:build go1.18
+// +build go1.18
+
+package genopenapi
+
+import (
+	"regexp"
+	"testing"
+)
+
+var replaceInternalCommentsRegex = regexp.MustCompile(`(?s)(\r?\n)?[ \t]*(\(--)((.*?--\))|.*$)?`)
+
+func FuzzRemoveInternalComments(f *testing.F) {
+	f.Add("Text\n\n(-- Comment --)\n\nMore Text\n")
+	f.Add("Text\n\n(-- Multi\nLine\n\nComment --)\n\nMore Text\n")
+	f.Add("(-- Starting with comment --)\n\nMore Text\n")
+	f.Add("\n\n(-- Starting with new line and comment --)\n\nMore Text\n")
+	f.Add("Ending with\n\n(-- Comment --)")
+	f.Fuzz(func(t *testing.T, s string) {
+		s1 := removeInternalComments(s)
+		s2 := replaceInternalCommentsRegex.ReplaceAllString(s, "")
+		if s1 != s2 {
+			t.Errorf("Unexpected comment removal difference: our function produced %q but regex produced %q on %q", s1, s2, s)
+		}
+	})
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/template_test.go b/protoc-gen-openapiv3/internal/genopenapi/template_test.go
new file mode 100644
index 00000000000..7b0ae4efdb7
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/template_test.go
@@ -0,0 +1,11281 @@
+package genopenapi
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+	"os"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfigv3"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule"
+	openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+	"google.golang.org/genproto/googleapis/api/annotations"
+	"google.golang.org/genproto/googleapis/api/visibility"
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protodesc"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/reflect/protoregistry"
+	"google.golang.org/protobuf/types/descriptorpb"
+	"google.golang.org/protobuf/types/known/anypb"
+	"google.golang.org/protobuf/types/known/durationpb"
+	"google.golang.org/protobuf/types/known/emptypb"
+	field_mask "google.golang.org/protobuf/types/known/fieldmaskpb"
+	"google.golang.org/protobuf/types/known/structpb"
+	"google.golang.org/protobuf/types/known/timestamppb"
+	"google.golang.org/protobuf/types/known/wrapperspb"
+	"google.golang.org/protobuf/types/pluginpb"
+)
+
+var marshaler = &runtime.JSONPb{}
+
+func TestOpenapiExamplesFromProtoExamples(t *testing.T) {
+	examples := openapiExamplesFromProtoExamples(map[string]string{
+		"application/json": `{"Hello": "Worldr!"}`,
+		"plain/text":       "Hello, World!",
+	})
+
+	testCases := map[Format]string{
+		FormatJSON: `
+		{
+			"application/json": {
+				"Hello": "Worldr!"
+			},
+			"plain/text": "Hello, World!"
+		}
+		`,
+		FormatYAML: `
+		application/json:
+		  Hello: Worldr!
+		plain/text: Hello, World!
+		`,
+	}
+
+	spaceRemover := strings.NewReplacer(" ", "", "\t", "", "\n", "")
+
+	for format, expected := range testCases {
+		t.Run(string(format), func(t *testing.T) {
+			var buf bytes.Buffer
+
+			encoder, err := format.NewEncoder(&buf)
+			if err != nil {
+				t.Fatalf("creating encoder: %s", err)
+			}
+
+			err = encoder.Encode(examples)
+			if err != nil {
+				t.Fatalf("encoding: %s", err)
+			}
+
+			actual := spaceRemover.Replace(buf.String())
+			expected = spaceRemover.Replace(expected)
+
+			if expected != actual {
+				t.Fatalf("expected:\n%s\nactual:\n%s", expected, actual)
+			}
+		})
+	}
+}
+
+func crossLinkFixture(f *descriptor.File) *descriptor.File {
+	for _, m := range f.Messages {
+		m.File = f
+	}
+	for _, svc := range f.Services {
+		svc.File = f
+		for _, m := range svc.Methods {
+			m.Service = svc
+			for _, b := range m.Bindings {
+				b.Method = m
+				for _, param := range b.PathParams {
+					param.Method = m
+				}
+			}
+		}
+	}
+	return f
+}
+
+func reqFromFile(f *descriptor.File) *pluginpb.CodeGeneratorRequest {
+	return &pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{
+			f.FileDescriptorProto,
+		},
+		FileToGenerate: []string{f.GetName()},
+	}
+}
+
+func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:   proto.String("b"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
+							Number: proto.Int32(2),
+						},
+						{
+							Name:   proto.String("c"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+							Number: proto.Int32(3),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "b",
+					In:       "query",
+					Required: false,
+					Type:     "number",
+					Format:   "double",
+				},
+				{
+					Name:             "c",
+					In:               "query",
+					Required:         false,
+					Type:             "array",
+					CollectionFormat: "multi",
+				},
+			},
+		},
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("Nested"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:     proto.String("deep"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested.DeepNested"),
+							Number:   proto.Int32(2),
+						},
+					},
+					NestedType: []*descriptorpb.DescriptorProto{{
+						Name: proto.String("DeepNested"),
+						Field: []*descriptorpb.FieldDescriptorProto{
+							{
+								Name:   proto.String("b"),
+								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+								Number: proto.Int32(1),
+							},
+							{
+								Name:     proto.String("c"),
+								Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+								TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"),
+								Number:   proto.Int32(2),
+							},
+						},
+						EnumType: []*descriptorpb.EnumDescriptorProto{
+							{
+								Name: proto.String("DeepEnum"),
+								Value: []*descriptorpb.EnumValueDescriptorProto{
+									{Name: proto.String("FALSE"), Number: proto.Int32(0)},
+									{Name: proto.String("TRUE"), Number: proto.Int32(1)},
+								},
+							},
+						},
+					}},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "nested.a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.b",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.c",
+					In:       "query",
+					Required: false,
+					Type:     "integer",
+					Enum:     []int{0, 1},
+					Default:  0,
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		reg.SetEnumsAsInts(true)
+		var msgs []*descriptor.Message
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		// avoid checking Items for array types
+		for i := range params {
+			params[i].Items = nil
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+func TestMessageToQueryParametersWithOmitEnumDefaultValue(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:   proto.String("b"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
+							Number: proto.Int32(2),
+						},
+						{
+							Name:   proto.String("c"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+							Number: proto.Int32(3),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "b",
+					In:       "query",
+					Required: false,
+					Type:     "number",
+					Format:   "double",
+				},
+				{
+					Name:             "c",
+					In:               "query",
+					Required:         false,
+					Type:             "array",
+					CollectionFormat: "multi",
+				},
+			},
+		},
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("Nested"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:     proto.String("deep"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested.DeepNested"),
+							Number:   proto.Int32(2),
+						},
+					},
+					NestedType: []*descriptorpb.DescriptorProto{{
+						Name: proto.String("DeepNested"),
+						Field: []*descriptorpb.FieldDescriptorProto{
+							{
+								Name:   proto.String("b"),
+								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+								Number: proto.Int32(1),
+							},
+							{
+								Name:     proto.String("c"),
+								Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+								TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"),
+								Number:   proto.Int32(2),
+							},
+						},
+						EnumType: []*descriptorpb.EnumDescriptorProto{
+							{
+								Name: proto.String("DeepEnum"),
+								Value: []*descriptorpb.EnumValueDescriptorProto{
+									{Name: proto.String("FALSE"), Number: proto.Int32(0)},
+									{Name: proto.String("TRUE"), Number: proto.Int32(1)},
+								},
+							},
+						},
+					}},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "nested.a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.b",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.c",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+					Enum:     []string{"TRUE"},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		reg.SetOmitEnumDefaultValue(true)
+		var msgs []*descriptor.Message
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		// avoid checking Items for array types
+		for i := range params {
+			params[i].Items = nil
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+func TestMessageToQueryParameters(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:   proto.String("b"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
+							Number: proto.Int32(2),
+						},
+						{
+							Name:   proto.String("c"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+							Number: proto.Int32(3),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "b",
+					In:       "query",
+					Required: false,
+					Type:     "number",
+					Format:   "double",
+				},
+				{
+					Name:             "c",
+					In:               "query",
+					Required:         false,
+					Type:             "array",
+					CollectionFormat: "multi",
+				},
+			},
+		},
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("Nested"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:     proto.String("deep"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Nested.DeepNested"),
+							Number:   proto.Int32(2),
+						},
+					},
+					NestedType: []*descriptorpb.DescriptorProto{{
+						Name: proto.String("DeepNested"),
+						Field: []*descriptorpb.FieldDescriptorProto{
+							{
+								Name:   proto.String("b"),
+								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+								Number: proto.Int32(1),
+							},
+							{
+								Name:     proto.String("c"),
+								Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+								TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"),
+								Number:   proto.Int32(2),
+							},
+						},
+						EnumType: []*descriptorpb.EnumDescriptorProto{
+							{
+								Name: proto.String("DeepEnum"),
+								Value: []*descriptorpb.EnumValueDescriptorProto{
+									{Name: proto.String("FALSE"), Number: proto.Int32(0)},
+									{Name: proto.String("TRUE"), Number: proto.Int32(1)},
+								},
+							},
+						},
+					}},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "nested.a",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.b",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "nested.deep.c",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+					Enum:     []string{"FALSE", "TRUE"},
+					Default:  "FALSE",
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		// avoid checking Items for array types
+		for i := range params {
+			params[i].Items = nil
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+// TestMessageToQueryParametersNoRecursive, is a check that cyclical references between messages
+// are not falsely detected given previous known edge-cases.
+func TestMessageToQueryParametersNoRecursive(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+	}
+
+	tests := []test{
+		// First test:
+		// Here is a message that has two of another message adjacent to one another in a nested message.
+		// There is no loop but this was previously falsely flagged as a cycle.
+		// Example proto:
+		// message NonRecursiveMessage {
+		//      string field = 1;
+		// }
+		// message BaseMessage {
+		//      NonRecursiveMessage first = 1;
+		//      NonRecursiveMessage second = 2;
+		// }
+		// message QueryMessage {
+		//      BaseMessage first = 1;
+		//      string second = 2;
+		// }
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("QueryMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("first"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.BaseMessage"),
+							Number:   proto.Int32(1),
+						},
+						{
+							Name:   proto.String("second"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(2),
+						},
+					},
+				},
+				{
+					Name: proto.String("BaseMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("first"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.NonRecursiveMessage"),
+							Number:   proto.Int32(1),
+						},
+						{
+							Name:     proto.String("second"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.NonRecursiveMessage"),
+							Number:   proto.Int32(2),
+						},
+					},
+				},
+				// Note there is no recursive nature to this message
+				{
+					Name: proto.String("NonRecursiveMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name: proto.String("field"),
+							// Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+					},
+				},
+			},
+			Message: "QueryMessage",
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+
+		_, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("No recursion error should be thrown: %s", err)
+		}
+	}
+}
+
+// TestMessageToQueryParametersRecursive, is a check that cyclical references between messages
+// are handled gracefully. The goal is to ensure that attempts to add messages with cyclical
+// references to query-parameters returns an error message.
+func TestMessageToQueryParametersRecursive(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+	}
+
+	tests := []test{
+		// First test:
+		// Here we test that a message that references itself through a field will return an error.
+		// Example proto:
+		// message DirectRecursiveMessage {
+		//      DirectRecursiveMessage nested = 1;
+		// }
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("DirectRecursiveMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.DirectRecursiveMessage"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+			},
+			Message: "DirectRecursiveMessage",
+		},
+		// Second test:
+		// Here we test that a cycle through multiple messages is detected and that an error is returned.
+		// Sample:
+		// message Root { NodeMessage nested = 1; }
+		// message NodeMessage { CycleMessage nested = 1; }
+		// message CycleMessage { Root nested = 1; }
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("RootMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.NodeMessage"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("NodeMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.CycleMessage"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("CycleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.RootMessage"),
+							Number:   proto.Int32(1),
+						},
+					},
+				},
+			},
+			Message: "RootMessage",
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		_, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err == nil {
+			t.Fatalf("It should not be allowed to have recursive query parameters")
+		}
+	}
+}
+
+func TestMessageToQueryParametersWithJsonName(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	requiredField := []annotations.FieldBehavior{annotations.FieldBehavior_REQUIRED}
+	requiredFieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(requiredFieldOptions, annotations.E_FieldBehavior, requiredField)
+
+	messageSchema := &openapi_options.Schema{
+		JsonSchema: &openapi_options.JSONSchema{
+			Required: []string{"test_field_b"},
+		},
+	}
+	messageOption := &descriptorpb.MessageOptions{}
+	proto.SetExtension(messageOption, openapi_options.E_Openapiv2Schema, messageSchema)
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("test_field_a"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(1),
+							JsonName: proto.String("testFieldA"),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "testFieldA",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+			},
+		},
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("SubMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("test_field_a"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(1),
+							JsonName: proto.String("testFieldA"),
+						},
+					},
+				},
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("sub_message"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.SubMessage"),
+							Number:   proto.Int32(1),
+							JsonName: proto.String("subMessage"),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "subMessage.testFieldA",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+			},
+		},
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("test_field_a"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(1),
+							JsonName: proto.String("testFieldACustom"),
+							Options:  requiredFieldOptions,
+						},
+						{
+							Name:     proto.String("test_field_b"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(2),
+							JsonName: proto.String("testFieldBCustom"),
+						},
+					},
+					Options: messageOption,
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "testFieldACustom",
+					In:       "query",
+					Required: true,
+					Type:     "string",
+				},
+				{
+					Name:     "testFieldBCustom",
+					In:       "query",
+					Required: true,
+					Type:     "string",
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		reg.SetUseJSONNamesForFields(true)
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %#v, got %#v", test.Params, params)
+		}
+	}
+}
+
+func TestMessageToQueryParametersWellKnownTypes(t *testing.T) {
+	type test struct {
+		MsgDescs          []*descriptorpb.DescriptorProto
+		WellKnownMsgDescs []*descriptorpb.DescriptorProto
+		Message           string
+		Params            []openapiParameterObject
+	}
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("a_field_mask"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".google.protobuf.FieldMask"),
+							Number:   proto.Int32(1),
+						},
+						{
+							Name:     proto.String("a_timestamp"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".google.protobuf.Timestamp"),
+							Number:   proto.Int32(2),
+						},
+					},
+				},
+			},
+			WellKnownMsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("FieldMask"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("paths"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+							Number: proto.Int32(1),
+						},
+					},
+				},
+				{
+					Name: proto.String("Timestamp"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("seconds"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:   proto.String("nanos"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+							Number: proto.Int32(2),
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "a_field_mask",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+				},
+				{
+					Name:     "a_timestamp",
+					In:       "query",
+					Required: false,
+					Type:     "string",
+					Format:   "date-time",
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		reg.SetEnumsAsInts(true)
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{
+				{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("google/well_known.proto"),
+					Package:        proto.String("google.protobuf"),
+					Dependency:     []string{},
+					MessageType:    test.WellKnownMsgDescs,
+					Service:        []*descriptorpb.ServiceDescriptorProto{},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("google/well_known"),
+					},
+				},
+				{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("acme/example.proto"),
+					Package:        proto.String("example"),
+					Dependency:     []string{"google/well_known.proto"},
+					MessageType:    test.MsgDescs,
+					Service:        []*descriptorpb.ServiceDescriptorProto{},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("acme/example"),
+					},
+				},
+			},
+		})
+		if err != nil {
+			t.Fatalf("failed to load CodeGeneratorRequest: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+func TestMessageToQueryParametersWithRequiredField(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	messageSchema := &openapi_options.Schema{
+		JsonSchema: &openapi_options.JSONSchema{
+			Required: []string{"a"},
+		},
+	}
+	messageOption := &descriptorpb.MessageOptions{}
+	proto.SetExtension(messageOption, openapi_options.E_Openapiv2Schema, messageSchema)
+
+	fieldSchema := &openapi_options.JSONSchema{Required: []string{"b"}}
+	fieldOption := &descriptorpb.FieldOptions{}
+	proto.SetExtension(fieldOption, openapi_options.E_Openapiv2Field, fieldSchema)
+
+	// TODO(makdon): is nested field's test case necessary here?
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("a"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:    proto.String("b"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
+							Number:  proto.Int32(2),
+							Options: fieldOption,
+						},
+						{
+							Name:   proto.String("c"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+							Number: proto.Int32(3),
+						},
+					},
+					Options: messageOption,
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name:     "a",
+					In:       "query",
+					Required: true,
+					Type:     "string",
+				},
+				{
+					Name:     "b",
+					In:       "query",
+					Required: true,
+					Type:     "number",
+					Format:   "double",
+				},
+				{
+					Name:             "c",
+					In:               "query",
+					Required:         false,
+					Type:             "array",
+					CollectionFormat: "multi",
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		// avoid checking Items for array types
+		for i := range params {
+			params[i].Items = nil
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+func TestMessageToQueryParametersWithEnumFieldOption(t *testing.T) {
+	type test struct {
+		MsgDescs []*descriptorpb.DescriptorProto
+		Message  string
+		Params   []openapiParameterObject
+	}
+
+	fieldSchema := &openapi_options.JSONSchema{Enum: []string{"enum1", "enum2"}}
+	fieldOption := &descriptorpb.FieldOptions{}
+	proto.SetExtension(fieldOption, openapi_options.E_Openapiv2Field, fieldSchema)
+
+	tests := []test{
+		{
+			MsgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("ExampleMessage"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("a"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(1),
+							Options: fieldOption,
+						},
+						{
+							Name:   proto.String("b"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(2),
+						},
+						{
+							Name:     proto.String("c"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+							TypeName: proto.String(".example.ExampleMessage.EnabledEnum"),
+							Number:   proto.Int32(3),
+						},
+						{
+							Name:     proto.String("d"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+							TypeName: proto.String(".example.ExampleMessage.EnabledEnum"),
+							Number:   proto.Int32(4),
+							Options:  fieldOption,
+						},
+					},
+					EnumType: []*descriptorpb.EnumDescriptorProto{
+						{
+							Name: proto.String("EnabledEnum"),
+							Value: []*descriptorpb.EnumValueDescriptorProto{
+								{Name: proto.String("FALSE"), Number: proto.Int32(0)},
+								{Name: proto.String("TRUE"), Number: proto.Int32(1)},
+							},
+						},
+					},
+				},
+			},
+			Message: "ExampleMessage",
+			Params: []openapiParameterObject{
+				{
+					Name: "a",
+					In:   "query",
+					Type: "string",
+					Enum: []string{"enum1", "enum2"},
+				},
+				{
+					Name: "b",
+					In:   "query",
+					Type: "string",
+				},
+				{
+					Name:    "c",
+					In:      "query",
+					Type:    "string",
+					Enum:    []string{"FALSE", "TRUE"},
+					Default: "FALSE",
+				},
+				{
+					Name:    "d",
+					In:      "query",
+					Type:    "string",
+					Enum:    []string{"FALSE", "TRUE"},
+					Default: "FALSE",
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		msgs := []*descriptor.Message{}
+		for _, msgdesc := range test.MsgDescs {
+			msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+		}
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				Dependency:     []string{},
+				MessageType:    test.MsgDescs,
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: msgs,
+		}
+		err := reg.Load(&pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+		})
+		if err != nil {
+			t.Fatalf("failed to load code generator request: %v", err)
+		}
+
+		message, err := reg.LookupMsg("", ".example."+test.Message)
+		if err != nil {
+			t.Fatalf("failed to lookup message: %s", err)
+		}
+		params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "")
+		if err != nil {
+			t.Fatalf("failed to convert message to query parameters: %s", err)
+		}
+		// avoid checking Items for array types
+		for i := range params {
+			params[i].Items = nil
+		}
+		if !reflect.DeepEqual(params, test.Params) {
+			t.Errorf("expected %v, got %v", test.Params, params)
+		}
+	}
+}
+
+func TestApplyTemplateSimple(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								Body:       &descriptor.Body{FieldPath: nil},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(reqFromFile(fileCL))
+	if err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+		return
+	}
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := ([]string)(nil), result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateMultiService(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+
+	// Create two services that have the same method name. We will test that the
+	// operation IDs are different
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	svc2 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("OtherService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								Body:       &descriptor.Body{FieldPath: nil},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo",
+								},
+							},
+						},
+					},
+				},
+			},
+			{
+				ServiceDescriptorProto: svc2,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								Body:       &descriptor.Body{FieldPath: nil},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/ping",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(reqFromFile(fileCL))
+	if err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+		return
+	}
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	// Check that the two services have unique operation IDs even though they
+	// have the same method name.
+	if want, is := "ExampleService_Example", result.getPathItemObject("/v1/echo").Get.OperationID; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want)
+	}
+	if want, is := "OtherService_Example", result.getPathItemObject("/v1/ping").Get.OperationID; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want)
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateOpenAPIConfigFromYAML(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								Body:       &descriptor.Body{FieldPath: nil},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(reqFromFile(fileCL))
+	if err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+		return
+	}
+	openapiOptions := &openapiconfigv3.OpenAPIOptions{
+		Service: []*openapiconfigv3.OpenAPIServiceOption{
+			{
+				Service: "example.ExampleService",
+				Option: &openapi_options.Tag{
+					Description: "ExampleService description",
+					ExternalDocs: &openapi_options.ExternalDocumentation{
+						Description: "Find out more about ExampleService",
+					},
+				},
+			},
+		},
+	}
+	if err := reg.RegisterOpenAPIOptionsv3(openapiOptions); err != nil {
+		t.Errorf("reg.RegisterOpenAPIOptions for Service %#v failed with %v; want success", openapiOptions.Service, err)
+		return
+	}
+
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	if want, is, name := "ExampleService description", result.Tags[0].Description, "Tags[0].Description"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := "Find out more about ExampleService", result.Tags[0].ExternalDocs.Description, "Tags[0].ExternalDocs.Description"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+
+	reg.SetDisableServiceTags(true)
+
+	res, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	if got, want := len(res.Tags), 0; got != want {
+		t.Fatalf("len(applyTemplate(%#v).Tags) = %d want to be %d", file, got, want)
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateOverrideWithOperation(t *testing.T) {
+	newFile := func() *descriptor.File {
+		msgdesc := &descriptorpb.DescriptorProto{
+			Name: proto.String("ExampleMessage"),
+		}
+		meth := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String("Example"),
+			InputType:  proto.String("ExampleMessage"),
+			OutputType: proto.String("ExampleMessage"),
+			Options:    &descriptorpb.MethodOptions{},
+		}
+		svc := &descriptorpb.ServiceDescriptorProto{
+			Name:   proto.String("ExampleService"),
+			Method: []*descriptorpb.MethodDescriptorProto{meth},
+		}
+		msg := &descriptor.Message{
+			DescriptorProto: msgdesc,
+		}
+		return &descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: []*descriptor.Message{msg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: meth,
+							RequestType:           msg,
+							ResponseType:          msg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: "GET",
+									Body:       &descriptor.Body{FieldPath: nil},
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+	}
+
+	verifyTemplateFromReq := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, opts *openapiconfigv3.OpenAPIOptions) {
+		if err := AddErrorDefs(reg); err != nil {
+			t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+			return
+		}
+		fileCL := crossLinkFixture(file)
+		err := reg.Load(reqFromFile(fileCL))
+		if err != nil {
+			t.Errorf("reg.Load(%#v) failed with %v; want success", *file, err)
+			return
+		}
+		if opts != nil {
+			if err := reg.RegisterOpenAPIOptionsv3(opts); err != nil {
+				t.Fatalf("failed to register OpenAPI options: %s", err)
+			}
+		}
+		result, err := applyTemplate(param{File: fileCL, reg: reg})
+		if err != nil {
+			t.Errorf("applyTemplate(%#v) failed with %v; want success", *file, err)
+			return
+		}
+
+		if want, is := "MyExample", result.getPathItemObject("/v1/echo").Get.OperationID; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", *file, is, want)
+		}
+		if want, is := []string{"application/xml"}, result.getPathItemObject("/v1/echo").Get.Consumes; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).Paths[0].Get.Consumes = %s want to be %s", *file, is, want)
+		}
+		if want, is := []string{"application/json", "application/xml"}, result.getPathItemObject("/v1/echo").Get.Produces; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).Paths[0].Get.Produces = %s want to be %s", *file, is, want)
+		}
+
+		// If there was a failure, print out the input and the json result for debugging.
+		if t.Failed() {
+			t.Errorf("had: %s", *file)
+			t.Errorf("got: %s", fmt.Sprint(result))
+		}
+	}
+
+	openapiOperation := openapi_options.Operation{
+		OperationId: "MyExample",
+		Consumes:    []string{"application/xml"},
+		Produces:    []string{"application/json", "application/xml"},
+	}
+
+	t.Run("verify override via method option", func(t *testing.T) {
+		file := newFile()
+		proto.SetExtension(proto.Message(file.Services[0].Methods[0].MethodDescriptorProto.Options),
+			openapi_options.E_Openapiv2Operation, &openapiOperation)
+
+		reg := descriptor.NewRegistry()
+		verifyTemplateFromReq(t, reg, file, nil)
+	})
+
+	t.Run("verify override options annotations", func(t *testing.T) {
+		file := newFile()
+		reg := descriptor.NewRegistry()
+		opts := &openapiconfigv3.OpenAPIOptions{
+			Method: []*openapiconfigv3.OpenAPIMethodOption{
+				{
+					Method: "example.ExampleService.Example",
+					Option: &openapiOperation,
+				},
+			},
+		}
+		verifyTemplateFromReq(t, reg, file, opts)
+	})
+}
+
+func TestApplyTemplateExtensions(t *testing.T) {
+	newFile := func() *descriptor.File {
+		msgdesc := &descriptorpb.DescriptorProto{
+			Name: proto.String("ExampleMessage"),
+		}
+		meth := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String("Example"),
+			InputType:  proto.String("ExampleMessage"),
+			OutputType: proto.String("ExampleMessage"),
+			Options:    &descriptorpb.MethodOptions{},
+		}
+		svc := &descriptorpb.ServiceDescriptorProto{
+			Name:   proto.String("ExampleService"),
+			Method: []*descriptorpb.MethodDescriptorProto{meth},
+		}
+		msg := &descriptor.Message{
+			DescriptorProto: msgdesc,
+		}
+		return &descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: []*descriptor.Message{msg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: meth,
+							RequestType:           msg,
+							ResponseType:          msg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: "GET",
+									Body:       &descriptor.Body{FieldPath: nil},
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+	}
+	swagger := openapi_options.Swagger{
+		Info: &openapi_options.Info{
+			Title: "test",
+			Extensions: map[string]*structpb.Value{
+				"x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}},
+			},
+		},
+		Extensions: map[string]*structpb.Value{
+			"x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}},
+			"x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{
+				Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}},
+			}}},
+		},
+		SecurityDefinitions: &openapi_options.SecurityDefinitions{
+			Security: map[string]*openapi_options.SecurityScheme{
+				"somescheme": {
+					Extensions: map[string]*structpb.Value{
+						"x-security-baz": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
+					},
+				},
+			},
+		},
+		Tags: []*openapi_options.Tag{
+			{
+				Name:        "test tag",
+				Description: "test tag description",
+				Extensions: map[string]*structpb.Value{
+					"x-traitTag": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
+				},
+			},
+		},
+	}
+	openapiOperation := openapi_options.Operation{
+		Responses: map[string]*openapi_options.Response{
+			"200": {
+				Extensions: map[string]*structpb.Value{
+					"x-resp-id": {Kind: &structpb.Value_StringValue{StringValue: "resp1000"}},
+				},
+			},
+		},
+		Extensions: map[string]*structpb.Value{
+			"x-op-foo": {Kind: &structpb.Value_StringValue{StringValue: "baz"}},
+		},
+	}
+	verifyTemplateExtensions := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File,
+		opts *openapiconfigv3.OpenAPIOptions,
+	) {
+		if err := AddErrorDefs(reg); err != nil {
+			t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+			return
+		}
+		fileCL := crossLinkFixture(file)
+		err := reg.Load(reqFromFile(fileCL))
+		if err != nil {
+			t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+			return
+		}
+		if opts != nil {
+			if err := reg.RegisterOpenAPIOptionsv3(opts); err != nil {
+				t.Fatalf("failed to register OpenAPI annotations: %s", err)
+			}
+		}
+		result, err := applyTemplate(param{File: fileCL, reg: reg})
+		if err != nil {
+			t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+			return
+		}
+		if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+		if got, want := len(result.extensions), 2; got != want {
+			t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want)
+		}
+		if got, want := result.extensions[0].key, "x-bar"; got != want {
+			t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want)
+		}
+		if got, want := result.extensions[1].key, "x-foo"; got != want {
+			t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want)
+		}
+		{
+			var got []string
+			err = marshaler.Unmarshal(result.extensions[0].value, &got)
+			if err != nil {
+				t.Fatalf("marshaler.Unmarshal failed: %v", err)
+			}
+			want := []string{"baz"}
+			if diff := cmp.Diff(got, want); diff != "" {
+				t.Error(diff)
+			}
+		}
+		{
+			var got string
+			err = marshaler.Unmarshal(result.extensions[1].value, &got)
+			if err != nil {
+				t.Fatalf("marshaler.Unmarshal failed: %v", err)
+			}
+			want := "bar"
+			if diff := cmp.Diff(got, want); diff != "" {
+				t.Error(diff)
+			}
+		}
+
+		var scheme openapiSecuritySchemeObject
+		for _, v := range result.SecurityDefinitions {
+			scheme = v
+		}
+		if want, is, name := []extension{
+			{key: "x-security-baz", value: json.RawMessage("true")},
+		}, scheme.extensions, "SecurityScheme.Extensions"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+
+		if want, is, name := []extension{
+			{key: "x-info-extension", value: json.RawMessage("\"bar\"")},
+		}, result.Info.extensions, "Info.Extensions"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+
+		var operation *openapiOperationObject
+		var response openapiResponseObject
+		for _, v := range result.Paths {
+			operation = v.PathItemObject.Get
+			response = v.PathItemObject.Get.Responses["200"]
+		}
+		if want, is, name := []extension{
+			{key: "x-op-foo", value: json.RawMessage("\"baz\"")},
+		}, operation.extensions, "operation.Extensions"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+		if want, is, name := []extension{
+			{key: "x-resp-id", value: json.RawMessage("\"resp1000\"")},
+		}, response.extensions, "response.Extensions"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+
+		if len(result.Tags) == 0 {
+			t.Errorf("No tags found in result")
+			return
+		}
+		tag := result.Tags[0]
+		if want, is, name := []extension{
+			{key: "x-traitTag", value: json.RawMessage("true")},
+		}, tag.extensions, "Tags[0].Extensions"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+	}
+	t.Run("verify template options set via proto options", func(t *testing.T) {
+		file := newFile()
+		proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger)
+		proto.SetExtension(proto.Message(file.Services[0].Methods[0].Options), openapi_options.E_Openapiv2Operation, &openapiOperation)
+		reg := descriptor.NewRegistry()
+		verifyTemplateExtensions(t, reg, file, nil)
+	})
+	t.Run("verify template options set via annotations", func(t *testing.T) {
+		file := newFile()
+		opts := &openapiconfigv3.OpenAPIOptions{
+			File: []*openapiconfigv3.OpenAPIFileOption{
+				{
+					File:   "example.proto",
+					Option: &swagger,
+				},
+			},
+			Method: []*openapiconfigv3.OpenAPIMethodOption{
+				{
+					Method: "example.ExampleService.Example",
+					Option: &openapiOperation,
+				},
+			},
+		}
+		reg := descriptor.NewRegistry()
+		verifyTemplateExtensions(t, reg, file, opts)
+	})
+}
+
+func TestApplyTemplateHeaders(t *testing.T) {
+	newFile := func() *descriptor.File {
+		msgdesc := &descriptorpb.DescriptorProto{
+			Name: proto.String("ExampleMessage"),
+		}
+		meth := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String("Example"),
+			InputType:  proto.String("ExampleMessage"),
+			OutputType: proto.String("ExampleMessage"),
+			Options:    &descriptorpb.MethodOptions{},
+		}
+		svc := &descriptorpb.ServiceDescriptorProto{
+			Name:   proto.String("ExampleService"),
+			Method: []*descriptorpb.MethodDescriptorProto{meth},
+		}
+		msg := &descriptor.Message{
+			DescriptorProto: msgdesc,
+		}
+		return &descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: []*descriptor.Message{msg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: meth,
+							RequestType:           msg,
+							ResponseType:          msg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: "GET",
+									Body:       &descriptor.Body{FieldPath: nil},
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+	}
+	openapiOperation := openapi_options.Operation{
+		Responses: map[string]*openapi_options.Response{
+			"200": {
+				Description: "Testing Headers",
+				Headers: map[string]*openapi_options.Header{
+					"string": {
+						Description: "string header description",
+						Type:        "string",
+						Format:      "uuid",
+						Pattern:     "",
+					},
+					"boolean": {
+						Description: "boolean header description",
+						Type:        "boolean",
+						Default:     "true",
+						Pattern:     "^true|false$",
+					},
+					"integer": {
+						Description: "integer header description",
+						Type:        "integer",
+						Default:     "0",
+						Pattern:     "^[0-9]$",
+					},
+					"number": {
+						Description: "number header description",
+						Type:        "number",
+						Default:     "1.2",
+						Pattern:     "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$",
+					},
+				},
+			},
+		},
+	}
+	verifyTemplateHeaders := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File,
+		opts *openapiconfigv3.OpenAPIOptions,
+	) {
+		if err := AddErrorDefs(reg); err != nil {
+			t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+			return
+		}
+		fileCL := crossLinkFixture(file)
+		err := reg.Load(reqFromFile(fileCL))
+		if err != nil {
+			t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+			return
+		}
+		if opts != nil {
+			if err := reg.RegisterOpenAPIOptionsv3(opts); err != nil {
+				t.Fatalf("failed to register OpenAPI annotations: %s", err)
+			}
+		}
+		result, err := applyTemplate(param{File: fileCL, reg: reg})
+		if err != nil {
+			t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+			return
+		}
+		if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+
+		var response openapiResponseObject
+		for _, v := range result.Paths {
+			response = v.PathItemObject.Get.Responses["200"]
+		}
+		if want, is, name := []openapiHeadersObject{
+			{
+				"String": openapiHeaderObject{
+					Description: "string header description",
+					Type:        "string",
+					Format:      "uuid",
+					Pattern:     "",
+				},
+				"Boolean": openapiHeaderObject{
+					Description: "boolean header description",
+					Type:        "boolean",
+					Default:     RawExample("true"),
+					Pattern:     "^true|false$",
+				},
+				"Integer": openapiHeaderObject{
+					Description: "integer header description",
+					Type:        "integer",
+					Default:     RawExample("0"),
+					Pattern:     "^[0-9]$",
+				},
+				"Number": openapiHeaderObject{
+					Description: "number header description",
+					Type:        "number",
+					Default:     RawExample("1.2"),
+					Pattern:     "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$",
+				},
+			},
+		}[0], response.Headers, "response.Headers"; !reflect.DeepEqual(is, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+		}
+	}
+	t.Run("verify template options set via proto options", func(t *testing.T) {
+		file := newFile()
+		proto.SetExtension(proto.Message(file.Services[0].Methods[0].Options), openapi_options.E_Openapiv2Operation, &openapiOperation)
+		reg := descriptor.NewRegistry()
+		verifyTemplateHeaders(t, reg, file, nil)
+	})
+}
+
+func TestValidateHeaderType(t *testing.T) {
+	type test struct {
+		Type          string
+		Format        string
+		expectedError error
+	}
+	tests := []test{
+		{
+			"string",
+			"date-time",
+			nil,
+		},
+		{
+			"boolean",
+			"",
+			nil,
+		},
+		{
+			"integer",
+			"uint",
+			nil,
+		},
+		{
+			"integer",
+			"uint8",
+			nil,
+		},
+		{
+			"integer",
+			"uint16",
+			nil,
+		},
+		{
+			"integer",
+			"uint32",
+			nil,
+		},
+		{
+			"integer",
+			"uint64",
+			nil,
+		},
+		{
+			"integer",
+			"int",
+			nil,
+		},
+		{
+			"integer",
+			"int8",
+			nil,
+		},
+		{
+			"integer",
+			"int16",
+			nil,
+		},
+		{
+			"integer",
+			"int32",
+			nil,
+		},
+		{
+			"integer",
+			"int64",
+			nil,
+		},
+		{
+			"integer",
+			"float64",
+			errors.New("the provided format \"float64\" is not a valid extension of the type \"integer\""),
+		},
+		{
+			"integer",
+			"uuid",
+			errors.New("the provided format \"uuid\" is not a valid extension of the type \"integer\""),
+		},
+		{
+			"number",
+			"uint",
+			nil,
+		},
+		{
+			"number",
+			"uint8",
+			nil,
+		},
+		{
+			"number",
+			"uint16",
+			nil,
+		},
+		{
+			"number",
+			"uint32",
+			nil,
+		},
+		{
+			"number",
+			"uint64",
+			nil,
+		},
+		{
+			"number",
+			"int",
+			nil,
+		},
+		{
+			"number",
+			"int8",
+			nil,
+		},
+		{
+			"number",
+			"int16",
+			nil,
+		},
+		{
+			"number",
+			"int32",
+			nil,
+		},
+		{
+			"number",
+			"int64",
+			nil,
+		},
+		{
+			"number",
+			"float",
+			nil,
+		},
+		{
+			"number",
+			"float32",
+			nil,
+		},
+		{
+			"number",
+			"float64",
+			nil,
+		},
+		{
+			"number",
+			"complex64",
+			nil,
+		},
+		{
+			"number",
+			"complex128",
+			nil,
+		},
+		{
+			"number",
+			"double",
+			nil,
+		},
+		{
+			"number",
+			"byte",
+			nil,
+		},
+		{
+			"number",
+			"rune",
+			nil,
+		},
+		{
+			"number",
+			"uintptr",
+			nil,
+		},
+		{
+			"number",
+			"date",
+			errors.New("the provided format \"date\" is not a valid extension of the type \"number\""),
+		},
+		{
+			"array",
+			"",
+			errors.New("the provided header type \"array\" is not supported"),
+		},
+		{
+			"foo",
+			"",
+			errors.New("the provided header type \"foo\" is not supported"),
+		},
+	}
+	for _, v := range tests {
+		err := validateHeaderTypeAndFormat(v.Type, v.Format)
+
+		if v.expectedError == nil {
+			if err != nil {
+				t.Errorf("unexpected error %v", err)
+			}
+		} else {
+			if err == nil {
+				t.Fatal("expected header error not returned")
+			}
+			if err.Error() != v.expectedError.Error() {
+				t.Errorf("expected error malformed, expected %q, got %q", v.expectedError.Error(), err.Error())
+			}
+		}
+	}
+}
+
+func TestValidateDefaultValueType(t *testing.T) {
+	type test struct {
+		Type          string
+		Value         string
+		Format        string
+		expectedError error
+	}
+	tests := []test{
+		{
+			"string",
+			`"string"`,
+			"",
+			nil,
+		},
+		{
+			"string",
+			"\"2012-11-01T22:08:41+00:00\"",
+			"date-time",
+			nil,
+		},
+		{
+			"string",
+			"\"2012-11-01\"",
+			"date",
+			nil,
+		},
+		{
+			"string",
+			"0",
+			"",
+			errors.New("the provided default value \"0\" does not match provider type \"string\", or is not properly quoted with escaped quotations"),
+		},
+		{
+			"string",
+			"false",
+			"",
+			errors.New("the provided default value \"false\" does not match provider type \"string\", or is not properly quoted with escaped quotations"),
+		},
+		{
+			"boolean",
+			"true",
+			"",
+			nil,
+		},
+		{
+			"boolean",
+			"0",
+			"",
+			errors.New("the provided default value \"0\" does not match provider type \"boolean\""),
+		},
+		{
+			"boolean",
+			`"string"`,
+			"",
+			errors.New("the provided default value \"\\\"string\\\"\" does not match provider type \"boolean\""),
+		},
+		{
+			"number",
+			"1.2",
+			"",
+			nil,
+		},
+		{
+			"number",
+			"123",
+			"",
+			nil,
+		},
+		{
+			"number",
+			"nan",
+			"",
+			errors.New("the provided number \"nan\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"NaN",
+			"",
+			errors.New("the provided number \"NaN\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"-459.67",
+			"",
+			nil,
+		},
+		{
+			"number",
+			"inf",
+			"",
+			errors.New("the provided number \"inf\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"infinity",
+			"",
+			errors.New("the provided number \"infinity\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"Inf",
+			"",
+			errors.New("the provided number \"Inf\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"Infinity",
+			"",
+			errors.New("the provided number \"Infinity\" is not a valid JSON number"),
+		},
+		{
+			"number",
+			"false",
+			"",
+			errors.New("the provided default value \"false\" does not match provider type \"number\""),
+		},
+		{
+			"number",
+			`"string"`,
+			"",
+			errors.New("the provided default value \"\\\"string\\\"\" does not match provider type \"number\""),
+		},
+		{
+			"integer",
+			"2",
+			"",
+			nil,
+		},
+		{
+			"integer",
+			fmt.Sprint(math.MaxInt32),
+			"int32",
+			nil,
+		},
+		{
+			"integer",
+			fmt.Sprint(int64(math.MaxInt32) + 1),
+			"int32",
+			errors.New("the provided default value \"2147483648\" does not match provided format \"int32\""),
+		},
+		{
+			"integer",
+			fmt.Sprint(int64(math.MaxInt64)),
+			"int64",
+			nil,
+		},
+		{
+			"integer",
+			"9223372036854775808",
+			"int64",
+			errors.New("the provided default value \"9223372036854775808\" does not match provided format \"int64\""),
+		},
+		{
+			"integer",
+			"18446744073709551615",
+			"uint64",
+			nil,
+		},
+		{
+			"integer",
+			"false",
+			"",
+			errors.New("the provided default value \"false\" does not match provided type \"integer\""),
+		},
+		{
+			"integer",
+			"1.2",
+			"",
+			errors.New("the provided default value \"1.2\" does not match provided type \"integer\""),
+		},
+		{
+			"integer",
+			`"string"`,
+			"",
+			errors.New("the provided default value \"\\\"string\\\"\" does not match provided type \"integer\""),
+		},
+	}
+	for _, v := range tests {
+		err := validateDefaultValueTypeAndFormat(v.Type, v.Value, v.Format)
+
+		if v.expectedError == nil {
+			if err != nil {
+				t.Errorf("unexpected error '%v'", err)
+			}
+		} else {
+			if err == nil {
+				t.Error("expected update error not returned")
+			}
+			if err.Error() != v.expectedError.Error() {
+				t.Errorf("expected error malformed, expected %q, got %q", v.expectedError.Error(), err.Error())
+			}
+		}
+	}
+}
+
+func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("nested"),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String("NestedMessage"),
+				Number:   proto.Int32(1),
+			},
+		},
+	}
+	nesteddesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("NestedMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("int32"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("bool"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:            proto.String("Echo"),
+		InputType:       proto.String("ExampleMessage"),
+		OutputType:      proto.String("ExampleMessage"),
+		ClientStreaming: proto.Bool(false),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	meth.ServerStreaming = proto.Bool(false)
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	nested := &descriptor.Message{
+		DescriptorProto: nesteddesc,
+	}
+
+	nestedField := &descriptor.Field{
+		Message:              msg,
+		FieldDescriptorProto: msg.GetField()[0],
+	}
+	intField := &descriptor.Field{
+		Message:              nested,
+		FieldDescriptorProto: nested.GetField()[0],
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc, nesteddesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg, nested},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo", // TODO(achew): Figure out what this should really be
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name:   "nested",
+												Target: nestedField,
+											},
+											{
+												Name:   "int32",
+												Target: intField,
+											},
+										}),
+										Target: intField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+										{
+											Name:   "nested",
+											Target: nestedField,
+										},
+									}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fmt.Fprintln(os.Stderr, "fd", file.FileDescriptorProto)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+	})
+	if err != nil {
+		t.Fatalf("failed to load code generator request: %v", err)
+	}
+	fmt.Fprintln(os.Stderr, "AllFQMNs", reg.GetAllFQMNs())
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	if want, got := "2.0", result.Swagger; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).Swagger = %s want to be %s", file, got, want)
+	}
+	if want, got := "", result.BasePath; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).BasePath = %s want to be %s", file, got, want)
+	}
+	if want, got := ([]string)(nil), result.Schemes; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).Schemes = %s want to be %s", file, got, want)
+	}
+	if want, got := []string{"application/json"}, result.Consumes; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).Consumes = %s want to be %s", file, got, want)
+	}
+	if want, got := []string{"application/json"}, result.Produces; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).Produces = %s want to be %s", file, got, want)
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateRequestWithClientStreaming(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("nested"),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String("NestedMessage"),
+				Number:   proto.Int32(1),
+			},
+		},
+	}
+	nesteddesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("NestedMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("int32"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("bool"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:            proto.String("Echo"),
+		InputType:       proto.String("ExampleMessage"),
+		OutputType:      proto.String("ExampleMessage"),
+		ClientStreaming: proto.Bool(true),
+		ServerStreaming: proto.Bool(true),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	nested := &descriptor.Message{
+		DescriptorProto: nesteddesc,
+	}
+
+	nestedField := &descriptor.Field{
+		Message:              msg,
+		FieldDescriptorProto: msg.GetField()[0],
+	}
+	intField := &descriptor.Field{
+		Message:              nested,
+		FieldDescriptorProto: nested.GetField()[0],
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc, nesteddesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg, nested},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo", // TODO(achew): Figure out what this should really be
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name:   "nested",
+												Target: nestedField,
+											},
+											{
+												Name:   "int32",
+												Target: intField,
+											},
+										}),
+										Target: intField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+										{
+											Name:   "nested",
+											Target: nestedField,
+										},
+									}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+	})
+	if err != nil {
+		t.Fatalf("failed to load code generator request: %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	// Only ExampleMessage must be present, not NestedMessage
+	if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+	}
+	if _, ok := result.getPathItemObject("/v1/echo").Post.Responses["200"]; !ok {
+		t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.getPathItemObject("/v1/echo").Post.Responses["200"]`)
+	} else {
+		if want, got, name := "A successful response.(streaming responses)", result.getPathItemObject("/v1/echo").Post.Responses["200"].Description, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		streamExampleExampleMessage := result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema
+		if want, got, name := "object", streamExampleExampleMessage.Type, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties)
+		if want, got, name := 2, len(streamExampleExampleMessageProperties), `len(StreamDefinitions["exampleExampleMessage"].Properties)`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+		} else {
+			resultProperty := streamExampleExampleMessageProperties[0]
+			if want, got, name := "result", resultProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+			result := resultProperty.Value.(openapiSchemaObject)
+			if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+			errorProperty := streamExampleExampleMessageProperties[1]
+			if want, got, name := "error", errorProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+			err := errorProperty.Value.(openapiSchemaObject)
+			if want, got, name := "#/definitions/rpcStatus", err.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+		}
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateRequestWithServerStreamingAndNoStandardErrors(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("nested"),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String("NestedMessage"),
+				Number:   proto.Int32(1),
+			},
+		},
+	}
+	nesteddesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("NestedMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("int32"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("bool"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:            proto.String("Echo"),
+		InputType:       proto.String("ExampleMessage"),
+		OutputType:      proto.String("ExampleMessage"),
+		ClientStreaming: proto.Bool(false),
+		ServerStreaming: proto.Bool(true),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+	nested := &descriptor.Message{
+		DescriptorProto: nesteddesc,
+	}
+
+	nestedField := &descriptor.Field{
+		Message:              msg,
+		FieldDescriptorProto: msg.GetField()[0],
+	}
+	intField := &descriptor.Field{
+		Message:              nested,
+		FieldDescriptorProto: nested.GetField()[0],
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc, nesteddesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg, nested},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name:   "nested",
+												Target: nestedField,
+											},
+											{
+												Name:   "int32",
+												Target: intField,
+											},
+										}),
+										Target: intField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+										{
+											Name:   "nested",
+											Target: nestedField,
+										},
+									}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+	})
+	if err != nil {
+		t.Fatalf("failed to load code generator request: %v", err)
+	}
+	reg.SetDisableDefaultErrors(true)
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	// Should only include the message, no status or any type
+	if want, got, name := 1, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+	}
+	if _, ok := result.getPathItemObject("/v1/echo").Post.Responses["200"]; !ok {
+		t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.getPathItemObject("/v1/echo").Post.Responses["200"]`)
+	} else {
+		if want, got, name := "A successful response.(streaming responses)", result.getPathItemObject("/v1/echo").Post.Responses["200"].Description, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		streamExampleExampleMessage := result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema
+		if want, got, name := "object", streamExampleExampleMessage.Type, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties)
+		if want, got, name := 1, len(streamExampleExampleMessageProperties), `len(StreamDefinitions["exampleExampleMessage"].Properties)`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+		} else {
+			resultProperty := streamExampleExampleMessageProperties[0]
+			if want, got, name := "result", resultProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+			result := resultProperty.Value.(openapiSchemaObject)
+			if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+			}
+		}
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) {
+	reqdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("string"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	respdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("EmptyMessage"),
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:            proto.String("Example"),
+		InputType:       proto.String("ExampleMessage"),
+		OutputType:      proto.String("EmptyMessage"),
+		ClientStreaming: proto.Bool(false),
+		ServerStreaming: proto.Bool(false),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	req := &descriptor.Message{
+		DescriptorProto: reqdesc,
+	}
+	resp := &descriptor.Message{
+		DescriptorProto: respdesc,
+	}
+	stringField := &descriptor.Field{
+		Message:              req,
+		FieldDescriptorProto: req.GetField()[0],
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqdesc, respdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{req, resp},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           req,
+						ResponseType:          resp,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/example",
+								},
+							},
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/example/{string}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name:   "string",
+												Target: stringField,
+											},
+										}),
+										Target: stringField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+										{
+											Name:   "string",
+											Target: stringField,
+										},
+									}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+	})
+	if err != nil {
+		t.Fatalf("failed to load code generator request: %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	// Only EmptyMessage must be present, not ExampleMessage (plus error status)
+	if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateRequestWithBodyQueryParameters(t *testing.T) {
+	bookDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("Book"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("name"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("id"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	createDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("CreateBookRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("parent"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("book"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+			{
+				Name:   proto.String("book_id"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(3),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("CreateBook"),
+		InputType:  proto.String("CreateBookRequest"),
+		OutputType: proto.String("Book"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("BookService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	bookMsg := &descriptor.Message{
+		DescriptorProto: bookDesc,
+	}
+	createMsg := &descriptor.Message{
+		DescriptorProto: createDesc,
+	}
+
+	parentField := &descriptor.Field{
+		Message:              createMsg,
+		FieldDescriptorProto: createMsg.GetField()[0],
+	}
+	bookField := &descriptor.Field{
+		Message:              createMsg,
+		FieldMessage:         bookMsg,
+		FieldDescriptorProto: createMsg.GetField()[1],
+	}
+	bookIDField := &descriptor.Field{
+		Message:              createMsg,
+		FieldDescriptorProto: createMsg.GetField()[2],
+	}
+
+	createMsg.Fields = []*descriptor.Field{parentField, bookField, bookIDField}
+
+	newFile := func() descriptor.File {
+		return descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("book.proto"),
+				MessageType:    []*descriptorpb.DescriptorProto{bookDesc, createDesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/book.pb",
+				Name: "book_pb",
+			},
+			Messages: []*descriptor.Message{bookMsg, createMsg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: meth,
+							RequestType:           createMsg,
+							ResponseType:          bookMsg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: "POST",
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/{parent=publishers/*}/books",
+									},
+									PathParams: []descriptor.Parameter{
+										{
+											FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+												{
+													Name:   "parent",
+													Target: parentField,
+												},
+											}),
+											Target: parentField,
+										},
+									},
+									Body: &descriptor.Body{
+										FieldPath: []descriptor.FieldPathComponent{
+											{
+												Name:   "book",
+												Target: bookField,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+	}
+	type args struct {
+		file descriptor.File
+	}
+	type paramOut struct {
+		Name     string
+		In       string
+		Required bool
+	}
+	tests := []struct {
+		name string
+		args args
+		want []paramOut
+	}{
+		{
+			name: "book_in_body",
+			args: args{file: newFile()},
+			want: []paramOut{
+				{"parent", "path", true},
+				{"book", "body", true},
+				{"book_id", "query", false},
+			},
+		},
+		{
+			name: "book_in_query",
+			args: args{file: func() descriptor.File {
+				f := newFile()
+				f.Services[0].Methods[0].Bindings[0].Body = nil
+				return f
+			}()},
+			want: []paramOut{
+				{"parent", "path", true},
+				{"book", "query", false},
+				{"book_id", "query", false},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			reg := descriptor.NewRegistry()
+			if err := AddErrorDefs(reg); err != nil {
+				t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+				return
+			}
+			err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{tt.args.file.FileDescriptorProto}})
+			if err != nil {
+				t.Errorf("Registry.Load() failed with %v; want success", err)
+				return
+			}
+			result, err := applyTemplate(param{File: crossLinkFixture(&tt.args.file), reg: reg})
+			if err != nil {
+				t.Errorf("applyTemplate(%#v) failed with %v; want success", tt.args.file, err)
+				return
+			}
+
+			if _, ok := result.getPathItemObject("/v1/{parent}/books").Post.Responses["200"]; !ok {
+				t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", tt.args.file, `result.getPathItemObject("/v1/{parent}/books").Post.Responses["200"]`)
+			} else {
+
+				if want, got, name := 3, len(result.getPathItemObject("/v1/{parent}/books").Post.Parameters), `len(result.getPathItemObject("/v1/{parent}/books").Post.Parameters)`; !reflect.DeepEqual(got, want) {
+					t.Errorf("applyTemplate(%#v).%s = %d want to be %d", tt.args.file, name, got, want)
+				}
+
+				for i, want := range tt.want {
+					p := result.getPathItemObject("/v1/{parent}/books").Post.Parameters[i]
+					if got, name := (paramOut{p.Name, p.In, p.Required}), `result.getPathItemObject("/v1/{parent}/books").Post.Parameters[0]`; !reflect.DeepEqual(got, want) {
+						t.Errorf("applyTemplate(%#v).%s = %v want to be %v", tt.args.file, name, got, want)
+					}
+				}
+
+			}
+
+			// If there was a failure, print out the input and the json result for debugging.
+			if t.Failed() {
+				t.Errorf("had: %s", tt.args.file)
+				t.Errorf("got: %s", fmt.Sprint(result))
+			}
+		})
+	}
+}
+
+func TestApplyTemplateWithRequestAndBodyParameters(t *testing.T) {
+	bookDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("Book"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("name"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("id"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	createDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("CreateBookRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("parent"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("book"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+			{
+				Name:   proto.String("book_id"),
+				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(3),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("CreateBook"),
+		InputType:  proto.String("CreateBookRequest"),
+		OutputType: proto.String("Book"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("BookService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	bookMsg := &descriptor.Message{
+		DescriptorProto: bookDesc,
+	}
+	createMsg := &descriptor.Message{
+		DescriptorProto: createDesc,
+	}
+
+	parentField := &descriptor.Field{
+		Message:              createMsg,
+		FieldDescriptorProto: createMsg.GetField()[0],
+	}
+	bookField := &descriptor.Field{
+		Message:              createMsg,
+		FieldMessage:         bookMsg,
+		FieldDescriptorProto: createMsg.GetField()[1],
+	}
+	bookIDField := &descriptor.Field{
+		Message:              createMsg,
+		FieldDescriptorProto: createMsg.GetField()[2],
+	}
+
+	createMsg.Fields = []*descriptor.Field{parentField, bookField, bookIDField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("book.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{bookDesc, createDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/book.pb",
+			Name: "book_pb",
+		},
+		Messages: []*descriptor.Message{bookMsg, createMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           createMsg,
+						ResponseType:          bookMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{parent=publishers/*}/books",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name:   "parent",
+												Target: parentField,
+											},
+										}),
+										Target: parentField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: []descriptor.FieldPathComponent{},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(reqFromFile(fileCL))
+	if err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+		return
+	}
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := ([]string)(nil), result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+
+	if want, is, name := 1, len(result.Paths), "len(result.Paths)"; !reflect.DeepEqual(is, want) {
+		t.Errorf("%s = %d want to be %d", name, want, is)
+	}
+	if want, is, name := 4, len(result.Paths[0].PathItemObject.Post.Parameters), "len(result.Paths[0].PathItemObject.Post.Parameters)"; !reflect.DeepEqual(is, want) {
+		t.Errorf("%s = %d want to be %d", name, want, is)
+	}
+	if want, is, name := "#/definitions/BookServiceCreateBookBody", result.Paths[0].PathItemObject.Post.Parameters[1].Schema.schemaCore.Ref, "result.Paths[0].PathItemObject.Post.Parameters[1].Schema.schemaCore.Ref"; !reflect.DeepEqual(is, want) {
+		t.Errorf("%s = %s want to be %s", name, want, is)
+	}
+
+	_, found := result.Definitions["BookServiceCreateBookBody"]
+	if !found {
+		t.Error("expecting definition to contain BookServiceCreateBookBody")
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+// TestApplyTemplateProtobufAny tests that the protobufAny definition is correctly rendered with the @type field and
+// allowing additional properties.
+func TestApplyTemplateProtobufAny(t *testing.T) {
+	// checkProtobufAnyFormat verifies the only property should be @type and additional properties are allowed
+	checkProtobufAnyFormat := func(t *testing.T, protobufAny openapiSchemaObject) {
+		anyPropsJSON, err := protobufAny.Properties.MarshalJSON()
+		if err != nil {
+			t.Errorf("protobufAny.Properties.MarshalJSON(), got error = %v", err)
+		}
+		var anyPropsMap map[string]interface{}
+		if err := json.Unmarshal(anyPropsJSON, &anyPropsMap); err != nil {
+			t.Errorf("json.Unmarshal(), got error = %v", err)
+		}
+
+		// @type should exist
+		if _, ok := anyPropsMap["@type"]; !ok {
+			t.Errorf("protobufAny.Properties missing key, \"@type\". got = %#v", anyPropsMap)
+		}
+
+		// and @type should be the only property
+		if len(anyPropsMap) > 1 {
+			t.Errorf("len(protobufAny.Properties) = %v, want = %v", len(anyPropsMap), 1)
+		}
+
+		// protobufAny should have additionalProperties allowed
+		if protobufAny.AdditionalProperties == nil {
+			t.Errorf("protobufAny.AdditionalProperties = nil, want not-nil")
+		}
+	}
+
+	type args struct {
+		regConfig      func(registry *descriptor.Registry)
+		msgContainsAny bool
+	}
+	tests := []struct {
+		name               string
+		args               args
+		wantNumDefinitions int
+	}{
+		{
+			// our proto schema doesn't directly use protobufAny, but it is implicitly used by rpcStatus being
+			// automatically rendered
+			name: "default_protobufAny_from_rpcStatus",
+			args: args{
+				msgContainsAny: false,
+			},
+			wantNumDefinitions: 4,
+		},
+		{
+			// we have a protobufAny in a message, it should contain a ref inside the custom message
+			name: "protobufAny_referenced_in_message",
+			args: args{
+				msgContainsAny: true,
+			},
+			wantNumDefinitions: 4,
+		},
+		{
+			// we have a protobufAny in a message but with automatic rendering of rpcStatus disabled
+			name: "protobufAny_referenced_in_message_with_default_errors_disabled",
+			args: args{
+				msgContainsAny: true,
+				regConfig: func(reg *descriptor.Registry) {
+					reg.SetDisableDefaultErrors(true)
+				},
+			},
+			wantNumDefinitions: 3,
+		},
+		{
+			// we have a protobufAny in a message but with automatic rendering of responses disabled
+			name: "protobufAny_referenced_in_message_with_default_responses_disabled",
+			args: args{
+				msgContainsAny: true,
+				regConfig: func(reg *descriptor.Registry) {
+					reg.SetDisableDefaultResponses(true)
+				},
+			},
+			wantNumDefinitions: 4,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			reqdesc := &descriptorpb.DescriptorProto{
+				Name: proto.String("ExampleMessage"),
+				Field: []*descriptorpb.FieldDescriptorProto{
+					{
+						Name:   proto.String("name"),
+						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+						Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+						Number: proto.Int32(1),
+					},
+				},
+			}
+			respdesc := &descriptorpb.DescriptorProto{
+				Name: proto.String("EmptyMessage"),
+			}
+			meth := &descriptorpb.MethodDescriptorProto{
+				Name:            proto.String("Example"),
+				InputType:       proto.String("ExampleMessage"),
+				OutputType:      proto.String("EmptyMessage"),
+				ClientStreaming: proto.Bool(false),
+				ServerStreaming: proto.Bool(false),
+			}
+			svc := &descriptorpb.ServiceDescriptorProto{
+				Name:   proto.String("ExampleService"),
+				Method: []*descriptorpb.MethodDescriptorProto{meth},
+			}
+
+			req := &descriptor.Message{
+				DescriptorProto: reqdesc,
+			}
+			resp := &descriptor.Message{
+				DescriptorProto: respdesc,
+			}
+			file := descriptor.File{
+				FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("example.proto"),
+					Package:        proto.String("example"),
+					MessageType:    []*descriptorpb.DescriptorProto{reqdesc, respdesc},
+					Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+					},
+				},
+				GoPkg: descriptor.GoPackage{
+					Path: "example.com/path/to/example/example.pb",
+					Name: "example_pb",
+				},
+				Messages: []*descriptor.Message{req, resp},
+				Services: []*descriptor.Service{
+					{
+						ServiceDescriptorProto: svc,
+						Methods: []*descriptor.Method{
+							{
+								MethodDescriptorProto: meth,
+								RequestType:           req,
+								ResponseType:          resp,
+							},
+						},
+					},
+				},
+			}
+
+			reg := descriptor.NewRegistry()
+			reg.SetGenerateUnboundMethods(true)
+
+			if tt.args.regConfig != nil {
+				tt.args.regConfig(reg)
+			}
+
+			if err := AddErrorDefs(reg); err != nil {
+				t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+				return
+			}
+
+			protoFiles := []*descriptorpb.FileDescriptorProto{
+				file.FileDescriptorProto,
+			}
+
+			if tt.args.msgContainsAny {
+				// add an Any field to the request message
+				reqdesc.Field = append(reqdesc.Field, &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("any_value"),
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					TypeName: proto.String(".google.protobuf.Any"),
+					Number:   proto.Int32(2),
+				})
+
+				// update the dependencies to import it
+				file.Dependency = append(file.Dependency, "google/protobuf/any.proto")
+
+				anyDescriptorProto := protodesc.ToFileDescriptorProto((&anypb.Any{}).ProtoReflect().Descriptor().ParentFile())
+				anyDescriptorProto.SourceCodeInfo = &descriptorpb.SourceCodeInfo{}
+
+				// prepend the anyDescriptorProto to the protoFiles slice so that the dependency can be resolved
+				protoFiles = append(append(make([]*descriptorpb.FileDescriptorProto, 0, len(protoFiles)+1), anyDescriptorProto), protoFiles[0:]...)
+			}
+
+			err := reg.Load(&pluginpb.CodeGeneratorRequest{
+				ProtoFile:      protoFiles,
+				FileToGenerate: []string{file.GetName()},
+			})
+			if err != nil {
+				t.Fatalf("failed to load code generator request: %v", err)
+			}
+
+			target, err := reg.LookupFile(file.GetName())
+			if err != nil {
+				t.Fatalf("failed to lookup file from reg: %v", err)
+			}
+			result, err := applyTemplate(param{File: crossLinkFixture(target), reg: reg})
+			if err != nil {
+				t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+				return
+			}
+
+			if want, got, name := tt.wantNumDefinitions, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
+				t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+			}
+
+			protobufAny, ok := result.Definitions["protobufAny"]
+			if !ok {
+				t.Error("expecting Definitions to contain protobufAny")
+			}
+
+			checkProtobufAnyFormat(t, protobufAny)
+
+			// If there was a failure, print out the input and the json result for debugging.
+			if t.Failed() {
+				t.Errorf("had: %s", file)
+				resultJSON, _ := json.Marshal(result)
+				t.Errorf("got: %s", resultJSON)
+			}
+		})
+	}
+}
+
+func generateFieldsForJSONReservedName() []*descriptor.Field {
+	fields := make([]*descriptor.Field, 0)
+	fieldName := "json_name"
+	fieldJSONName := "jsonNAME"
+	fieldDescriptor := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName}
+	field := &descriptor.Field{FieldDescriptorProto: &fieldDescriptor}
+	return append(fields, field)
+}
+
+func generateMsgsForJSONReservedName() []*descriptor.Message {
+	result := make([]*descriptor.Message, 0)
+	// The first message, its field is field_abc and its type is NewType
+	// NewType field_abc
+	fieldName := "field_abc"
+	fieldJSONName := "fieldAbc"
+	messageName1 := "message1"
+	messageType := "pkg.a.NewType"
+	pfd := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType}
+	result = append(result,
+		&descriptor.Message{
+			DescriptorProto: &descriptorpb.DescriptorProto{
+				Name: &messageName1, Field: []*descriptorpb.FieldDescriptorProto{&pfd},
+			},
+		})
+	// The second message, its name is NewName, its type is string
+	// message NewType {
+	//    string field_newName [json_name = RESERVEDJSONNAME]
+	// }
+	messageName := "NewType"
+	field := "field_newName"
+	fieldJSONName2 := "RESERVEDJSONNAME"
+	pfd2 := descriptorpb.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2}
+	result = append(result, &descriptor.Message{
+		DescriptorProto: &descriptorpb.DescriptorProto{
+			Name: &messageName, Field: []*descriptorpb.FieldDescriptorProto{&pfd2},
+		},
+	})
+	return result
+}
+
+func TestTemplateWithJsonCamelCase(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"/test/{test_id}", "/test/{testId}"},
+		{"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1Id}/test2/{test2Id}"},
+		{"/test1/{test1_id}/{test2_id}", "/test1/{test1Id}/{test2Id}"},
+		{"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1Id}/{test2Id}"},
+		{"/test1/{test1_id1_id2}", "/test1/{test1Id1Id2}"},
+		{"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1Id1Id2}/test2/{test2Id3Id4}"},
+		{"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1Id1Id2}/{test2Id3Id4}"},
+		{"test/{a}", "test/{a}"},
+		{"test/{ab}", "test/{ab}"},
+		{"test/{a_a}", "test/{aA}"},
+		{"test/{ab_c}", "test/{abC}"},
+		{"test/{json_name}", "test/{jsonNAME}"},
+		{"test/{field_abc.field_newName}", "test/{fieldAbc.RESERVEDJSONNAME}"},
+		{"/item/search:item/{item_no_query}", "/item/search:item/{itemNoQuery}"},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+}
+
+func TestTemplateWithoutJsonCamelCase(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"/test/{test_id}", "/test/{test_id}"},
+		{"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1_id}/test2/{test2_id}"},
+		{"/test1/{test1_id}/{test2_id}", "/test1/{test1_id}/{test2_id}"},
+		{"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1_id}/{test2_id}"},
+		{"/test1/{test1_id1_id2}", "/test1/{test1_id1_id2}"},
+		{"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1_id1_id2}/test2/{test2_id3_id4}"},
+		{"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1_id1_id2}/{test2_id3_id4}"},
+		{"test/{a}", "test/{a}"},
+		{"test/{ab}", "test/{ab}"},
+		{"test/{a_a}", "test/{a_a}"},
+		{"test/{json_name}", "test/{json_name}"},
+		{"test/{field_abc.field_newName}", "test/{field_abc.field_newName}"},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(false)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+}
+
+func TestTemplateToOpenAPIPath(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"/test", "/test"},
+		{"/{test}", "/{test}"},
+		{"/{test=prefix/*}", "/{test}"},
+		{"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"},
+		{"/{test1}/{test2}", "/{test1}/{test2}"},
+		{"/{test1}/{test2}/", "/{test1}/{test2}/"},
+		{"/{name=prefix/*}", "/{name}"},
+		{"/{name=prefix1/*/prefix2/*}", "/{name}"},
+		{"/{user.name=prefix/*}", "/{user.name}"},
+		{"/{user.name=prefix1/*/prefix2/*}", "/{user.name}"},
+		{"/{parent=prefix/*}/children", "/{parent}/children"},
+		{"/{name=prefix/*}:customMethod", "/{name}:customMethod"},
+		{"/{name=prefix1/*/prefix2/*}:customMethod", "/{name}:customMethod"},
+		{"/{user.name=prefix/*}:customMethod", "/{user.name}:customMethod"},
+		{"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name}:customMethod"},
+		{"/{parent=prefix/*}/children:customMethod", "/{parent}/children:customMethod"},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(false)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+	reg.SetUseJSONNamesForFields(true)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+}
+
+func getParameters(names []string) []descriptor.Parameter {
+	params := make([]descriptor.Parameter, 0)
+	for _, name := range names {
+		params = append(params, descriptor.Parameter{
+			Target: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name: proto.String(name),
+					Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				},
+				Message: &descriptor.Message{
+					File: &descriptor.File{
+						FileDescriptorProto: &descriptorpb.FileDescriptorProto{},
+					},
+					DescriptorProto: &descriptorpb.DescriptorProto{
+						Name: proto.String(""),
+					},
+				},
+				FieldMessage:      nil,
+				ForcePrefixedName: false,
+			},
+			FieldPath: []descriptor.FieldPathComponent{{
+				Name:   name,
+				Target: nil,
+			}},
+			Method: nil,
+		})
+	}
+	return params
+}
+
+func TestTemplateToOpenAPIPathExpandSlashed(t *testing.T) {
+	tests := []struct {
+		input              string
+		expected           string
+		pathParams         []descriptor.Parameter
+		expectedPathParams []string
+		useJSONNames       bool
+	}{
+		{"/v1/{name=projects/*/documents/*}:exportResults", "/v1/projects/{project}/documents/{document}:exportResults", getParameters([]string{"name"}), []string{"project", "document"}, true},
+		{"/test/{name=*}", "/test/{name}", getParameters([]string{"name"}), []string{"name"}, true},
+		{"/test/{name=*}/", "/test/{name}/", getParameters([]string{"name"}), []string{"name"}, true},
+		{"/test/{name=test_cases/*}/", "/test/test_cases/{testCase}/", getParameters([]string{"name"}), []string{"testCase"}, true},
+		{"/test/{name=test_cases/*}/", "/test/test_cases/{test_case}/", getParameters([]string{"name"}), []string{"test_case"}, false},
+		{"/test/{test_type.name=test_cases/*}/", "/test/test_cases/{testCase}/", getParameters([]string{"test_type.name"}), []string{"testCase"}, true},
+		{"/test/{test_type.name=test_cases/*}/", "/test/test_cases/{test_case}/", getParameters([]string{"test_type.name"}), []string{"test_case"}, false},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetExpandSlashedPathPatterns(true)
+	for _, data := range tests {
+		reg.SetUseJSONNamesForFields(data.useJSONNames)
+		actualParts, actualParams := templateToExpandedPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), data.pathParams)
+		if data.expected != actualParts {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actualParts)
+		}
+		pathParamsNames := make([]string, 0)
+		for _, param := range actualParams {
+			pathParamsNames = append(pathParamsNames, param.FieldPath[0].Name)
+		}
+		if !reflect.DeepEqual(data.expectedPathParams, pathParamsNames) {
+			t.Errorf("Expected mutated path params in templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expectedPathParams, data.pathParams)
+		}
+	}
+}
+
+func TestExpandedPathParametersStringType(t *testing.T) {
+	tests := []struct {
+		input string
+	}{
+		{"/test/{name=test_cases/*}/"}, {"/v1/{name=projects/*/documents/*}:exportResults"},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetExpandSlashedPathPatterns(true)
+	expectedParamType := openapiSchemaObject{
+		schemaCore: schemaCore{
+			Type: "string",
+		},
+	}
+	for _, data := range tests {
+		_, actualParams := templateToExpandedPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), getParameters([]string{"name"}))
+		for _, param := range actualParams {
+			refs := make(refMap)
+			actualParamType := schemaOfField(param.Target, reg, refs)
+			if !reflect.DeepEqual(actualParamType, expectedParamType) {
+				t.Errorf("Expected all path parameters to be type of 'string', actual: %#+v", actualParamType)
+			}
+		}
+	}
+}
+
+func BenchmarkTemplateToOpenAPIPath(b *testing.B) {
+	const input = "/{user.name=prefix1/*/prefix2/*}:customMethod"
+
+	b.Run("with JSON names", func(b *testing.B) {
+		reg := descriptor.NewRegistry()
+		reg.SetUseJSONNamesForFields(false)
+
+		for i := 0; i < b.N; i++ {
+			_ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		}
+	})
+
+	b.Run("without JSON names", func(b *testing.B) {
+		reg := descriptor.NewRegistry()
+		reg.SetUseJSONNamesForFields(true)
+
+		for i := 0; i < b.N; i++ {
+			_ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		}
+	})
+}
+
+func TestResolveFullyQualifiedNameToOpenAPIName(t *testing.T) {
+	tests := []struct {
+		input          string
+		output         string
+		listOfFQMNs    []string
+		namingStrategy string
+	}{
+		{
+			".a.b.C",
+			"C",
+			[]string{
+				".a.b.C",
+			},
+			"legacy",
+		},
+		{
+			".a.b.C",
+			"C",
+			[]string{
+				".a.b.C",
+			},
+			"simple",
+		},
+		{
+			".a.b.C",
+			"abC",
+			[]string{
+				".a.C",
+				".a.b.C",
+			},
+			"legacy",
+		},
+		{
+			".a.b.C",
+			"b.C",
+			[]string{
+				".a.C",
+				".a.b.C",
+			},
+			"simple",
+		},
+		{
+			".a.b.C",
+			"abC",
+			[]string{
+				".C",
+				".a.C",
+				".a.b.C",
+			},
+			"legacy",
+		},
+		{
+			".a.b.C",
+			"b.C",
+			[]string{
+				".C",
+				".a.C",
+				".a.b.C",
+			},
+			"simple",
+		},
+		{
+			".a.b.C",
+			"a.b.C",
+			[]string{
+				".C",
+				".a.C",
+				".a.b.C",
+			},
+			"fqn",
+		},
+	}
+
+	for _, data := range tests {
+		names := resolveFullyQualifiedNameToOpenAPINames(data.listOfFQMNs, data.namingStrategy)
+		output := names[data.input]
+		if output != data.output {
+			t.Errorf("Expected fullyQualifiedNameToOpenAPIName(%v, %s) to be %s but got %s",
+				data.input, data.namingStrategy, data.output, output)
+		}
+	}
+}
+
+func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message, pathParamNames map[string]string) string {
+	return partsToOpenAPIPath(templateToParts(path, reg, fields, msgs), pathParamNames)
+}
+
+func templateToRegexpMap(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) map[string]string {
+	return partsToRegexpMap(templateToParts(path, reg, fields, msgs))
+}
+
+func templateToExpandedPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message, pathParams []descriptor.Parameter) (string, []descriptor.Parameter) {
+	pathParts, pathParams := expandPathPatterns(templateToParts(path, reg, fields, msgs), pathParams, reg)
+	return partsToOpenAPIPath(pathParts, make(map[string]string)), pathParams
+}
+
+func TestFQMNToRegexpMap(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected map[string]string
+	}{
+		{"/test", map[string]string{}},
+		{"/{test}", map[string]string{}},
+		{"/{test" + pathParamUniqueSuffixDeliminator + "1=prefix/*}", map[string]string{"test" + pathParamUniqueSuffixDeliminator + "1": "prefix/[^/]+"}},
+		{"/{test=prefix/that/has/multiple/parts/to/it/**}", map[string]string{"test": "prefix/that/has/multiple/parts/to/it/.+"}},
+		{"/{test1=organizations/*}/{test2=divisions/*}", map[string]string{
+			"test1": "organizations/[^/]+",
+			"test2": "divisions/[^/]+",
+		}},
+		{"/v1/{name=projects/*/topics/*}:delete", map[string]string{"name": "projects/[^/]+/topics/[^/]+"}},
+	}
+	reg := descriptor.NewRegistry()
+	for _, data := range tests {
+		actual := templateToRegexpMap(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName())
+		if !reflect.DeepEqual(data.expected, actual) {
+			t.Errorf("Expected partsToRegexpMap(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+}
+
+func TestFQMNtoOpenAPIName(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"/test", "/test"},
+		{"/{test}", "/{test}"},
+		{"/{test=prefix/*}", "/{test}"},
+		{"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"},
+		{"/{test1}/{test2}", "/{test1}/{test2}"},
+		{"/{test1}/{test2}/", "/{test1}/{test2}/"},
+		{"/v1/{name=tests/*}/tests", "/v1/{name}/tests"},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(false)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+	reg.SetUseJSONNamesForFields(true)
+	for _, data := range tests {
+		actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName(), make(map[string]string))
+		if data.expected != actual {
+			t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual)
+		}
+	}
+}
+
+func TestSchemaOfField(t *testing.T) {
+	type test struct {
+		field                 *descriptor.Field
+		refs                  refMap
+		expected              openapiSchemaObject
+		openAPIOptions        *openapiconfigv3.OpenAPIOptions
+		useJSONNamesForFields bool
+	}
+
+	jsonSchema := &openapi_options.JSONSchema{
+		Title:       "field title",
+		Description: "field description",
+	}
+	jsonSchemaWithOptions := &openapi_options.JSONSchema{
+		Title:            "field title",
+		Description:      "field description",
+		MultipleOf:       100,
+		Maximum:          101,
+		ExclusiveMaximum: true,
+		Minimum:          1,
+		ExclusiveMinimum: true,
+		MaxLength:        10,
+		MinLength:        3,
+		Pattern:          "[a-z]+",
+		MaxItems:         20,
+		MinItems:         2,
+		UniqueItems:      true,
+		MaxProperties:    33,
+		MinProperties:    22,
+		Required:         []string{"req"},
+		ReadOnly:         true,
+	}
+	jsonSchemaRequired := &openapi_options.JSONSchema{
+		Required: []string{"required_via_json_schema"},
+	}
+	jsonSchemaWithFormat := &openapi_options.JSONSchema{
+		Format: "uuid",
+	}
+
+	fieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, jsonSchema)
+
+	requiredField := []annotations.FieldBehavior{annotations.FieldBehavior_REQUIRED}
+	requiredFieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(requiredFieldOptions, annotations.E_FieldBehavior, requiredField)
+
+	outputOnlyField := []annotations.FieldBehavior{annotations.FieldBehavior_OUTPUT_ONLY}
+	outputOnlyOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(outputOnlyOptions, annotations.E_FieldBehavior, outputOnlyField)
+
+	tests := []test{
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name: proto.String("primitive_field"),
+					Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("repeated_primitive_field"),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{
+						schemaCore: schemaCore{
+							Type: "string",
+						},
+					},
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("empty_field"),
+					TypeName: proto.String(".google.protobuf.Empty"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "object",
+				},
+				Properties: &openapiSchemaObjectProperties{},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.FieldMask"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Timestamp"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "string",
+					Format: "date-time",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Duration"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.StringValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("repeated_wrapped_field"),
+					TypeName: proto.String(".google.protobuf.StringValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{
+						schemaCore: schemaCore{
+							Type: "string",
+						},
+					},
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.BytesValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "string",
+					Format: "byte",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Int32Value"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "integer",
+					Format: "int32",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.UInt32Value"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "integer",
+					Format: "int64",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Int64Value"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "string",
+					Format: "int64",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.UInt64Value"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "string",
+					Format: "uint64",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.FloatValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "number",
+					Format: "float",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.DoubleValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "number",
+					Format: "double",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.BoolValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "boolean",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Struct"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "object",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.Value"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.ListValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{schemaCore: schemaCore{
+						Type: "object",
+					}},
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("wrapped_field"),
+					TypeName: proto.String(".google.protobuf.NullValue"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("message_field"),
+					TypeName: proto.String(".example.Message"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				},
+			},
+			refs: refMap{".example.Message": struct{}{}},
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Ref: "#/definitions/exampleMessage",
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("map_field"),
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					TypeName: proto.String(".example.Message.MapFieldEntry"),
+					Options:  fieldOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "object",
+				},
+				AdditionalProperties: &openapiSchemaObject{
+					schemaCore: schemaCore{Type: "string"},
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:    proto.String("array_field"),
+					Label:   descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					Options: fieldOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{schemaCore: schemaCore{
+						Type: "string",
+					}},
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:    proto.String("primitive_field"),
+					Label:   descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:    descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+					Options: fieldOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "integer",
+					Format: "int32",
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("message_field"),
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					TypeName: proto.String(".example.Empty"),
+					Options:  fieldOptions,
+				},
+			},
+			refs: refMap{".example.Empty": struct{}{}},
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Ref: "#/definitions/exampleEmpty",
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("map_field"), // should be called map_field_option but it's not valid map field name
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					TypeName: proto.String(".example.Message.MapFieldEntry"),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.map_field",
+						Option: jsonSchema,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "object",
+				},
+				AdditionalProperties: &openapiSchemaObject{
+					schemaCore: schemaCore{Type: "string"},
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("array_field_option"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.array_field_option",
+						Option: jsonSchema,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{schemaCore: schemaCore{
+						Type: "string",
+					}},
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("primitive_field_option"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.primitive_field_option",
+						Option: jsonSchema,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "integer",
+					Format: "int32",
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("primitive_field_option"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum().Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field: "example.Message.primitive_field_option",
+						Option: &openapi_options.JSONSchema{
+							Title:       "field title",
+							Description: "field description",
+							Format:      "uuid",
+						},
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type:   "string",
+					Format: "uuid",
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("message_field_option"),
+					Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					TypeName: proto.String(".example.Empty"),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.message_field_option",
+						Option: jsonSchema,
+					},
+				},
+			},
+			refs: refMap{".example.Empty": struct{}{}},
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Ref: "#/definitions/exampleEmpty",
+				},
+				Title:       "field title",
+				Description: "field description",
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:    proto.String("required_via_field_behavior_field"),
+					Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					Options: requiredFieldOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+				Required: []string{"required_via_field_behavior_field"},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:    proto.String("readonly_via_field_behavior_field"),
+					Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					Options: outputOnlyOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+				ReadOnly: true,
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("required_message_field"),
+					TypeName: proto.String(".example.Message"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+					Options:  requiredFieldOptions,
+				},
+			},
+			refs: refMap{".example.Message": struct{}{}},
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Ref: "#/definitions/exampleMessage",
+				},
+				Required: []string{"required_message_field"},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("array_field_option"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.array_field_option",
+						Option: jsonSchemaWithOptions,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{
+						schemaCore: schemaCore{
+							Type: "string",
+						},
+						MultipleOf:       100,
+						Maximum:          101,
+						ExclusiveMaximum: true,
+						Minimum:          1,
+						ExclusiveMinimum: true,
+						MaxLength:        10,
+						MinLength:        3,
+						Pattern:          "[a-z]+",
+						MaxProperties:    33,
+						MinProperties:    22,
+						Required:         []string{"req"},
+						ReadOnly:         true,
+					},
+				},
+				Title:       "field title",
+				Description: "field description",
+				UniqueItems: true,
+				MaxItems:    20,
+				MinItems:    2,
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("array_field_option"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.array_field_option",
+						Option: jsonSchemaWithOptions,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{
+						schemaCore: schemaCore{
+							Type:   "string",
+							Format: "int64",
+						},
+						MultipleOf:       100,
+						Maximum:          101,
+						ExclusiveMaximum: true,
+						Minimum:          1,
+						ExclusiveMinimum: true,
+						MaxLength:        10,
+						MinLength:        3,
+						Pattern:          "[a-z]+",
+						MaxProperties:    33,
+						MinProperties:    22,
+						Required:         []string{"req"},
+						ReadOnly:         true,
+					},
+				},
+				Title:       "field title",
+				Description: "field description",
+				UniqueItems: true,
+				MaxItems:    20,
+				MinItems:    2,
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:  proto.String("array_field_format"),
+					Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+					Type:  descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.array_field_format",
+						Option: jsonSchemaWithFormat,
+					},
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "array",
+					Items: &openapiItemsObject{
+						schemaCore: schemaCore{
+							Type:   "string",
+							Format: "uuid",
+						},
+					},
+				},
+			},
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("required_via_field_behavior_field_json_name"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					JsonName: proto.String("required_field_custom_name"),
+					Options:  requiredFieldOptions,
+				},
+			},
+			refs: make(refMap),
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+				Required: []string{"required_field_custom_name"},
+			},
+			useJSONNamesForFields: true,
+		},
+		{
+			field: &descriptor.Field{
+				FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+					Name:     proto.String("required_via_json_schema"),
+					Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+					JsonName: proto.String("required_via_json_schema_json_name"),
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field:  "example.Message.required_via_json_schema",
+						Option: jsonSchemaRequired,
+					},
+				},
+			},
+			refs:                  make(refMap),
+			useJSONNamesForFields: true,
+			expected: openapiSchemaObject{
+				schemaCore: schemaCore{
+					Type: "string",
+				},
+				Required: []string{"required_via_json_schema_json_name"},
+			},
+		},
+	}
+	for _, test := range tests {
+		reg := descriptor.NewRegistry()
+		reg.SetUseJSONNamesForFields(test.useJSONNamesForFields)
+
+		req := &pluginpb.CodeGeneratorRequest{
+			ProtoFile: []*descriptorpb.FileDescriptorProto{
+				{
+					Name:    proto.String("third_party/google.proto"),
+					Package: proto.String("google.protobuf"),
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("third_party/google"),
+					},
+					MessageType: []*descriptorpb.DescriptorProto{
+						protodesc.ToDescriptorProto((&emptypb.Empty{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&structpb.Struct{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&structpb.Value{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&structpb.ListValue{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&field_mask.FieldMask{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((×tamppb.Timestamp{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&durationpb.Duration{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.StringValue{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.BytesValue{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.Int32Value{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.UInt32Value{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.Int64Value{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.UInt64Value{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.FloatValue{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.DoubleValue{}).ProtoReflect().Descriptor()),
+						protodesc.ToDescriptorProto((&wrapperspb.BoolValue{}).ProtoReflect().Descriptor()),
+					},
+					EnumType: []*descriptorpb.EnumDescriptorProto{
+						protodesc.ToEnumDescriptorProto(structpb.NullValue(0).Descriptor()),
+					},
+				},
+				{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("example.proto"),
+					Package:        proto.String("example"),
+					Dependency:     []string{"third_party/google.proto"},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+					},
+					MessageType: []*descriptorpb.DescriptorProto{
+						{
+							Name: proto.String("Message"),
+							Field: []*descriptorpb.FieldDescriptorProto{
+								{
+									Name:   proto.String("value"),
+									Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+									Number: proto.Int32(1),
+								},
+								func() *descriptorpb.FieldDescriptorProto {
+									fd := test.field.FieldDescriptorProto
+									fd.Number = proto.Int32(2)
+									return fd
+								}(),
+							},
+							NestedType: []*descriptorpb.DescriptorProto{
+								{
+									Name:    proto.String("MapFieldEntry"),
+									Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)},
+									Field: []*descriptorpb.FieldDescriptorProto{
+										{
+											Name:   proto.String("key"),
+											Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+											Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+											Number: proto.Int32(1),
+										},
+										{
+											Name:   proto.String("value"),
+											Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+											Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+											Number: proto.Int32(2),
+										},
+									},
+								},
+							},
+						},
+						{
+							Name: proto.String("Empty"),
+						},
+					},
+					EnumType: []*descriptorpb.EnumDescriptorProto{
+						{
+							Name: proto.String("MessageType"),
+							Value: []*descriptorpb.EnumValueDescriptorProto{
+								{
+									Name:   proto.String("MESSAGE_TYPE_1"),
+									Number: proto.Int32(0),
+								},
+							},
+						},
+					},
+					Service: []*descriptorpb.ServiceDescriptorProto{},
+				},
+			},
+		}
+		err := reg.Load(req)
+		if err != nil {
+			t.Errorf("failed to reg.Load(req): %v", err)
+		}
+
+		// set field's parent message pointer to message so field can resolve its FQFN
+		test.field.Message = &descriptor.Message{
+			DescriptorProto: req.ProtoFile[1].MessageType[0],
+			File: &descriptor.File{
+				FileDescriptorProto: req.ProtoFile[1],
+			},
+		}
+
+		if test.openAPIOptions != nil {
+			if err := reg.RegisterOpenAPIOptionsv3(test.openAPIOptions); err != nil {
+				t.Fatalf("failed to register OpenAPI options: %s", err)
+			}
+		}
+
+		refs := make(refMap)
+		actual := schemaOfField(test.field, reg, refs)
+		expectedSchemaObject := test.expected
+		if e, a := expectedSchemaObject, actual; !reflect.DeepEqual(a, e) {
+			t.Errorf("Expected schemaOfField(%v) = \n%#+v, actual: \n%#+v", test.field, e, a)
+		}
+		if !reflect.DeepEqual(refs, test.refs) {
+			t.Errorf("Expected schemaOfField(%v) to add refs %v, not %v", test.field, test.refs, refs)
+		}
+	}
+}
+
+func TestRenderMessagesAsDefinition(t *testing.T) {
+	jsonSchema := &openapi_options.JSONSchema{
+		Title:       "field title",
+		Description: "field description",
+		Required:    []string{"aRequiredField"},
+	}
+
+	requiredField := new(descriptorpb.FieldOptions)
+	proto.SetExtension(requiredField, openapi_options.E_Openapiv2Field, jsonSchema)
+
+	fieldBehaviorRequired := []annotations.FieldBehavior{annotations.FieldBehavior_REQUIRED}
+	requiredFieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(requiredFieldOptions, annotations.E_FieldBehavior, fieldBehaviorRequired)
+
+	fieldBehaviorOutputOnlyField := []annotations.FieldBehavior{annotations.FieldBehavior_OUTPUT_ONLY}
+	fieldBehaviorOutputOnlyOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(fieldBehaviorOutputOnlyOptions, annotations.E_FieldBehavior, fieldBehaviorOutputOnlyField)
+
+	fieldVisibilityFieldInternal := &visibility.VisibilityRule{Restriction: "INTERNAL"}
+	fieldVisibilityInternalOption := new(descriptorpb.FieldOptions)
+	proto.SetExtension(fieldVisibilityInternalOption, visibility.E_FieldVisibility, fieldVisibilityFieldInternal)
+
+	fieldVisibilityFieldPreview := &visibility.VisibilityRule{Restriction: "INTERNAL,PREVIEW"}
+	fieldVisibilityPreviewOption := new(descriptorpb.FieldOptions)
+	proto.SetExtension(fieldVisibilityPreviewOption, visibility.E_FieldVisibility, fieldVisibilityFieldPreview)
+
+	tests := []struct {
+		descr                 string
+		msgDescs              []*descriptorpb.DescriptorProto
+		schema                map[string]*openapi_options.Schema // per-message schema to add
+		defs                  openapiDefinitionsObject
+		openAPIOptions        *openapiconfigv3.OpenAPIOptions
+		pathParams            []descriptor.Parameter
+		UseJSONNamesForFields bool
+		UseAllOfForRefs       bool
+	}{
+		{
+			descr: "no OpenAPI options",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{},
+			defs: map[string]openapiSchemaObject{
+				"Message": {schemaCore: schemaCore{Type: "object"}},
+			},
+		},
+		{
+			descr: "example option",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					Example: `{"foo":"bar"}`,
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {schemaCore: schemaCore{
+					Type:    "object",
+					Example: RawExample(`{"foo":"bar"}`),
+				}},
+			},
+		},
+		{
+			descr: "example option with something non-json",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					Example: `XXXX anything goes XXXX`,
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {schemaCore: schemaCore{
+					Type:    "object",
+					Example: RawExample(`XXXX anything goes XXXX`),
+				}},
+			},
+		},
+		{
+			descr: "external docs option",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					ExternalDocs: &openapi_options.ExternalDocumentation{
+						Description: "glorious docs",
+						Url:         "https://nada",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: "glorious docs",
+						URL:         "https://nada",
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema options",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:            "title",
+						Description:      "desc",
+						MultipleOf:       100,
+						Maximum:          101,
+						ExclusiveMaximum: true,
+						Minimum:          1,
+						ExclusiveMinimum: true,
+						MaxLength:        10,
+						MinLength:        3,
+						Pattern:          "[a-z]+",
+						MaxItems:         20,
+						MinItems:         2,
+						UniqueItems:      true,
+						MaxProperties:    33,
+						MinProperties:    22,
+						Required:         []string{"req"},
+						ReadOnly:         true,
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:            "title",
+					Description:      "desc",
+					MultipleOf:       100,
+					Maximum:          101,
+					ExclusiveMaximum: true,
+					Minimum:          1,
+					ExclusiveMinimum: true,
+					MaxLength:        10,
+					MinLength:        3,
+					Pattern:          "[a-z]+",
+					MaxItems:         20,
+					MinItems:         2,
+					UniqueItems:      true,
+					MaxProperties:    33,
+					MinProperties:    22,
+					Required:         []string{"req"},
+					ReadOnly:         true,
+				},
+			},
+		},
+		{
+			descr: "JSONSchema options from registry",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Message: []*openapiconfigv3.OpenAPIMessageOption{
+					{
+						Message: "example.Message",
+						Option: &openapi_options.Schema{
+							JsonSchema: &openapi_options.JSONSchema{
+								Title:            "title",
+								Description:      "desc",
+								MultipleOf:       100,
+								Maximum:          101,
+								ExclusiveMaximum: true,
+								Minimum:          1,
+								ExclusiveMinimum: true,
+								MaxLength:        10,
+								MinLength:        3,
+								Pattern:          "[a-z]+",
+								MaxItems:         20,
+								MinItems:         2,
+								UniqueItems:      true,
+								MaxProperties:    33,
+								MinProperties:    22,
+								Required:         []string{"req"},
+								ReadOnly:         true,
+							},
+						},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:            "title",
+					Description:      "desc",
+					MultipleOf:       100,
+					Maximum:          101,
+					ExclusiveMaximum: true,
+					Minimum:          1,
+					ExclusiveMinimum: true,
+					MaxLength:        10,
+					MinLength:        3,
+					Pattern:          "[a-z]+",
+					MaxItems:         20,
+					MinItems:         2,
+					UniqueItems:      true,
+					MaxProperties:    33,
+					MinProperties:    22,
+					Required:         []string{"req"},
+					ReadOnly:         true,
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with required properties",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:   proto.String("FieldOne"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(1),
+						},
+						{
+							Name:    proto.String("FieldTwo"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(2),
+							Options: requiredFieldOptions,
+						},
+						{
+							Name:    proto.String("FieldThree"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(3),
+							Options: requiredFieldOptions,
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{"FieldOne", "FieldTwo"},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"FieldOne", "FieldTwo", "FieldThree"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "FieldOne",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "FieldTwo",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "FieldThree",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with required properties",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("FieldOne"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(3),
+							Options: requiredFieldOptions,
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"FieldOne"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "FieldOne",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with required properties by using annotations",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("FieldOne"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(2),
+							Options: requiredFieldOptions,
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"FieldOne"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "FieldOne",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with hidden properties",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("aInternalField"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(1),
+							Options: fieldVisibilityInternalOption,
+						},
+						{
+							Name:    proto.String("aPreviewField"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(2),
+							Options: fieldVisibilityPreviewOption,
+						},
+						{
+							Name:   proto.String("aVisibleField"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(3),
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{"req"},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"req"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "aPreviewField",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "aVisibleField",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with path parameters",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("aRequiredField"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(1),
+							Options: requiredField,
+						},
+						{
+							Name:   proto.String("aPathParameter"),
+							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number: proto.Int32(2),
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{"req"},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"req", "aRequiredField"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "aRequiredField",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+								Description: "field description",
+								Title:       "field title",
+							},
+						},
+					},
+				},
+			},
+			pathParams: []descriptor.Parameter{
+				{
+					FieldPath: descriptor.FieldPath{
+						descriptor.FieldPathComponent{
+							Name: ("aPathParameter"),
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with required properties via field_behavior",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:    proto.String("aRequiredField"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(1),
+							Options: requiredFieldOptions,
+						},
+						{
+							Name:    proto.String("aOutputOnlyField"),
+							Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:  proto.Int32(2),
+							Options: fieldBehaviorOutputOnlyOptions,
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{"req"},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"req", "aRequiredField"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "aRequiredField",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "aOutputOnlyField",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+								ReadOnly: true,
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			descr: "JSONSchema with required properties and fields with json_name",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("FieldOne"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(1),
+							JsonName: proto.String("custom_json_1"),
+						},
+						{
+							Name:     proto.String("FieldTwo"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(2),
+							JsonName: proto.String("custom_json_2"),
+							Options:  requiredFieldOptions,
+						},
+						{
+							Name:     proto.String("FieldThree"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+							Number:   proto.Int32(3),
+							JsonName: proto.String("custom_json_3"),
+							Options:  requiredFieldOptions,
+						},
+					},
+				},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{"FieldOne", "FieldTwo"},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    []string{"custom_json_1", "custom_json_2", "custom_json_3"},
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "custom_json_1",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "custom_json_2",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+						{
+							Key: "custom_json_3",
+							Value: openapiSchemaObject{
+								schemaCore: schemaCore{
+									Type: "string",
+								},
+							},
+						},
+					},
+				},
+			},
+			UseJSONNamesForFields: true,
+		},
+		{
+			descr: "JSONSchema with a read_only nested field",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{
+					Name: proto.String("Message"),
+					Field: []*descriptorpb.FieldDescriptorProto{
+						{
+							Name:     proto.String("nested"),
+							Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+							TypeName: proto.String(".example.Message.Nested"),
+							Number:   proto.Int32(1),
+							Options:  fieldBehaviorOutputOnlyOptions,
+						},
+					},
+					NestedType: []*descriptorpb.DescriptorProto{{
+						Name: proto.String("Nested"),
+					}},
+				},
+			},
+			UseAllOfForRefs: true,
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "title",
+						Description: "desc",
+						Required:    []string{},
+					},
+				},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Field: []*openapiconfigv3.OpenAPIFieldOption{
+					{
+						Field: "example.Message.nested",
+						Option: &openapi_options.JSONSchema{
+							Title:       "nested field title",
+							Description: "nested field desc",
+							Example:     `"ok":"TRUE"`,
+						},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"exampleMessage": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "title",
+					Description: "desc",
+					Required:    nil,
+					Properties: &openapiSchemaObjectProperties{
+						{
+							Key: "nested",
+							Value: openapiSchemaObject{
+								AllOf:    []allOfEntry{{Ref: "#/definitions/MessageNested"}},
+								ReadOnly: true,
+								schemaCore: schemaCore{
+									Example: RawExample(`"ok":"TRUE"`),
+								},
+								Title:       "nested field title",
+								Description: "nested field desc",
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.descr, func(t *testing.T) {
+			msgs := []*descriptor.Message{}
+			for _, msgdesc := range test.msgDescs {
+				msgdesc.Options = &descriptorpb.MessageOptions{}
+				msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+			}
+
+			reg := descriptor.NewRegistry()
+			file := descriptor.File{
+				FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("example.proto"),
+					Package:        proto.String("example"),
+					Dependency:     []string{},
+					MessageType:    test.msgDescs,
+					EnumType:       []*descriptorpb.EnumDescriptorProto{},
+					Service:        []*descriptorpb.ServiceDescriptorProto{},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+					},
+				},
+				Messages: msgs,
+			}
+			err := reg.Load(&pluginpb.CodeGeneratorRequest{
+				ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+			})
+			reg.SetVisibilityRestrictionSelectors([]string{"PREVIEW"})
+
+			if test.UseJSONNamesForFields {
+				reg.SetUseJSONNamesForFields(true)
+			}
+
+			if test.UseAllOfForRefs {
+				reg.SetUseAllOfForRefs(true)
+			}
+
+			if err != nil {
+				t.Fatalf("failed to load code generator request: %v", err)
+			}
+
+			msgMap := map[string]*descriptor.Message{}
+			for _, d := range test.msgDescs {
+				name := d.GetName()
+				msg, err := reg.LookupMsg("example", name)
+				if err != nil {
+					t.Fatalf("lookup message %v: %v", name, err)
+				}
+				msgMap[msg.FQMN()] = msg
+
+				if schema, ok := test.schema[name]; ok {
+					proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, schema)
+				}
+			}
+
+			if test.openAPIOptions != nil {
+				if err := reg.RegisterOpenAPIOptionsv3(test.openAPIOptions); err != nil {
+					t.Fatalf("failed to register OpenAPI options: %s", err)
+				}
+			}
+
+			refs := make(refMap)
+			actual := make(openapiDefinitionsObject)
+			if err := renderMessagesAsDefinition(msgMap, actual, reg, refs, test.pathParams); err != nil {
+				t.Errorf("renderMessagesAsDefinition failed with: %s", err)
+			}
+
+			if !reflect.DeepEqual(actual, test.defs) {
+				t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual)
+			}
+		})
+	}
+}
+
+func TestUpdateOpenAPIDataFromComments(t *testing.T) {
+	tests := []struct {
+		descr                 string
+		openapiSwaggerObject  interface{}
+		comments              string
+		expectedError         error
+		expectedOpenAPIObject interface{}
+		useGoTemplate         bool
+		goTemplateArgs        []string
+	}{
+		{
+			descr:                 "empty comments",
+			openapiSwaggerObject:  nil,
+			expectedOpenAPIObject: nil,
+			comments:              "",
+			expectedError:         nil,
+		},
+		{
+			descr:                "set field to read only",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				ReadOnly:    true,
+				Description: "... Output only. ...",
+			},
+			comments:      "... Output only. ...",
+			expectedError: nil,
+		},
+		{
+			descr:                "set title",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title: "Comment with no trailing dot",
+			},
+			comments:      "Comment with no trailing dot",
+			expectedError: nil,
+		},
+		{
+			descr:                "set description",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Description: "Comment with trailing dot.",
+			},
+			comments:      "Comment with trailing dot.",
+			expectedError: nil,
+		},
+		{
+			descr: "use info object",
+			openapiSwaggerObject: &openapiSwaggerObject{
+				Info: openapiInfoObject{},
+			},
+			expectedOpenAPIObject: &openapiSwaggerObject{
+				Info: openapiInfoObject{
+					Description: "Comment with trailing dot.",
+				},
+			},
+			comments:      "Comment with trailing dot.",
+			expectedError: nil,
+		},
+		{
+			descr:                "multi line comment with title",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title:       "First line",
+				Description: "Second line",
+			},
+			comments:      "First line\n\nSecond line",
+			expectedError: nil,
+		},
+		{
+			descr:                "multi line comment no title",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Description: "First line.\n\nSecond line",
+			},
+			comments:      "First line.\n\nSecond line",
+			expectedError: nil,
+		},
+		{
+			descr:                "multi line comment with summary with dot",
+			openapiSwaggerObject: &openapiOperationObject{},
+			expectedOpenAPIObject: &openapiOperationObject{
+				Summary:     "First line.",
+				Description: "Second line",
+			},
+			comments:      "First line.\n\nSecond line",
+			expectedError: nil,
+		},
+		{
+			descr:                "multi line comment with summary no dot",
+			openapiSwaggerObject: &openapiOperationObject{},
+			expectedOpenAPIObject: &openapiOperationObject{
+				Summary:     "First line",
+				Description: "Second line",
+			},
+			comments:      "First line\n\nSecond line",
+			expectedError: nil,
+		},
+		{
+			descr:                 "multi line comment with summary no dot",
+			openapiSwaggerObject:  &schemaCore{},
+			expectedOpenAPIObject: &schemaCore{},
+			comments:              "Any comment",
+			expectedError:         errors.New("no description nor summary property"),
+		},
+		{
+			descr:                "without use_go_template",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title:       "First line",
+				Description: "{{import \"documentation.md\"}}",
+			},
+			comments:      "First line\n\n{{import \"documentation.md\"}}",
+			expectedError: nil,
+		},
+		{
+			descr:                "error with use_go_template",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title:       "First line",
+				Description: "open noneexistingfile.txt: no such file or directory",
+			},
+			comments:      "First line\n\n{{import \"noneexistingfile.txt\"}}",
+			expectedError: nil,
+			useGoTemplate: true,
+		},
+		{
+			descr:                "template with use_go_template",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title:       "Template",
+				Description: `Description "which means nothing"`,
+			},
+			comments:      "Template\n\nDescription {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+			expectedError: nil,
+			useGoTemplate: true,
+		},
+		{
+			descr:                "template with use_go_template and go_template_args",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title:       "Template",
+				Description: `Description "which means nothing" for environment test with value my_value`,
+			},
+			comments: "Template\n\nDescription {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} for " +
+				"environment {{arg \"environment\"}} with value {{arg \"my_key\"}}",
+			expectedError:  nil,
+			useGoTemplate:  true,
+			goTemplateArgs: []string{"my_key=my_value", "environment=test"},
+		},
+		{
+			descr:                "template with use_go_template and undefined go_template_args",
+			openapiSwaggerObject: &openapiSchemaObject{},
+			expectedOpenAPIObject: &openapiSchemaObject{
+				Title: "Template",
+				Description: `Description "which means nothing" for environment test with value ` +
+					`goTemplateArg something_undefined not found`,
+			},
+			comments: "Template\n\nDescription {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} for " +
+				"environment {{arg \"environment\"}} with value {{arg \"something_undefined\"}}",
+			expectedError:  nil,
+			useGoTemplate:  true,
+			goTemplateArgs: []string{"environment=test"},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.descr, func(t *testing.T) {
+			reg := descriptor.NewRegistry()
+			if test.useGoTemplate {
+				reg.SetUseGoTemplate(true)
+			}
+			if len(test.goTemplateArgs) > 0 {
+				reg.SetGoTemplateArgs(test.goTemplateArgs)
+			}
+			err := updateOpenAPIDataFromComments(reg, test.openapiSwaggerObject, nil, test.comments, false)
+			if test.expectedError == nil {
+				if err != nil {
+					t.Errorf("unexpected error '%v'", err)
+				}
+				if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) {
+					t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject)
+				}
+			} else {
+				if err == nil {
+					t.Error("expected update error not returned")
+				}
+				if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) {
+					t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject)
+				}
+				if err.Error() != test.expectedError.Error() {
+					t.Errorf("expected error malformed, expected %q, got %q", test.expectedError.Error(), err.Error())
+				}
+			}
+		})
+	}
+}
+
+func TestMessageOptionsWithGoTemplate(t *testing.T) {
+	tests := []struct {
+		descr          string
+		msgDescs       []*descriptorpb.DescriptorProto
+		schema         map[string]*openapi_options.Schema // per-message schema to add
+		defs           openapiDefinitionsObject
+		openAPIOptions *openapiconfigv3.OpenAPIOptions
+		useGoTemplate  bool
+		goTemplateArgs []string
+	}{
+		{
+			descr: "external docs option",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "{{.Name}}",
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					},
+					ExternalDocs: &openapi_options.ExternalDocumentation{
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "Message",
+					Description: `Description "which means nothing"`,
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: `Description "which means nothing"`,
+					},
+				},
+			},
+			useGoTemplate: true,
+		},
+		{
+			descr: "external docs option",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title:       "{{.Name}}",
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					},
+					ExternalDocs: &openapi_options.ExternalDocumentation{
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "{{.Name}}",
+					Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+					},
+				},
+			},
+			useGoTemplate: false,
+		},
+		{
+			descr: "external docs option with go template args",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			schema: map[string]*openapi_options.Schema{
+				"Message": {
+					JsonSchema: &openapi_options.JSONSchema{
+						Title: "{{.Name}}",
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} " +
+							"{{arg \"my_key\"}}",
+					},
+					ExternalDocs: &openapi_options.ExternalDocumentation{
+						Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} " +
+							"{{arg \"my_key\"}}",
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "Message",
+					Description: `Description "which means nothing" too`,
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: `Description "which means nothing" too`,
+					},
+				},
+			},
+			useGoTemplate:  true,
+			goTemplateArgs: []string{"my_key=too"},
+		},
+		{
+			descr: "registered OpenAPIOption",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Message: []*openapiconfigv3.OpenAPIMessageOption{
+					{
+						Message: "example.Message",
+						Option: &openapi_options.Schema{
+							JsonSchema: &openapi_options.JSONSchema{
+								Title:       "{{.Name}}",
+								Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+							},
+							ExternalDocs: &openapi_options.ExternalDocumentation{
+								Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}",
+							},
+						},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "Message",
+					Description: `Description "which means nothing"`,
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: `Description "which means nothing"`,
+					},
+				},
+			},
+			useGoTemplate: true,
+		},
+		{
+			descr: "registered OpenAPIOption with go template args",
+			msgDescs: []*descriptorpb.DescriptorProto{
+				{Name: proto.String("Message")},
+			},
+			openAPIOptions: &openapiconfigv3.OpenAPIOptions{
+				Message: []*openapiconfigv3.OpenAPIMessageOption{
+					{
+						Message: "example.Message",
+						Option: &openapi_options.Schema{
+							JsonSchema: &openapi_options.JSONSchema{
+								Title: "{{.Name}}",
+								Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} " +
+									"{{arg \"my_key\"}}",
+							},
+							ExternalDocs: &openapi_options.ExternalDocumentation{
+								Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}} " +
+									"{{arg \"my_key\"}}",
+							},
+						},
+					},
+				},
+			},
+			defs: map[string]openapiSchemaObject{
+				"Message": {
+					schemaCore: schemaCore{
+						Type: "object",
+					},
+					Title:       "Message",
+					Description: `Description "which means nothing" too`,
+					ExternalDocs: &openapiExternalDocumentationObject{
+						Description: `Description "which means nothing" too`,
+					},
+				},
+			},
+			useGoTemplate:  true,
+			goTemplateArgs: []string{"my_key=too"},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.descr, func(t *testing.T) {
+			msgs := []*descriptor.Message{}
+			for _, msgdesc := range test.msgDescs {
+				msgdesc.Options = &descriptorpb.MessageOptions{}
+				msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc})
+			}
+
+			reg := descriptor.NewRegistry()
+			reg.SetUseGoTemplate(test.useGoTemplate)
+			reg.SetGoTemplateArgs(test.goTemplateArgs)
+			file := descriptor.File{
+				FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("example.proto"),
+					Package:        proto.String("example"),
+					Dependency:     []string{},
+					MessageType:    test.msgDescs,
+					EnumType:       []*descriptorpb.EnumDescriptorProto{},
+					Service:        []*descriptorpb.ServiceDescriptorProto{},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+					},
+				},
+				Messages: msgs,
+			}
+			err := reg.Load(&pluginpb.CodeGeneratorRequest{
+				ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+			})
+			if err != nil {
+				t.Fatalf("failed to load code generator request: %v", err)
+			}
+
+			msgMap := map[string]*descriptor.Message{}
+			for _, d := range test.msgDescs {
+				name := d.GetName()
+				msg, err := reg.LookupMsg("example", name)
+				if err != nil {
+					t.Fatalf("lookup message %v: %v", name, err)
+				}
+				msgMap[msg.FQMN()] = msg
+
+				if schema, ok := test.schema[name]; ok {
+					proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, schema)
+				}
+			}
+
+			if test.openAPIOptions != nil {
+				if err := reg.RegisterOpenAPIOptionsv3(test.openAPIOptions); err != nil {
+					t.Fatalf("failed to register OpenAPI options: %s", err)
+				}
+			}
+
+			refs := make(refMap)
+			actual := make(openapiDefinitionsObject)
+			if err := renderMessagesAsDefinition(msgMap, actual, reg, refs, nil); err != nil {
+				t.Errorf("renderMessagesAsDefinition failed with: %s", err)
+			}
+
+			if !reflect.DeepEqual(actual, test.defs) {
+				t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual)
+			}
+		})
+	}
+}
+
+func TestTagsWithGoTemplate(t *testing.T) {
+	reg := descriptor.NewRegistry()
+	reg.SetUseGoTemplate(true)
+	reg.SetGoTemplateArgs([]string{"my_key=my_value"})
+
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:    proto.String("ExampleService"),
+		Options: &descriptorpb.ServiceOptions{},
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			Dependency:     []string{},
+			MessageType:    []*descriptorpb.DescriptorProto{},
+			EnumType:       []*descriptorpb.EnumDescriptorProto{},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		Messages: []*descriptor.Message{},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+			},
+		},
+	}
+
+	// Set tag through service extension
+	proto.SetExtension(file.GetService()[0].Options, openapi_options.E_Openapiv2Tag, &openapi_options.Tag{
+		Name:        "service tag",
+		Description: "{{ .Name }}!",
+	})
+
+	// Set tags through file extension
+	swagger := openapi_options.Swagger{
+		Tags: []*openapi_options.Tag{
+			{
+				Name:        "not a service tag",
+				Description: "{{ import \"file\" }}",
+			},
+			{
+				Name:        "ExampleService",
+				Description: "ExampleService!",
+			},
+			{
+				Name:        "not a service tag 2",
+				Description: "{{ import \"file\" }}",
+			},
+			{
+				Name:        "Service with my_key",
+				Description: "the {{arg \"my_key\"}}",
+			},
+		},
+	}
+	proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger)
+
+	actual, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+	expectedTags := []openapiTagObject{
+		{
+			Name:        "not a service tag",
+			Description: "open file: no such file or directory",
+		},
+		{
+			Name:        "ExampleService",
+			Description: "ExampleService!",
+		},
+		{
+			Name:        "not a service tag 2",
+			Description: "open file: no such file or directory",
+		},
+		{
+			Name:        "Service with my_key",
+			Description: "the my_value",
+		},
+		{
+			Name:        "service tag",
+			Description: "ExampleService!",
+		},
+	}
+	if !reflect.DeepEqual(actual.Tags, expectedTags) {
+		t.Errorf("Expected tags %+v, not %+v", expectedTags, actual.Tags)
+	}
+}
+
+func TestTemplateWithoutErrorDefinition(t *testing.T) {
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name:  proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Echo"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo",
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Errorf("failed to reg.Load(): %v", err)
+		return
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	defRsp, ok := result.getPathItemObject("/v1/echo").Post.Responses["default"]
+	if !ok {
+		return
+	}
+
+	ref := defRsp.Schema.schemaCore.Ref
+	refName := strings.TrimPrefix(ref, "#/definitions/")
+	if refName == "" {
+		t.Fatal("created default Error response with empty reflink")
+	}
+
+	if _, ok := result.Definitions[refName]; !ok {
+		t.Errorf("default Error response with reflink '%v', but its definition was not found", refName)
+	}
+}
+
+func TestSingleServiceTemplateWithDuplicateHttp1Operations(t *testing.T) {
+	fieldType := descriptorpb.FieldDescriptorProto_TYPE_STRING
+	field1 := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("name"),
+		Number: proto.Int32(1),
+		Type:   &fieldType,
+	}
+
+	getFooMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("GetFooRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	getFooMsg := &descriptor.Message{
+		DescriptorProto: getFooMsgDesc,
+	}
+	deleteFooMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("DeleteFooRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	deleteFooMsg := &descriptor.Message{
+		DescriptorProto: deleteFooMsgDesc,
+	}
+	getFoo := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("GetFoo"),
+		InputType:  proto.String("GetFooRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+	deleteFoo := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("DeleteFoo"),
+		InputType:  proto.String("DeleteFooRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+
+	getBarMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("GetBarRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	getBarMsg := &descriptor.Message{
+		DescriptorProto: getBarMsgDesc,
+	}
+	deleteBarMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("DeleteBarRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	deleteBarMsg := &descriptor.Message{
+		DescriptorProto: deleteBarMsgDesc,
+	}
+	getBar := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("GetBar"),
+		InputType:  proto.String("GetBarRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+	deleteBar := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("DeleteBar"),
+		InputType:  proto.String("DeleteBarRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+
+	svc1 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("Service1"),
+		Method: []*descriptorpb.MethodDescriptorProto{getFoo, deleteFoo, getBar, deleteBar},
+	}
+
+	emptyMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("EmptyMessage"),
+	}
+	emptyMsg := &descriptor.Message{
+		DescriptorProto: emptyMsgDesc,
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("service1.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{getBarMsgDesc, deleteBarMsgDesc, getFooMsgDesc, deleteFooMsgDesc, emptyMsgDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc1},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{getFooMsg, deleteFooMsg, getBarMsg, deleteBarMsg, emptyMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc1,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: getFoo,
+						RequestType:           getFooMsg,
+						ResponseType:          getFooMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=foos/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              getFooMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: deleteFoo,
+						RequestType:           deleteFooMsg,
+						ResponseType:          emptyMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "DELETE",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=foos/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              deleteFooMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: getBar,
+						RequestType:           getBarMsg,
+						ResponseType:          getBarMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=bars/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              getBarMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: deleteBar,
+						RequestType:           deleteBarMsg,
+						ResponseType:          emptyMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "DELETE",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=bars/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              deleteBarMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	if got, want := len(result.Paths), 2; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	firstOpGet := result.getPathItemObject("/v1/{name}").Get
+	if got, want := firstOpGet.OperationID, "Service1_GetFoo"; got != want {
+		t.Fatalf("First operation GET id differed, got %s want %s", got, want)
+	}
+	if got, want := len(firstOpGet.Parameters), 2; got != want {
+		t.Fatalf("First operation GET params length differed, got %d want %d", got, want)
+	}
+	if got, want := firstOpGet.Parameters[0].Name, "name"; got != want {
+		t.Fatalf("First operation GET first param name differed, got %s want %s", got, want)
+	}
+	if got, want := firstOpGet.Parameters[0].Pattern, "foos/[^/]+"; got != want {
+		t.Fatalf("First operation GET first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := firstOpGet.Parameters[1].In, "body"; got != want {
+		t.Fatalf("First operation GET second param 'in' differed, got %s want %s", got, want)
+	}
+
+	firstOpDelete := result.getPathItemObject("/v1/{name}").Delete
+	if got, want := firstOpDelete.OperationID, "Service1_DeleteFoo"; got != want {
+		t.Fatalf("First operation id DELETE differed, got %s want %s", got, want)
+	}
+	if got, want := len(firstOpDelete.Parameters), 2; got != want {
+		t.Fatalf("First operation DELETE params length differed, got %d want %d", got, want)
+	}
+	if got, want := firstOpDelete.Parameters[0].Name, "name"; got != want {
+		t.Fatalf("First operation DELETE first param name differed, got %s want %s", got, want)
+	}
+	if got, want := firstOpDelete.Parameters[0].Pattern, "foos/[^/]+"; got != want {
+		t.Fatalf("First operation DELETE first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := firstOpDelete.Parameters[1].In, "body"; got != want {
+		t.Fatalf("First operation DELETE second param 'in' differed, got %s want %s", got, want)
+	}
+
+	secondOpGet := result.getPathItemObject("/v1/{name" + pathParamUniqueSuffixDeliminator + "1}").Get
+	if got, want := secondOpGet.OperationID, "Service1_GetBar"; got != want {
+		t.Fatalf("Second operation id GET differed, got %s want %s", got, want)
+	}
+	if got, want := len(secondOpGet.Parameters), 2; got != want {
+		t.Fatalf("Second operation GET params length differed, got %d want %d", got, want)
+	}
+	if got, want := secondOpGet.Parameters[0].Name, "name"+pathParamUniqueSuffixDeliminator+"1"; got != want {
+		t.Fatalf("Second operation GET first param name differed, got %s want %s", got, want)
+	}
+	if got, want := secondOpGet.Parameters[0].Pattern, "bars/[^/]+"; got != want {
+		t.Fatalf("Second operation GET first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := secondOpGet.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Second operation GET second param 'in' differed, got %s want %s", got, want)
+	}
+
+	secondOpDelete := result.getPathItemObject("/v1/{name" + pathParamUniqueSuffixDeliminator + "1}").Delete
+	if got, want := secondOpDelete.OperationID, "Service1_DeleteBar"; got != want {
+		t.Fatalf("Second operation id differed, got %s want %s", got, want)
+	}
+	if got, want := len(secondOpDelete.Parameters), 2; got != want {
+		t.Fatalf("Second operation params length differed, got %d want %d", got, want)
+	}
+	if got, want := secondOpDelete.Parameters[0].Name, "name"+pathParamUniqueSuffixDeliminator+"1"; got != want {
+		t.Fatalf("Second operation first param name differed, got %s want %s", got, want)
+	}
+	if got, want := secondOpDelete.Parameters[0].Pattern, "bars/[^/]+"; got != want {
+		t.Fatalf("Second operation first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := secondOpDelete.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Second operation third param 'in' differed, got %s want %s", got, want)
+	}
+}
+
+func getOperation(pathItem openapiPathItemObject, httpMethod string) *openapiOperationObject {
+	switch httpMethod {
+	case "GET":
+		return pathItem.Get
+	case "POST":
+		return pathItem.Post
+	case "PUT":
+		return pathItem.Put
+	case "DELETE":
+		return pathItem.Delete
+	case "PATCH":
+		return pathItem.Patch
+	case "HEAD":
+		return pathItem.Head
+	case "OPTIONS":
+		return pathItem.Options
+	default:
+		return nil
+	}
+}
+
+func TestSingleServiceTemplateWithDuplicateInAllSupportedHttp1Operations(t *testing.T) {
+	supportedMethods := []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}
+
+	for _, method := range supportedMethods {
+		fieldType := descriptorpb.FieldDescriptorProto_TYPE_STRING
+		field1 := &descriptorpb.FieldDescriptorProto{
+			Name:   proto.String("name"),
+			Number: proto.Int32(1),
+			Type:   &fieldType,
+		}
+
+		methodFooMsgDesc := &descriptorpb.DescriptorProto{
+			Name: proto.String(method + "FooRequest"),
+			Field: []*descriptorpb.FieldDescriptorProto{
+				field1,
+			},
+		}
+		methodFooMsg := &descriptor.Message{
+			DescriptorProto: methodFooMsgDesc,
+		}
+		methodFoo := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String(method + "Foo"),
+			InputType:  proto.String(method + "FooRequest"),
+			OutputType: proto.String("EmptyMessage"),
+		}
+
+		methodBarMsgDesc := &descriptorpb.DescriptorProto{
+			Name: proto.String(method + "BarRequest"),
+			Field: []*descriptorpb.FieldDescriptorProto{
+				field1,
+			},
+		}
+		methodBarMsg := &descriptor.Message{
+			DescriptorProto: methodBarMsgDesc,
+		}
+		methodBar := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String(method + "Bar"),
+			InputType:  proto.String(method + "BarRequest"),
+			OutputType: proto.String("EmptyMessage"),
+		}
+
+		svc1 := &descriptorpb.ServiceDescriptorProto{
+			Name:   proto.String("Service1"),
+			Method: []*descriptorpb.MethodDescriptorProto{methodFoo, methodBar},
+		}
+
+		emptyMsgDesc := &descriptorpb.DescriptorProto{
+			Name: proto.String("EmptyMessage"),
+		}
+		emptyMsg := &descriptor.Message{
+			DescriptorProto: emptyMsgDesc,
+		}
+
+		file := descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("service1.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{methodBarMsgDesc, methodFooMsgDesc, emptyMsgDesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc1},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: []*descriptor.Message{methodFooMsg, methodBarMsg, emptyMsg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc1,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: methodFoo,
+							RequestType:           methodFooMsg,
+							ResponseType:          methodFooMsg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: method,
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/{name=foos/*}",
+									},
+									PathParams: []descriptor.Parameter{
+										{
+											Target: &descriptor.Field{
+												FieldDescriptorProto: field1,
+												Message:              methodFooMsg,
+											},
+											FieldPath: descriptor.FieldPath{
+												{
+													Name: "name",
+												},
+											},
+										},
+									},
+									Body: &descriptor.Body{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+									},
+								},
+							},
+						},
+						{
+							MethodDescriptorProto: methodBar,
+							RequestType:           methodBarMsg,
+							ResponseType:          methodBarMsg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: method,
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/{name=bars/*}",
+									},
+									PathParams: []descriptor.Parameter{
+										{
+											Target: &descriptor.Field{
+												FieldDescriptorProto: field1,
+												Message:              methodBarMsg,
+											},
+											FieldPath: descriptor.FieldPath{
+												{
+													Name: "name",
+												},
+											},
+										},
+									},
+									Body: &descriptor.Body{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		reg := descriptor.NewRegistry()
+		err := reg.Load(reqFromFile(&file))
+		if err != nil {
+			t.Fatalf("failed to reg.Load(): %v", err)
+		}
+		result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+		if err != nil {
+			t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+		}
+
+		if got, want := len(result.Paths), 2; got != want {
+			t.Fatalf("Results path length differed, got %d want %d", got, want)
+		}
+
+		firstOpMethod := getOperation(result.getPathItemObject("/v1/{name}"), method)
+		if got, want := firstOpMethod.OperationID, "Service1_"+method+"Foo"; got != want {
+			t.Fatalf("First operation %s id differed, got %s want %s", method, got, want)
+		}
+		if got, want := len(firstOpMethod.Parameters), 2; got != want {
+			t.Fatalf("First operation %s params length differed, got %d want %d", method, got, want)
+		}
+		if got, want := firstOpMethod.Parameters[0].Name, "name"; got != want {
+			t.Fatalf("First operation %s first param name differed, got %s want %s", method, got, want)
+		}
+		if got, want := firstOpMethod.Parameters[0].Pattern, "foos/[^/]+"; got != want {
+			t.Fatalf("First operation %s first param pattern differed, got %s want %s", method, got, want)
+		}
+		if got, want := firstOpMethod.Parameters[1].In, "body"; got != want {
+			t.Fatalf("First operation %s second param 'in' differed, got %s want %s", method, got, want)
+		}
+
+		secondOpMethod := getOperation(result.getPathItemObject("/v1/{name"+pathParamUniqueSuffixDeliminator+"1}"), method)
+		if got, want := secondOpMethod.OperationID, "Service1_"+method+"Bar"; got != want {
+			t.Fatalf("Second operation id %s differed, got %s want %s", method, got, want)
+		}
+		if got, want := len(secondOpMethod.Parameters), 2; got != want {
+			t.Fatalf("Second operation %s params length differed, got %d want %d", method, got, want)
+		}
+		if got, want := secondOpMethod.Parameters[0].Name, "name"+pathParamUniqueSuffixDeliminator+"1"; got != want {
+			t.Fatalf("Second operation %s first param name differed, got %s want %s", method, got, want)
+		}
+		if got, want := secondOpMethod.Parameters[0].Pattern, "bars/[^/]+"; got != want {
+			t.Fatalf("Second operation %s first param pattern differed, got %s want %s", method, got, want)
+		}
+		if got, want := secondOpMethod.Parameters[1].In, "body"; got != want {
+			t.Fatalf("Second operation %s second param 'in' differed, got %s want %s", method, got, want)
+		}
+	}
+}
+
+func TestSingleServiceTemplateWithDuplicateHttp1UnsupportedOperations(t *testing.T) {
+	fieldType := descriptorpb.FieldDescriptorProto_TYPE_STRING
+	field1 := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("name"),
+		Number: proto.Int32(1),
+		Type:   &fieldType,
+	}
+
+	unsupportedFooMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("UnsupportedFooRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	unsupportedFooMsg := &descriptor.Message{
+		DescriptorProto: unsupportedFooMsgDesc,
+	}
+	unsupportedFoo := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("UnsupportedFoo"),
+		InputType:  proto.String("UnsupportedFooRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+
+	unsupportedBarMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("UnsupportedBarRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+		},
+	}
+	unsupportedBarMsg := &descriptor.Message{
+		DescriptorProto: unsupportedBarMsgDesc,
+	}
+	unsupportedBar := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("UnsupportedBar"),
+		InputType:  proto.String("UnsupportedBarRequest"),
+		OutputType: proto.String("EmptyMessage"),
+	}
+
+	svc1 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("Service1"),
+		Method: []*descriptorpb.MethodDescriptorProto{unsupportedFoo, unsupportedBar},
+	}
+
+	emptyMsgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("EmptyMessage"),
+	}
+	emptyMsg := &descriptor.Message{
+		DescriptorProto: emptyMsgDesc,
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("service1.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{unsupportedBarMsgDesc, unsupportedFooMsgDesc, emptyMsgDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc1},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{unsupportedFooMsg, unsupportedBarMsg, emptyMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc1,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: unsupportedFoo,
+						RequestType:           unsupportedFooMsg,
+						ResponseType:          unsupportedFooMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "UNSUPPORTED",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=foos/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              unsupportedFooMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: unsupportedBar,
+						RequestType:           unsupportedBarMsg,
+						ResponseType:          unsupportedBarMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "UNSUPPORTED",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=bars/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              unsupportedBarMsg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	// Just should not crash, no special handling of unsupported HTTP methods
+	if got, want := len(result.Paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+}
+
+func TestTemplateWithDuplicateHttp1Operations(t *testing.T) {
+	fieldType := descriptorpb.FieldDescriptorProto_TYPE_STRING
+	field1 := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("name"),
+		Number: proto.Int32(1),
+		Type:   &fieldType,
+	}
+	field2 := &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("role"),
+		Number: proto.Int32(2),
+		Type:   &fieldType,
+	}
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			field1,
+			field2,
+		},
+	}
+	meth1 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Method1"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	meth2 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Method2"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	svc1 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("Service1"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2},
+	}
+	meth3 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Method3"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	meth4 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Method4"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+	svc2 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("Service2"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth3, meth4},
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("service1.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc1, svc2},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc1,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth1,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=organizations/*}/{role=roles/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field2,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "role",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: meth2,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=users/*}/{role=roles/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field2,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "role",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+			{
+				ServiceDescriptorProto: svc2,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth3,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=users/*}/roles",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+					{
+						MethodDescriptorProto: meth4,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/{name=groups/*}/{role=roles/*}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field1,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "name",
+											},
+										},
+									},
+									{
+										Target: &descriptor.Field{
+											FieldDescriptorProto: field2,
+											Message:              msg,
+										},
+										FieldPath: descriptor.FieldPath{
+											{
+												Name: "role",
+											},
+										},
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	if got, want := len(result.Paths), 4; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	firstOp := result.getPathItemObject("/v1/{name}/{role}").Get
+	if got, want := firstOp.OperationID, "Service1_Method1"; got != want {
+		t.Fatalf("First operation id differed, got %s want %s", got, want)
+	}
+	if got, want := len(firstOp.Parameters), 3; got != want {
+		t.Fatalf("First operation params length differed, got %d want %d", got, want)
+	}
+	if got, want := firstOp.Parameters[0].Name, "name"; got != want {
+		t.Fatalf("First operation first param name differed, got %s want %s", got, want)
+	}
+	if got, want := firstOp.Parameters[0].Pattern, "organizations/[^/]+"; got != want {
+		t.Fatalf("First operation first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := firstOp.Parameters[1].Name, "role"; got != want {
+		t.Fatalf("First operation second param name differed, got %s want %s", got, want)
+	}
+	if got, want := firstOp.Parameters[1].Pattern, "roles/[^/]+"; got != want {
+		t.Fatalf("First operation second param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := firstOp.Parameters[2].In, "body"; got != want {
+		t.Fatalf("First operation third param 'in' differed, got %s want %s", got, want)
+	}
+
+	secondOp := result.getPathItemObject("/v1/{name" + pathParamUniqueSuffixDeliminator + "1}/{role}").Get
+	if got, want := secondOp.OperationID, "Service1_Method2"; got != want {
+		t.Fatalf("Second operation id differed, got %s want %s", got, want)
+	}
+	if got, want := len(secondOp.Parameters), 3; got != want {
+		t.Fatalf("Second operation params length differed, got %d want %d", got, want)
+	}
+	if got, want := secondOp.Parameters[0].Name, "name"+pathParamUniqueSuffixDeliminator+"1"; got != want {
+		t.Fatalf("Second operation first param name differed, got %s want %s", got, want)
+	}
+	if got, want := secondOp.Parameters[0].Pattern, "users/[^/]+"; got != want {
+		t.Fatalf("Second operation first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := secondOp.Parameters[1].Name, "role"; got != want {
+		t.Fatalf("Second operation second param name differed, got %s want %s", got, want)
+	}
+	if got, want := secondOp.Parameters[1].Pattern, "roles/[^/]+"; got != want {
+		t.Fatalf("Second operation second param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := secondOp.Parameters[2].In, "body"; got != want {
+		t.Fatalf("Second operation third param 'in' differed, got %s want %s", got, want)
+	}
+
+	thirdOp := result.getPathItemObject("/v1/{name}/roles").Get
+	if got, want := thirdOp.OperationID, "Service2_Method3"; got != want {
+		t.Fatalf("Third operation id differed, got %s want %s", got, want)
+	}
+	if got, want := len(thirdOp.Parameters), 2; got != want {
+		t.Fatalf("Third operation params length differed, got %d want %d", got, want)
+	}
+	if got, want := thirdOp.Parameters[0].Name, "name"; got != want {
+		t.Fatalf("Third operation first param name differed, got %s want %s", got, want)
+	}
+	if got, want := thirdOp.Parameters[0].Pattern, "users/[^/]+"; got != want {
+		t.Fatalf("Third operation first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := thirdOp.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Third operation second param 'in' differed, got %s want %s", got, want)
+	}
+
+	forthOp := result.getPathItemObject("/v1/{name" + pathParamUniqueSuffixDeliminator + "2}/{role}").Get
+	if got, want := forthOp.OperationID, "Service2_Method4"; got != want {
+		t.Fatalf("Fourth operation id differed, got %s want %s", got, want)
+	}
+	if got, want := len(forthOp.Parameters), 3; got != want {
+		t.Fatalf("Fourth operation params length differed, got %d want %d", got, want)
+	}
+	if got, want := forthOp.Parameters[0].Name, "name"+pathParamUniqueSuffixDeliminator+"2"; got != want {
+		t.Fatalf("Fourth operation first param name differed, got %s want %s", got, want)
+	}
+	if got, want := forthOp.Parameters[0].Pattern, "groups/[^/]+"; got != want {
+		t.Fatalf("Fourth operation first param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := forthOp.Parameters[1].Name, "role"; got != want {
+		t.Fatalf("Fourth operation second param name differed, got %s want %s", got, want)
+	}
+	if got, want := forthOp.Parameters[1].Pattern, "roles/[^/]+"; got != want {
+		t.Fatalf("Fourth operation second param pattern differed, got %s want %s", got, want)
+	}
+	if got, want := forthOp.Parameters[2].In, "body"; got != want {
+		t.Fatalf("Fourth operation second param 'in' differed, got %s want %s", got, want)
+	}
+}
+
+func Test_getReservedJsonName(t *testing.T) {
+	type args struct {
+		fieldName                     string
+		messageNameToFieldsToJSONName map[string]map[string]string
+		fieldNameToType               map[string]string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			"test case 1: single dot use case",
+			args{
+				fieldName: "abc.a_1",
+				messageNameToFieldsToJSONName: map[string]map[string]string{
+					"Msg": {
+						"a_1": "a1JSONNAME",
+						"b_1": "b1JSONNAME",
+					},
+				},
+				fieldNameToType: map[string]string{
+					"abc": "pkg1.test.Msg",
+					"bcd": "pkg1.test.Msg",
+				},
+			},
+			"a1JSONNAME",
+		},
+		{
+			"test case 2: single dot use case with no existing field",
+			args{
+				fieldName: "abc.d_1",
+				messageNameToFieldsToJSONName: map[string]map[string]string{
+					"Msg": {
+						"a_1": "a1JSONNAME",
+						"b_1": "b1JSONNAME",
+					},
+				},
+				fieldNameToType: map[string]string{
+					"abc": "pkg1.test.Msg",
+					"bcd": "pkg1.test.Msg",
+				},
+			},
+			"",
+		},
+		{
+			"test case 3: double dot use case",
+			args{
+				fieldName: "pkg.abc.a_1",
+				messageNameToFieldsToJSONName: map[string]map[string]string{
+					"Msg": {
+						"a_1": "a1JSONNAME",
+						"b_1": "b1JSONNAME",
+					},
+				},
+				fieldNameToType: map[string]string{
+					"abc": "pkg1.test.Msg",
+					"bcd": "pkg1.test.Msg",
+				},
+			},
+			"a1JSONNAME",
+		},
+		{
+			"test case 4: double dot use case with a not existed field",
+			args{
+				fieldName: "pkg.abc.c_1",
+				messageNameToFieldsToJSONName: map[string]map[string]string{
+					"Msg": {
+						"a_1": "a1JSONNAME",
+						"b_1": "b1JSONNAME",
+					},
+				},
+				fieldNameToType: map[string]string{
+					"abc": "pkg1.test.Msg",
+					"bcd": "pkg1.test.Msg",
+				},
+			},
+			"",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getReservedJSONName(tt.args.fieldName, tt.args.messageNameToFieldsToJSONName, tt.args.fieldNameToType); got != tt.want {
+				t.Errorf("getReservedJSONName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestParseIncompleteSecurityRequirement(t *testing.T) {
+	swagger := openapi_options.Swagger{
+		Security: []*openapi_options.SecurityRequirement{
+			{
+				SecurityRequirement: map[string]*openapi_options.SecurityRequirement_SecurityRequirementValue{
+					"key": nil,
+				},
+			},
+		},
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+	}
+	proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger)
+	reg := descriptor.NewRegistry()
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Errorf("failed to reg.Load(): %v", err)
+		return
+	}
+	_, err = applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err == nil {
+		t.Errorf("applyTemplate(%#v) did not error as expected", file)
+		return
+	}
+}
+
+func TestSubPathParams(t *testing.T) {
+	outerParams := []descriptor.Parameter{
+		{
+			FieldPath: []descriptor.FieldPathComponent{
+				{
+					Name: "prefix",
+				},
+				{
+					Name: "first",
+				},
+			},
+		},
+		{
+			FieldPath: []descriptor.FieldPathComponent{
+				{
+					Name: "prefix",
+				},
+				{
+					Name: "second",
+				},
+				{
+					Name: "deeper",
+				},
+			},
+		},
+		{
+			FieldPath: []descriptor.FieldPathComponent{
+				{
+					Name: "otherprefix",
+				},
+				{
+					Name: "third",
+				},
+			},
+		},
+	}
+	subParams := subPathParams("prefix", outerParams)
+
+	if got, want := len(subParams), 2; got != want {
+		t.Fatalf("Wrong number of path params, got %d want %d", got, want)
+	}
+	if got, want := len(subParams[0].FieldPath), 1; got != want {
+		t.Fatalf("Wrong length of path param 0, got %d want %d", got, want)
+	}
+	if got, want := subParams[0].FieldPath[0].Name, "first"; got != want {
+		t.Fatalf("Wrong path param 0, element 0, got %s want %s", got, want)
+	}
+	if got, want := len(subParams[1].FieldPath), 2; got != want {
+		t.Fatalf("Wrong length of path param 1 got %d want %d", got, want)
+	}
+	if got, want := subParams[1].FieldPath[0].Name, "second"; got != want {
+		t.Fatalf("Wrong path param 1, element 0, got %s want %s", got, want)
+	}
+	if got, want := subParams[1].FieldPath[1].Name, "deeper"; got != want {
+		t.Fatalf("Wrong path param 1, element 1, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesParameterDescriptionNoFieldBody(t *testing.T) {
+	optionsRaw := `{
+			"[grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema]": {
+			  "jsonSchema": {
+				"title": "aMessage title",
+				"description": "aMessage description"
+			  }
+			}
+      	}`
+
+	options := &descriptorpb.MessageOptions{}
+	err := protojson.Unmarshal([]byte(optionsRaw), options)
+	if err != nil {
+		t.Fatalf("Error while unmarshalling options: %s", err.Error())
+	}
+
+	aMessageDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("AMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("project_id"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("other_field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+		Options: options,
+	}
+	someResponseDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("SomeResponse"),
+	}
+	aMeth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("AMethod"),
+		InputType:  proto.String("AMessage"),
+		OutputType: proto.String("SomeResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("Test"),
+		Method: []*descriptorpb.MethodDescriptorProto{aMeth},
+	}
+	aMessage := &descriptor.Message{
+		DescriptorProto: aMessageDesc,
+	}
+	someResponseMessage := &descriptor.Message{
+		DescriptorProto: someResponseDesc,
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("api"),
+			Name:           proto.String("test.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{aMessageDesc, someResponseDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{aMessage, someResponseMessage},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: aMeth,
+						RequestType:           aMessage,
+						ResponseType:          someResponseMessage,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/projects/someotherpath",
+								},
+								Body: &descriptor.Body{},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err = reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	got := result.getPathItemObject("/v1/projects/someotherpath").Post.Parameters[0].Description
+	want := "aMessage description"
+
+	if got != want {
+		t.Fatalf("Wrong description for body parameter, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesWithBodyFieldNameInCamelCase(t *testing.T) {
+	userDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("User"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("name"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("role"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	updateDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("UpdateUserRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("user_object"),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".example.User"),
+				Number:   proto.Int32(1),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("UpdateUser"),
+		InputType:  proto.String("UpdateUserRequest"),
+		OutputType: proto.String("User"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("UserService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	userMsg := &descriptor.Message{
+		DescriptorProto: userDesc,
+	}
+	updateMsg := &descriptor.Message{
+		DescriptorProto: updateDesc,
+	}
+	nameField := &descriptor.Field{
+		Message:              userMsg,
+		FieldDescriptorProto: userMsg.GetField()[0],
+	}
+	nameField.JsonName = proto.String("name")
+	roleField := &descriptor.Field{
+		Message:              userMsg,
+		FieldDescriptorProto: userMsg.GetField()[1],
+	}
+	roleField.JsonName = proto.String("role")
+	userMsg.Fields = []*descriptor.Field{nameField, roleField}
+	userField := &descriptor.Field{
+		Message:              updateMsg,
+		FieldMessage:         userMsg,
+		FieldDescriptorProto: updateMsg.GetField()[0],
+	}
+	userField.JsonName = proto.String("userObject")
+	updateMsg.Fields = []*descriptor.Field{userField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String("user_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{userDesc, updateDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{userMsg, updateMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           updateMsg,
+						ResponseType:          userMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/users/{user_object.name}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "user_object",
+											},
+											{
+												Name: "name",
+											},
+										}),
+										Target: nameField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: []descriptor.FieldPathComponent{
+										{
+											Name:   "user_object",
+											Target: userField,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/v1/users/{userObject.name}"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/v1/users/{userObject.name}").Post
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "userObject.name"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "userObject"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	// The body parameter should be inlined and not contain 'name', as this is a path parameter.
+	schema := operation.Parameters[1].Schema
+	if got, want := schema.Ref, ""; got != want {
+		t.Fatalf("Wrong reference, got %s want %s", got, want)
+	}
+	props := schema.Properties
+	if props == nil {
+		t.Fatal("No properties on body parameter")
+	}
+	if got, want := len(*props), 1; got != want {
+		t.Fatalf("Properties length differed, got %d want %d", got, want)
+	}
+	for _, v := range *props {
+		if got, want := v.Key, "role"; got != want {
+			t.Fatalf("Wrong key for property, got %s want %s", got, want)
+		}
+	}
+}
+
+func TestRenderServicesWithBodyFieldHasFieldMask(t *testing.T) {
+	userDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("User"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("name"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("role"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	updateDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("UpdateUserRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("user_object"),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".example.User"),
+				Number:   proto.Int32(1),
+			},
+			{
+				Name:     proto.String("update_mask"),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".google.protobuf.FieldMask"),
+				Number:   proto.Int32(2),
+			},
+		},
+	}
+
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("UpdateUser"),
+		InputType:  proto.String("UpdateUserRequest"),
+		OutputType: proto.String("User"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("UserService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	userMsg := &descriptor.Message{
+		DescriptorProto: userDesc,
+	}
+	updateMsg := &descriptor.Message{
+		DescriptorProto: updateDesc,
+	}
+	nameField := &descriptor.Field{
+		Message:              userMsg,
+		FieldDescriptorProto: userMsg.GetField()[0],
+	}
+	nameField.JsonName = proto.String("name")
+	roleField := &descriptor.Field{
+		Message:              userMsg,
+		FieldDescriptorProto: userMsg.GetField()[1],
+	}
+	roleField.JsonName = proto.String("role")
+	userMsg.Fields = []*descriptor.Field{nameField, roleField}
+	userField := &descriptor.Field{
+		Message:              updateMsg,
+		FieldMessage:         userMsg,
+		FieldDescriptorProto: updateMsg.GetField()[0],
+	}
+	userField.JsonName = proto.String("userObject")
+	updateMaskField := &descriptor.Field{
+		Message:              updateMsg,
+		FieldDescriptorProto: updateMsg.GetField()[1],
+	}
+	updateMaskField.JsonName = proto.String("updateMask")
+	updateMsg.Fields = []*descriptor.Field{userField, updateMaskField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String("user_service.proto"),
+			Dependency:     []string{"google/well_known.proto"},
+			MessageType:    []*descriptorpb.DescriptorProto{userDesc, updateDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{userMsg, updateMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           updateMsg,
+						ResponseType:          userMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "PATCH",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/users/{user_object.name}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "user_object",
+											},
+											{
+												Name: "name",
+											},
+										}),
+										Target: nameField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: []descriptor.FieldPathComponent{
+										{
+											Name:   "user_object",
+											Target: userField,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	reg.SetAllowPatchFeature(true)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{
+		{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("google/well_known.proto"),
+			Package:        proto.String("google.protobuf"),
+			Dependency:     []string{},
+			MessageType: []*descriptorpb.DescriptorProto{
+				protodesc.ToDescriptorProto((&field_mask.FieldMask{}).ProtoReflect().Descriptor()),
+			},
+			Service: []*descriptorpb.ServiceDescriptorProto{},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("google/well_known"),
+			},
+		},
+		file.FileDescriptorProto,
+	}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/v1/users/{userObject.name}"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/v1/users/{userObject.name}").Patch
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "userObject.name"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "userObject"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesWithColonInPath(t *testing.T) {
+	jsonSchema := &openapi_options.JSONSchema{
+		FieldConfiguration: &openapi_options.JSONSchema_FieldConfiguration{
+			PathParamName: "overrideField",
+		},
+	}
+	fieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, jsonSchema)
+
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:    proto.String("field"),
+				Type:    descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number:  proto.Int32(1),
+				Options: fieldOptions,
+			},
+		},
+	}
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/my/{field}:foo",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "field",
+											},
+										}),
+										Target: reqField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/my/{overrideField}:foo"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/my/{overrideField}:foo").Post
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "overrideField"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Type, "string"; got != want {
+		t.Fatalf("Wrong parameter type, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "body"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesWithDoubleColonInPath(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/my/{field}:foo:bar",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "field",
+											},
+										}),
+										Target: reqField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/my/{field}:foo:bar"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/my/{field}:foo:bar").Post
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "field"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Type, "string"; got != want {
+		t.Fatalf("Wrong parameter type, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "body"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesWithColonLastInPath(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/my/{field}:",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "field",
+											},
+										}),
+										Target: reqField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/my/{field}:"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/my/{field}:").Post
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "field"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Type, "string"; got != want {
+		t.Fatalf("Wrong parameter type, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "body"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServicesWithColonInSegment(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/my/{field=segment/wi:th}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "field",
+											},
+										}),
+										Target: reqField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(reqFromFile(&file))
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/my/{field}"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/my/{field}").Post
+	if got, want := len(operation.Parameters), 2; got != want {
+		t.Fatalf("Parameters length differed, got %d want %d", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Name, "field"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].Type, "string"; got != want {
+		t.Fatalf("Wrong parameter type, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "body"; got != want {
+		t.Fatalf("Wrong parameter name, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location, got %s want %s", got, want)
+	}
+}
+
+func TestRenderServiceWithHeaderParameters(t *testing.T) {
+	file := func() descriptor.File {
+		msgdesc := &descriptorpb.DescriptorProto{
+			Name: proto.String("ExampleMessage"),
+		}
+
+		meth := &descriptorpb.MethodDescriptorProto{
+			Name:       proto.String("Example"),
+			InputType:  proto.String("ExampleMessage"),
+			OutputType: proto.String("ExampleMessage"),
+			Options:    &descriptorpb.MethodOptions{},
+		}
+
+		svc := &descriptorpb.ServiceDescriptorProto{
+			Name:   proto.String("ExampleService"),
+			Method: []*descriptorpb.MethodDescriptorProto{meth},
+		}
+
+		msg := &descriptor.Message{
+			DescriptorProto: msgdesc,
+		}
+
+		return descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("example.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+				},
+			},
+			GoPkg: descriptor.GoPackage{
+				Path: "example.com/path/to/example/example.pb",
+				Name: "example_pb",
+			},
+			Messages: []*descriptor.Message{msg},
+			Services: []*descriptor.Service{
+				{
+					ServiceDescriptorProto: svc,
+					Methods: []*descriptor.Method{
+						{
+							MethodDescriptorProto: meth,
+							RequestType:           msg,
+							ResponseType:          msg,
+							Bindings: []*descriptor.Binding{
+								{
+									HTTPMethod: "GET",
+									PathTmpl: httprule.Template{
+										Version:  1,
+										OpCodes:  []int{0, 0},
+										Template: "/v1/echo",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+	}
+
+	type test struct {
+		file             func() descriptor.File
+		openapiOperation *openapi_options.Operation
+		parameters       openapiParametersObject
+	}
+
+	tests := map[string]*test{
+		"type string": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name: "X-Custom-Header",
+							Type: openapi_options.HeaderParameter_STRING,
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name: "X-Custom-Header",
+					In:   "header",
+					Type: "string",
+				},
+			},
+		},
+		"type string with format": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name:   "X-Custom-Header",
+							Type:   openapi_options.HeaderParameter_STRING,
+							Format: "uuid",
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name:   "X-Custom-Header",
+					In:     "header",
+					Type:   "string",
+					Format: "uuid",
+				},
+			},
+		},
+		"type integer": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name: "X-Custom-Header",
+							Type: openapi_options.HeaderParameter_INTEGER,
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name: "X-Custom-Header",
+					In:   "header",
+					Type: "integer",
+				},
+			},
+		},
+		"type number": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name: "X-Custom-Header",
+							Type: openapi_options.HeaderParameter_NUMBER,
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name: "X-Custom-Header",
+					In:   "header",
+					Type: "number",
+				},
+			},
+		},
+		"type boolean": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name: "X-Custom-Header",
+							Type: openapi_options.HeaderParameter_BOOLEAN,
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name: "X-Custom-Header",
+					In:   "header",
+					Type: "boolean",
+				},
+			},
+		},
+		"header required": {
+			file: file,
+			openapiOperation: &openapi_options.Operation{
+				Parameters: &openapi_options.Parameters{
+					Headers: []*openapi_options.HeaderParameter{
+						{
+							Name:     "X-Custom-Header",
+							Required: true,
+							Type:     openapi_options.HeaderParameter_STRING,
+						},
+					},
+				},
+			},
+			parameters: openapiParametersObject{
+				{
+					Name:     "X-Custom-Header",
+					In:       "header",
+					Required: true,
+					Type:     "string",
+				},
+			},
+		},
+	}
+
+	for name, test := range tests {
+		test := test
+
+		t.Run(name, func(t *testing.T) {
+			file := test.file()
+
+			proto.SetExtension(
+				proto.Message(file.Services[0].Methods[0].Options),
+				openapi_options.E_Openapiv2Operation,
+				test.openapiOperation)
+
+			reg := descriptor.NewRegistry()
+
+			fileCL := crossLinkFixture(&file)
+
+			err := reg.Load(reqFromFile(fileCL))
+			if err != nil {
+				t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+			}
+
+			result, err := applyTemplate(param{File: fileCL, reg: reg})
+			if err != nil {
+				t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+			}
+
+			params := result.getPathItemObject("/v1/echo").Get.Parameters
+
+			if !reflect.DeepEqual(params, test.parameters) {
+				t.Errorf("expected %+v, got %+v", test.parameters, params)
+			}
+		})
+	}
+}
+
+func GetPaths(req *openapiSwaggerObject) []string {
+	paths := make([]string, len(req.Paths))
+	i := 0
+	for _, k := range req.Paths {
+		paths[i] = k.Path
+		i++
+	}
+	return paths
+}
+
+func TestRenderServicesOpenapiPathsOrderPreserved(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth1 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod1"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	meth2 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod2"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth1,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/c/cpath",
+								},
+							},
+						},
+					}, {
+						MethodDescriptorProto: meth2,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/b/bpath",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetPreserveRPCOrder(true)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := result.Paths
+
+	firstRPCPath := file.Services[0].Methods[0].Bindings[0].PathTmpl.Template
+	secondRPCPath := file.Services[0].Methods[1].Bindings[0].PathTmpl.Template
+	for i, pathData := range paths {
+		switch i {
+		case 0:
+			if got, want := pathData.Path, firstRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 1:
+			if got, want := pathData.Path, secondRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		}
+	}
+}
+
+func TestRenderServicesOpenapiPathsOrderPreservedMultipleServices(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth1 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod1"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	meth2 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod2"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	meth3 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod3"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	meth4 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod4"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+
+	svc1 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyServiceOne"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2},
+	}
+	svc2 := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyServiceTwo"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth3, meth4},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc1, svc2},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc1,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth1,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/g/gpath",
+								},
+							},
+						},
+					}, {
+						MethodDescriptorProto: meth2,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/f/fpath",
+								},
+							},
+						},
+					},
+				},
+			}, {
+				ServiceDescriptorProto: svc1,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth3,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/c/cpath",
+								},
+							},
+						},
+					}, {
+						MethodDescriptorProto: meth4,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/b/bpath",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetPreserveRPCOrder(true)
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := result.Paths
+
+	firstRPCPath := file.Services[0].Methods[0].Bindings[0].PathTmpl.Template
+	secondRPCPath := file.Services[0].Methods[1].Bindings[0].PathTmpl.Template
+	thirdRPCPath := file.Services[1].Methods[0].Bindings[0].PathTmpl.Template
+	fourthRPCPath := file.Services[1].Methods[1].Bindings[0].PathTmpl.Template
+	for i, pathData := range paths {
+		switch i {
+		case 0:
+			if got, want := pathData.Path, firstRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 1:
+			if got, want := pathData.Path, secondRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 2:
+			if got, want := pathData.Path, thirdRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 3:
+			if got, want := pathData.Path, fourthRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		}
+	}
+}
+
+func TestRenderServicesOpenapiPathsOrderPreservedAdditionalBindings(t *testing.T) {
+	reqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyRequest"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+
+	resDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("MyResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("field"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+		},
+	}
+	meth1 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod1"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+	meth2 := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("MyMethod2"),
+		InputType:  proto.String("MyRequest"),
+		OutputType: proto.String("MyResponse"),
+	}
+
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("MyService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2},
+	}
+	reqMsg := &descriptor.Message{
+		DescriptorProto: reqDesc,
+	}
+	resMsg := &descriptor.Message{
+		DescriptorProto: resDesc,
+	}
+	reqField := &descriptor.Field{
+		Message:              reqMsg,
+		FieldDescriptorProto: reqMsg.GetField()[0],
+	}
+	resField := &descriptor.Field{
+		Message:              resMsg,
+		FieldDescriptorProto: resMsg.GetField()[0],
+	}
+	reqField.JsonName = proto.String("field")
+	resField.JsonName = proto.String("field")
+	reqMsg.Fields = []*descriptor.Field{reqField}
+	resMsg.Fields = []*descriptor.Field{resField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Package:        proto.String("example"),
+			Name:           proto.String(",my_service.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{reqDesc, resDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{reqMsg, resMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth1,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/c/cpath",
+								},
+							}, {
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/additionalbinding",
+								},
+							},
+						},
+					}, {
+						MethodDescriptorProto: meth2,
+						RequestType:           reqMsg,
+						ResponseType:          resMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/b/bpath",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetPreserveRPCOrder(true)
+	reg.SetUseJSONNamesForFields(true)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}})
+	if err != nil {
+		t.Fatalf("failed to reg.Load(): %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := result.Paths
+	if err != nil {
+		t.Fatalf("failed to obtain extension paths: %v", err)
+	}
+
+	firstRPCPath := file.Services[0].Methods[0].Bindings[0].PathTmpl.Template
+	firstRPCPathAdditionalBinding := file.Services[0].Methods[0].Bindings[1].PathTmpl.Template
+	secondRPCPath := file.Services[0].Methods[1].Bindings[0].PathTmpl.Template
+	for i, pathData := range paths {
+		switch i {
+		case 0:
+			if got, want := pathData.Path, firstRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 1:
+			if got, want := pathData.Path, firstRPCPathAdditionalBinding; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		case 2:
+			if got, want := pathData.Path, secondRPCPath; got != want {
+				t.Fatalf("RPC path order not preserved, got %s want %s", got, want)
+			}
+		}
+	}
+}
+
+func TestRenderServicesOpenapiRequiredBodyFieldContainingPathParam(t *testing.T) {
+	fieldBehaviorRequired := []annotations.FieldBehavior{annotations.FieldBehavior_REQUIRED}
+	requiredFieldOptions := new(descriptorpb.FieldOptions)
+	proto.SetExtension(requiredFieldOptions, annotations.E_FieldBehavior, fieldBehaviorRequired)
+
+	bookDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("Book"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:   proto.String("name"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(1),
+			},
+			{
+				Name:   proto.String("type"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				Number: proto.Int32(2),
+			},
+		},
+	}
+	addBookReqDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("AddBookReq"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("book"),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".Book"),
+				Number:   proto.Int32(1),
+				Options:  requiredFieldOptions,
+			},
+			{
+				Name:    proto.String("libraryId"),
+				Type:    descriptorpb.FieldDescriptorProto_TYPE_UINT32.Enum(),
+				Number:  proto.Int32(2),
+				Options: requiredFieldOptions,
+			},
+			{
+				Name:   proto.String("isLatestEdition"),
+				Type:   descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
+				Number: proto.Int32(3),
+			},
+		},
+	}
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("AddBook"),
+		InputType:  proto.String("AddBookReq"),
+		OutputType: proto.String("Book"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("BookService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	bookMsg := &descriptor.Message{
+		DescriptorProto: bookDesc,
+	}
+	addBookReqMsg := &descriptor.Message{
+		DescriptorProto: addBookReqDesc,
+	}
+
+	nameField := &descriptor.Field{
+		Message:              bookMsg,
+		FieldDescriptorProto: bookMsg.GetField()[0],
+	}
+	typeField := &descriptor.Field{
+		Message:              bookMsg,
+		FieldDescriptorProto: bookMsg.GetField()[1],
+	}
+	bookMsg.Fields = []*descriptor.Field{nameField, typeField}
+
+	bookField := &descriptor.Field{
+		Message:              addBookReqMsg,
+		FieldMessage:         bookMsg,
+		FieldDescriptorProto: addBookReqMsg.GetField()[0],
+	}
+	libraryIdField := &descriptor.Field{
+		Message:              addBookReqMsg,
+		FieldDescriptorProto: addBookReqMsg.GetField()[1],
+	}
+	isLatestEditionField := &descriptor.Field{
+		Message:              addBookReqMsg,
+		FieldDescriptorProto: addBookReqMsg.GetField()[2],
+	}
+	addBookReqMsg.Fields = []*descriptor.Field{bookField, libraryIdField, isLatestEditionField}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("book.proto"),
+			MessageType:    []*descriptorpb.DescriptorProto{bookDesc, addBookReqDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{bookMsg, addBookReqMsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           addBookReqMsg,
+						ResponseType:          bookMsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/books/{book.type}",
+								},
+								PathParams: []descriptor.Parameter{
+									{
+										FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{
+											{
+												Name: "book",
+											},
+											{
+												Name: "type",
+											},
+										}),
+										Target: typeField,
+									},
+								},
+								Body: &descriptor.Body{
+									FieldPath: []descriptor.FieldPathComponent{},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(reqFromFile(fileCL))
+	if err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+		return
+	}
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	paths := GetPaths(result)
+	if got, want := len(paths), 1; got != want {
+		t.Fatalf("Results path length differed, got %d want %d", got, want)
+	}
+
+	if got, want := paths[0], "/v1/books/{book.type}"; got != want {
+		t.Fatalf("Wrong results path, got %s want %s", got, want)
+	}
+
+	operation := *result.getPathItemObject("/v1/books/{book.type}").Post
+
+	if got, want := operation.Parameters[0].Name, "book.type"; got != want {
+		t.Fatalf("Wrong parameter name 0, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[0].In, "path"; got != want {
+		t.Fatalf("Wrong parameter location 0, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].Name, "body"; got != want {
+		t.Fatalf("Wrong parameter name 1, got %s want %s", got, want)
+	}
+
+	if got, want := operation.Parameters[1].In, "body"; got != want {
+		t.Fatalf("Wrong parameter location 1, got %s want %s", got, want)
+	}
+
+	if want, is, name := "#/definitions/BookServiceAddBookBody", operation.Parameters[1].Schema.schemaCore.Ref, "operation.Parameters[1].Schema.schemaCore.Ref"; !reflect.DeepEqual(is, want) {
+		t.Fatalf("%s = %s want to be %s", name, want, is)
+	}
+
+	definition, found := result.Definitions["BookServiceAddBookBody"]
+	if !found {
+		t.Fatalf("expecting definition to contain BookServiceAddBookBody")
+	}
+
+	if want, is, name := 3, len(*definition.Properties), "len(*definition.Properties)"; !reflect.DeepEqual(is, want) {
+		t.Fatalf("%s = %d want to be %d", name, want, is)
+	}
+
+	for index, keyValue := range []string{"book", "libraryId", "isLatestEdition"} {
+		if got, want := (*definition.Properties)[index].Key, keyValue; got != want {
+			t.Fatalf("Wrong definition property %d, got %s want %s", index, got, want)
+		}
+	}
+
+	correctRequiredFields := []string{"book", "libraryId"}
+	if got, want := definition.Required, correctRequiredFields; !reflect.DeepEqual(got, want) {
+		t.Fatalf("Wrong required fields in body definition, got = %s, want = %s", got, want)
+	}
+}
+
+func TestArrayMessageItemsType(t *testing.T) {
+	msgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("children"),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".example.ExampleMessage"),
+				Number:   proto.Int32(1),
+				JsonName: proto.String("children"),
+			},
+		},
+	}
+
+	nestDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("NestDescMessage"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("children"),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".example.ExampleMessage"),
+				Number:   proto.Int32(1),
+				JsonName: proto.String("children"),
+			},
+		},
+	}
+
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("NestDescMessage"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: msgDesc,
+	}
+	nsg := &descriptor.Message{
+		DescriptorProto: nestDesc,
+	}
+	msg.Fields = []*descriptor.Field{
+		{
+			Message:              msg,
+			FieldDescriptorProto: msg.GetField()[0],
+		},
+	}
+	nsg.Fields = []*descriptor.Field{
+		{
+			Message:              nsg,
+			FieldDescriptorProto: nsg.GetField()[0],
+		},
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgDesc, nestDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg, nsg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          nsg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								Body: &descriptor.Body{
+									FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}),
+								},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo", // TODO(achew22): Figure out what this should really be
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(true)
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	if err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{
+			{
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				Name:           proto.String("acme/example.proto"),
+				Package:        proto.String("example"),
+				MessageType:    []*descriptorpb.DescriptorProto{msgDesc, nestDesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("acme/example"),
+				},
+			},
+		},
+	}); err != nil {
+		t.Errorf("reg.Load(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	expect := openapiDefinitionsObject{
+		"rpcStatus": openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+			Properties: &openapiSchemaObjectProperties{
+				keyVal{
+					Key: "code",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type:   "integer",
+							Format: "int32",
+						},
+					},
+				},
+				keyVal{
+					Key: "message",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type: "string",
+						},
+					},
+				},
+				keyVal{
+					Key: "details",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type: "array",
+							Items: &openapiItemsObject{
+								schemaCore: schemaCore{
+									Type: "object",
+									Ref:  "#/definitions/protobufAny",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"exampleExampleMessage": openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+			Properties: &openapiSchemaObjectProperties{
+				keyVal{
+					Key: "children",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type: "array",
+							Items: &openapiItemsObject{
+								schemaCore: schemaCore{
+									Type: "object",
+									Ref:  "#/definitions/exampleExampleMessage",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"exampleNestDescMessage": openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+			Properties: &openapiSchemaObjectProperties{
+				keyVal{
+					Key: "children",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type: "array",
+							Items: &openapiItemsObject{
+								schemaCore: schemaCore{
+									Type: "object",
+									Ref:  "#/definitions/exampleExampleMessage",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"protobufAny": openapiSchemaObject{
+			schemaCore: schemaCore{
+				Type: "object",
+			},
+			Properties: &openapiSchemaObjectProperties{
+				keyVal{
+					Key: "@type",
+					Value: openapiSchemaObject{
+						schemaCore: schemaCore{
+							Type: "string",
+						},
+					},
+				},
+			},
+			AdditionalProperties: &openapiSchemaObject{},
+		},
+	}
+
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+	if want, is, name := expect, result.Definitions, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, is, want)
+	}
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestQueryParameterType(t *testing.T) {
+	ntDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("AddressEntry"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("key"),
+				Number:   proto.Int32(1),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				JsonName: proto.String("key"),
+			},
+			{
+				Name:     proto.String("value"),
+				Number:   proto.Int32(2),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				JsonName: proto.String("value"),
+			},
+		},
+		Options: &descriptorpb.MessageOptions{
+			MapEntry: proto.Bool(true),
+		},
+	}
+
+	msgDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("Person"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("Address"),
+				Number:   proto.Int32(1),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+				TypeName: proto.String(".example.com.Person.AddressEntry"),
+				JsonName: proto.String("Address"),
+			},
+		},
+		NestedType: []*descriptorpb.DescriptorProto{
+			ntDesc,
+		},
+	}
+
+	nesteDesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleResponse"),
+		Field: []*descriptorpb.FieldDescriptorProto{
+			{
+				Name:     proto.String("Key"),
+				Number:   proto.Int32(1),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+				JsonName: proto.String("Key"),
+			},
+			{
+				Name:     proto.String("Value"),
+				Number:   proto.Int32(2),
+				Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+				Type:     descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+				JsonName: proto.String("Value"),
+			},
+		},
+	}
+
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("Person"),
+		OutputType: proto.String("ExampleResponse"),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: msgDesc,
+	}
+	nt := &descriptor.Message{
+		DescriptorProto: ntDesc,
+	}
+	nest := &descriptor.Message{
+		DescriptorProto: nesteDesc,
+	}
+	msg.Fields = []*descriptor.Field{
+		{
+			Message:              msg,
+			FieldDescriptorProto: msg.GetField()[0],
+		},
+	}
+	nt.Fields = []*descriptor.Field{
+		{
+			Message:              nt,
+			FieldDescriptorProto: msg.GetField()[0],
+		},
+	}
+	nest.Fields = []*descriptor.Field{
+		{
+			Message:              nest,
+			FieldDescriptorProto: nest.GetField()[0],
+		},
+		{
+			Message:              nest,
+			FieldDescriptorProto: nest.GetField()[1],
+		},
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("person.proto"),
+			Package:        proto.String("example.com"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgDesc, nesteDesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg, nest},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          nest,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	expect := openapiPathsObject{{
+		Path: "/v1/echo",
+		PathItemObject: openapiPathItemObject{
+			Get: &openapiOperationObject{
+				Parameters: openapiParametersObject{
+					{
+						Name: "Address[string]",
+						In:   "query",
+						Type: "integer",
+					},
+				},
+			},
+		},
+	}}
+
+	reg := descriptor.NewRegistry()
+	reg.SetUseJSONNamesForFields(false)
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	fileCL := crossLinkFixture(&file)
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{
+			{
+				Name:           proto.String("person.proto"),
+				Package:        proto.String("example.com"),
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+				MessageType:    []*descriptorpb.DescriptorProto{msgDesc, nesteDesc},
+				Service:        []*descriptorpb.ServiceDescriptorProto{},
+				Options: &descriptorpb.FileOptions{
+					GoPackage: proto.String("person.proto"),
+				},
+			},
+		},
+	})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	result, err := applyTemplate(param{File: fileCL, reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+	if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want)
+	}
+
+	if want, is, name := expect[0].PathItemObject.Get.Parameters, result.getPathItemObject("/v1/echo").Get.Parameters, "Produces"; !reflect.DeepEqual(is, want) {
+		t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, is, want)
+	}
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+func TestApplyTemplateRequestWithServerStreamingHttpBody(t *testing.T) {
+	meth := &descriptorpb.MethodDescriptorProto{
+		Name:            proto.String("Echo"),
+		InputType:       proto.String(".google.api.HttpBody"),
+		OutputType:      proto.String(".google.api.HttpBody"),
+		ClientStreaming: proto.Bool(false),
+		ServerStreaming: proto.Bool(true),
+	}
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:   proto.String("ExampleService"),
+		Method: []*descriptorpb.MethodDescriptorProto{meth},
+	}
+	httpBodyFile, err := protoregistry.GlobalFiles.FindFileByPath("google/api/httpbody.proto")
+	if err != nil {
+		t.Fatal(err)
+	}
+	httpBodyFile.SourceLocations()
+	desc, err := protoregistry.GlobalFiles.FindDescriptorByName("google.api.HttpBody")
+	if err != nil {
+		t.Fatal(err)
+	}
+	msg := &descriptor.Message{
+		DescriptorProto: protodesc.ToDescriptorProto(desc.(protoreflect.MessageDescriptor)),
+		File: &descriptor.File{
+			FileDescriptorProto: protodesc.ToFileDescriptorProto(httpBodyFile),
+		},
+	}
+	anyFile, err := protoregistry.GlobalFiles.FindFileByPath("google/protobuf/any.proto")
+	if err != nil {
+		t.Fatal(err)
+	}
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			Dependency: []string{
+				"google/api/httpbody.proto",
+			},
+			Service: []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: meth,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "POST",
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/echo",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	reg := descriptor.NewRegistry()
+	if err := AddErrorDefs(reg); err != nil {
+		t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err)
+		return
+	}
+	err = reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{
+			protodesc.ToFileDescriptorProto(anyFile),
+			protodesc.ToFileDescriptorProto(httpBodyFile),
+			file.FileDescriptorProto,
+		},
+	})
+	if err != nil {
+		t.Fatalf("failed to load code generator request: %v", err)
+	}
+	result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
+		return
+	}
+
+	if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
+		t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
+	}
+
+	if _, ok := result.getPathItemObject("/v1/echo").Post.Responses["200"]; !ok {
+		t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.getPathItemObject("/v1/echo").Post.Responses["200"]`)
+	} else {
+		if want, got, name := "A successful response.(streaming responses)", result.getPathItemObject("/v1/echo").Post.Responses["200"].Description, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		streamExampleExampleMessage := result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema
+		if want, got, name := "string", streamExampleExampleMessage.Type, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		if want, got, name := "binary", streamExampleExampleMessage.Format, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Format`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		if want, got, name := "Free form byte stream", streamExampleExampleMessage.Title, `result.getPathItemObject("/v1/echo").Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) {
+			t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
+		}
+		if len(*streamExampleExampleMessage.Properties) != 0 {
+			t.Errorf("applyTemplate(%#v).Properties should be empty", file)
+		}
+	}
+
+	// If there was a failure, print out the input and the json result for debugging.
+	if t.Failed() {
+		t.Errorf("had: %s", file)
+		t.Errorf("got: %s", fmt.Sprint(result))
+	}
+}
+
+// Returns the openapiPathItemObject associated with a path.
+func (so openapiSwaggerObject) getPathItemObject(path string) openapiPathItemObject {
+	for _, pathData := range so.Paths {
+		if pathData.Path == path {
+			return pathData.PathItemObject
+		}
+	}
+
+	return openapiPathItemObject{}
+}
+
+func TestGetPathItemObjectSwaggerObjectMethod(t *testing.T) {
+	testCases := [...]struct {
+		testName               string
+		swaggerObject          openapiSwaggerObject
+		path                   string
+		expectedPathItemObject openapiPathItemObject
+	}{
+		{
+			testName: "Path present in swagger object",
+			swaggerObject: openapiSwaggerObject{Paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}}},
+			path: "a/path",
+			expectedPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "A testful description",
+				},
+			},
+		}, {
+			testName: "Path not present in swaggerObject",
+			swaggerObject: openapiSwaggerObject{Paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}}},
+			path:                   "b/path",
+			expectedPathItemObject: openapiPathItemObject{},
+		}, {
+			testName: "Path present in swaggerPathsObject with multiple paths",
+			swaggerObject: openapiSwaggerObject{Paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}, {
+				Path: "another/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "Another testful description",
+					},
+				},
+			}}},
+			path: "another/path",
+			expectedPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "Another testful description",
+				},
+			},
+		}, {
+			testName:               "Path not present in swaggerObject with no paths",
+			swaggerObject:          openapiSwaggerObject{},
+			path:                   "b/path",
+			expectedPathItemObject: openapiPathItemObject{},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(tc.testName, func(t *testing.T) {
+			actualPathItemObject := tc.swaggerObject.getPathItemObject(tc.path)
+			if isEqual := reflect.DeepEqual(actualPathItemObject, tc.expectedPathItemObject); !isEqual {
+				t.Fatalf("Got pathItemObject: %#v, want pathItemObject: %#v", actualPathItemObject, tc.expectedPathItemObject)
+			}
+		})
+	}
+}
+
+func TestGetPathItemObjectFunction(t *testing.T) {
+	testCases := [...]struct {
+		testName               string
+		paths                  openapiPathsObject
+		path                   string
+		expectedPathItemObject openapiPathItemObject
+		expectedIsPathPresent  bool
+	}{
+		{
+			testName: "Path present in openapiPathsObject",
+			paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}},
+			path: "a/path",
+			expectedPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "A testful description",
+				},
+			},
+			expectedIsPathPresent: true,
+		}, {
+			testName: "Path not present in openapiPathsObject",
+			paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}},
+			path:                   "b/path",
+			expectedPathItemObject: openapiPathItemObject{},
+			expectedIsPathPresent:  false,
+		}, {
+			testName: "Path present in openapiPathsObject with multiple paths",
+			paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}, {
+				Path: "another/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "Another testful description",
+					},
+				},
+			}},
+			path: "another/path",
+			expectedPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "Another testful description",
+				},
+			},
+			expectedIsPathPresent: true,
+		}, {
+			testName:               "Path not present in empty openapiPathsObject",
+			paths:                  openapiPathsObject{},
+			path:                   "b/path",
+			expectedPathItemObject: openapiPathItemObject{},
+			expectedIsPathPresent:  false,
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(tc.testName, func(t *testing.T) {
+			actualPathItemObject, actualIsPathPresent := getPathItemObject(tc.paths, tc.path)
+			if isEqual := reflect.DeepEqual(actualPathItemObject, tc.expectedPathItemObject); !isEqual {
+				t.Fatalf("Got pathItemObject: %#v, want pathItemObject: %#v", actualPathItemObject, tc.expectedPathItemObject)
+			}
+			if actualIsPathPresent != tc.expectedIsPathPresent {
+				t.Fatalf("Got isPathPresent bool: %t, want isPathPresent bool: %t", actualIsPathPresent, tc.expectedIsPathPresent)
+			}
+		})
+	}
+}
+
+func TestUpdatePaths(t *testing.T) {
+	testCases := [...]struct {
+		testName             string
+		paths                openapiPathsObject
+		pathToUpdate         string
+		newPathItemObject    openapiPathItemObject
+		expectedUpdatedPaths openapiPathsObject
+	}{
+		{
+			testName: "Path present in openapiPathsObject, pathItemObject updated.",
+			paths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}},
+			pathToUpdate: "a/path",
+			newPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "A newly updated testful description",
+				},
+			},
+			expectedUpdatedPaths: openapiPathsObject{{
+				Path: "a/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A newly updated testful description",
+					},
+				},
+			}},
+		}, {
+			testName: "Path not present in openapiPathsObject, new path data appended.",
+			paths: openapiPathsObject{{
+				Path: "c/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}},
+			pathToUpdate: "b/path",
+			newPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "A new testful description to add",
+				},
+			},
+			expectedUpdatedPaths: openapiPathsObject{{
+				Path: "c/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A testful description",
+					},
+				},
+			}, {
+				Path: "b/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A new testful description to add",
+					},
+				},
+			}},
+		}, {
+			testName:     "No paths present in openapiPathsObject, new path data appended.",
+			paths:        openapiPathsObject{},
+			pathToUpdate: "b/path",
+			newPathItemObject: openapiPathItemObject{
+				Get: &openapiOperationObject{
+					Description: "A new testful description to add",
+				},
+			},
+			expectedUpdatedPaths: openapiPathsObject{{
+				Path: "b/path",
+				PathItemObject: openapiPathItemObject{
+					Get: &openapiOperationObject{
+						Description: "A new testful description to add",
+					},
+				},
+			}},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(tc.testName, func(t *testing.T) {
+			updatePaths(&tc.paths, tc.pathToUpdate, tc.newPathItemObject)
+			if pathsCorrectlyUpdated := reflect.DeepEqual(tc.paths, tc.expectedUpdatedPaths); !pathsCorrectlyUpdated {
+				t.Fatalf("Paths not correctly updated. Want %#v, got %#v", tc.expectedUpdatedPaths, tc.paths)
+			}
+		})
+	}
+}
+
+// Test that enum values have internal comments removed
+func TestEnumValueProtoComments(t *testing.T) {
+	reg := descriptor.NewRegistry()
+	name := "kind"
+	comments := "(-- this is a comment --)"
+
+	enum := &descriptor.Enum{
+		EnumDescriptorProto: &descriptorpb.EnumDescriptorProto{
+			Name: &name,
+		},
+		File: &descriptor.File{
+			FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+				Name:    new(string),
+				Package: new(string),
+				SourceCodeInfo: &descriptorpb.SourceCodeInfo{
+					Location: []*descriptorpb.SourceCodeInfo_Location{
+						{
+							LeadingComments: &comments,
+						},
+					},
+				},
+			},
+		},
+	}
+	comments = enumValueProtoComments(reg, enum)
+	if comments != "" {
+		t.Errorf("expected '', got '%v'", comments)
+	}
+}
+
+func MustMarshal(v interface{}) []byte {
+	b, err := json.Marshal(v)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+func TestMergeTags(t *testing.T) {
+	testCases := [...]struct {
+		testName           string
+		existingTags       []openapiTagObject
+		newTags            []openapiTagObject
+		expectedMergedTags []openapiTagObject
+	}{
+		{
+			testName: "Simple merge.",
+			existingTags: []openapiTagObject{{
+				Name:        "tag1",
+				Description: "tag1 description",
+			}},
+			newTags: []openapiTagObject{{
+				Name:        "tag2",
+				Description: "tag2 description",
+			}},
+			expectedMergedTags: []openapiTagObject{{
+				Name:        "tag1",
+				Description: "tag1 description",
+			}, {
+				Name:        "tag2",
+				Description: "tag2 description",
+			}},
+		},
+		{
+			testName: "Merge description",
+			existingTags: []openapiTagObject{{
+				Name:        "tag1",
+				Description: "tag1 description",
+			}, {
+				Name: "tag2",
+			}, {
+				Name:        "tag3",
+				Description: "tag3 description",
+			}},
+			newTags: []openapiTagObject{{
+				Name:        "tag2",
+				Description: "tag2 description",
+			}},
+			expectedMergedTags: []openapiTagObject{{
+				Name:        "tag1",
+				Description: "tag1 description",
+			}, {
+				Name:        "tag2",
+				Description: "tag2 description",
+			}, {
+				Name:        "tag3",
+				Description: "tag3 description",
+			}},
+		},
+		{
+			testName: "Merge external docs",
+			existingTags: []openapiTagObject{{
+				Name:         "tag1",
+				ExternalDocs: &openapiExternalDocumentationObject{},
+			}, {
+				Name: "tag2",
+			}, {
+				Name: "tag3",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag3 description",
+				},
+			}, {
+				Name: "tag4",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					URL: "tag4 url",
+				},
+			}},
+			newTags: []openapiTagObject{{
+				Name: "tag1",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag1 description",
+				},
+			}, {
+				Name: "tag2",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag2 description",
+					URL:         "tag2 url",
+				},
+			}, {
+				Name: "tag3",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "ignored tag3 description",
+					URL:         "tag3 url",
+				},
+			}, {
+				Name: "tag4",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag4 description",
+				},
+			}},
+			expectedMergedTags: []openapiTagObject{{
+				Name: "tag1",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag1 description",
+				},
+			}, {
+				Name: "tag2",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag2 description",
+					URL:         "tag2 url",
+				},
+			}, {
+				Name: "tag3",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag3 description",
+					URL:         "tag3 url",
+				},
+			}, {
+				Name: "tag4",
+				ExternalDocs: &openapiExternalDocumentationObject{
+					Description: "tag4 description",
+					URL:         "tag4 url",
+				},
+			}},
+		},
+		{
+			testName: "Merge extensions",
+			existingTags: []openapiTagObject{{
+				Name:       "tag1",
+				extensions: []extension{{key: "x-key1", value: MustMarshal("key1 extension")}},
+			}, {
+				Name: "tag2",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+					{key: "x-key2", value: MustMarshal("key2 extension")},
+				},
+			}, {
+				Name: "tag3",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+				},
+			}, {
+				Name:       "tag4",
+				extensions: nil,
+			}},
+			newTags: []openapiTagObject{{
+				Name:       "tag1",
+				extensions: []extension{{key: "x-key2", value: MustMarshal("key2 extension")}},
+			}, {
+				Name: "tag2",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+					{key: "x-key2", value: MustMarshal("ignored key2 extension")},
+					{key: "x-key3", value: MustMarshal("key3 extension")},
+				},
+			}, {
+				Name:       "tag3",
+				extensions: nil,
+			}, {
+				Name: "tag4",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+				},
+			}},
+			expectedMergedTags: []openapiTagObject{{
+				Name: "tag1",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+					{key: "x-key2", value: MustMarshal("key2 extension")},
+				},
+			}, {
+				Name: "tag2",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+					{key: "x-key2", value: MustMarshal("key2 extension")},
+					{key: "x-key3", value: MustMarshal("key3 extension")},
+				},
+			}, {
+				Name: "tag3",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+				},
+			}, {
+				Name: "tag4",
+				extensions: []extension{
+					{key: "x-key1", value: MustMarshal("key1 extension")},
+				},
+			}},
+		},
+	}
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.testName, func(t *testing.T) {
+			mergedTags := mergeTags(tc.existingTags, tc.newTags)
+			if !reflect.DeepEqual(tc.expectedMergedTags, mergedTags) {
+				t.Fatalf("%s: Tags not correctly merged. Want %#v, got %#v", tc.testName, tc.expectedMergedTags, mergedTags)
+			}
+		})
+	}
+}
+
+func TestApiVisibilityOption(t *testing.T) {
+	reg := descriptor.NewRegistry()
+
+	msgdesc := &descriptorpb.DescriptorProto{
+		Name: proto.String("ExampleMessage"),
+	}
+
+	msg := &descriptor.Message{
+		DescriptorProto: msgdesc,
+	}
+
+	methodExample := &descriptorpb.MethodDescriptorProto{
+		Name:       proto.String("Example"),
+		InputType:  proto.String("ExampleMessage"),
+		OutputType: proto.String("ExampleMessage"),
+	}
+
+	serviceOptions := &descriptorpb.ServiceOptions{}
+	proto.SetExtension(serviceOptions, visibility.E_ApiVisibility, &visibility.VisibilityRule{
+		Restriction: "INTERNAL",
+	})
+
+	svc := &descriptorpb.ServiceDescriptorProto{
+		Name:    proto.String("ExampleService"),
+		Options: serviceOptions,
+		Method:  []*descriptorpb.MethodDescriptorProto{methodExample},
+	}
+
+	file := descriptor.File{
+		FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+			SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+			Name:           proto.String("example.proto"),
+			Package:        proto.String("example"),
+			MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+			Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+			Options: &descriptorpb.FileOptions{
+				GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+			},
+		},
+		GoPkg: descriptor.GoPackage{
+			Path: "example.com/path/to/example/example.pb",
+			Name: "example_pb",
+		},
+		Messages: []*descriptor.Message{msg},
+		Services: []*descriptor.Service{
+			{
+				ServiceDescriptorProto: svc,
+				Methods: []*descriptor.Method{
+					{
+						MethodDescriptorProto: methodExample,
+						RequestType:           msg,
+						ResponseType:          msg,
+						Bindings: []*descriptor.Binding{
+							{
+								HTTPMethod: "GET",
+								Body:       &descriptor.Body{FieldPath: nil},
+								PathTmpl: httprule.Template{
+									Version:  1,
+									OpCodes:  []int{0, 0},
+									Template: "/v1/example",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	err := reg.Load(&pluginpb.CodeGeneratorRequest{
+		ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto},
+	})
+	if err != nil {
+		t.Errorf("failed to reg.Load(req): %v", err)
+	}
+
+	actual, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg})
+	if err != nil {
+		t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+	}
+
+	if len(actual.Definitions) != 0 {
+		t.Fatal("Definition should be excluded by api visibility option")
+	}
+}
+
+func TestRenderServicesOptionDeprecated(t *testing.T) {
+	testCases := [...]struct {
+		testName           string
+		methodOptions      descriptorpb.MethodOptions
+		openapiOperation   *openapi_options.Operation
+		expectedDeprecated bool
+	}{
+		{
+			testName: "method option",
+			methodOptions: descriptorpb.MethodOptions{
+				Deprecated: proto.Bool(true),
+			},
+			expectedDeprecated: true,
+		},
+		{
+			testName: "openapi option",
+			openapiOperation: &openapi_options.Operation{
+				Deprecated: true,
+			},
+			expectedDeprecated: true,
+		},
+		{
+			testName: "empty openapi doesn't override method option",
+			methodOptions: descriptorpb.MethodOptions{
+				Deprecated: proto.Bool(true),
+			},
+			openapiOperation:   &openapi_options.Operation{},
+			expectedDeprecated: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(tc.testName, func(t *testing.T) {
+			msgdesc := &descriptorpb.DescriptorProto{
+				Name: proto.String("ExampleMessage"),
+			}
+
+			meth := &descriptorpb.MethodDescriptorProto{
+				Name:       proto.String("Example"),
+				InputType:  proto.String("ExampleMessage"),
+				OutputType: proto.String("ExampleMessage"),
+				Options:    &tc.methodOptions,
+			}
+
+			svc := &descriptorpb.ServiceDescriptorProto{
+				Name:   proto.String("ExampleService"),
+				Method: []*descriptorpb.MethodDescriptorProto{meth},
+			}
+
+			msg := &descriptor.Message{
+				DescriptorProto: msgdesc,
+			}
+
+			file := descriptor.File{
+				FileDescriptorProto: &descriptorpb.FileDescriptorProto{
+					SourceCodeInfo: &descriptorpb.SourceCodeInfo{},
+					Name:           proto.String("example.proto"),
+					Package:        proto.String("example"),
+					MessageType:    []*descriptorpb.DescriptorProto{msgdesc},
+					Service:        []*descriptorpb.ServiceDescriptorProto{svc},
+					Options: &descriptorpb.FileOptions{
+						GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"),
+					},
+				},
+				GoPkg: descriptor.GoPackage{
+					Path: "example.com/path/to/example/example.pb",
+					Name: "example_pb",
+				},
+				Messages: []*descriptor.Message{msg},
+				Services: []*descriptor.Service{
+					{
+						ServiceDescriptorProto: svc,
+						Methods: []*descriptor.Method{
+							{
+								MethodDescriptorProto: meth,
+								RequestType:           msg,
+								ResponseType:          msg,
+								Bindings: []*descriptor.Binding{
+									{
+										HTTPMethod: "GET",
+										PathTmpl: httprule.Template{
+											Version:  1,
+											OpCodes:  []int{0, 0},
+											Template: "/v1/echo",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			}
+
+			if tc.openapiOperation != nil {
+				proto.SetExtension(
+					proto.Message(file.Services[0].Methods[0].Options),
+					openapi_options.E_Openapiv2Operation,
+					tc.openapiOperation,
+				)
+			}
+
+			reg := descriptor.NewRegistry()
+			reg.SetEnableRpcDeprecation(true)
+			fileCL := crossLinkFixture(&file)
+
+			if err := reg.Load(reqFromFile(fileCL)); err != nil {
+				t.Errorf("reg.Load(%#v) failed with %v; want success", file, err)
+			}
+
+			result, err := applyTemplate(param{File: fileCL, reg: reg})
+			if err != nil {
+				t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err)
+			}
+
+			got := result.getPathItemObject("/v1/echo").Get.Deprecated
+			if got != tc.expectedDeprecated {
+				t.Fatalf("Wrong deprecated field, got %v want %v", got, tc.expectedDeprecated)
+			}
+		})
+	}
+}
+
+func Test_updateSwaggerObjectFromFieldBehavior(t *testing.T) {
+	type args struct {
+		s     *openapiSchemaObject
+		j     []annotations.FieldBehavior
+		reg   *descriptor.Registry
+		field *descriptor.Field
+	}
+
+	regWithNoProto3FieldSemantics := &descriptor.Registry{}
+	regWithProto3FieldSemantics := &descriptor.Registry{}
+	regWithProto3FieldSemantics.SetUseProto3FieldSemantics(true)
+	proto3Field := &descriptor.Field{FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+		Name:   proto.String("name"),
+		Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+		Number: proto.Int32(1),
+	}}
+	boolTrue := true
+	proto3FieldOptional := &descriptor.Field{FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{
+		Name:           proto.String("name"),
+		Type:           descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+		Number:         proto.Int32(1),
+		Proto3Optional: &boolTrue,
+	}}
+	tests := []struct {
+		name     string
+		args     args
+		required []string
+	}{
+		{
+			name: "FieldBehavior_REQUIRED",
+			args: args{
+				s: &openapiSchemaObject{},
+				j: []annotations.FieldBehavior{
+					annotations.FieldBehavior_REQUIRED,
+				},
+				reg:   regWithNoProto3FieldSemantics,
+				field: proto3FieldOptional,
+			},
+			required: []string{"name"},
+		},
+		{
+			name: "No Required No Proto3 Optional",
+			args: args{
+				s:     &openapiSchemaObject{},
+				j:     []annotations.FieldBehavior{},
+				reg:   regWithNoProto3FieldSemantics,
+				field: proto3FieldOptional,
+			},
+			required: nil,
+		},
+		{
+			name: "No Required Has Proto3 Optional",
+			args: args{
+				s:     &openapiSchemaObject{},
+				j:     []annotations.FieldBehavior{},
+				reg:   regWithProto3FieldSemantics,
+				field: proto3FieldOptional,
+			},
+			required: nil,
+		},
+		{
+			name: "No Required Has Proto3 Required",
+			args: args{
+				s:     &openapiSchemaObject{},
+				j:     []annotations.FieldBehavior{},
+				reg:   regWithProto3FieldSemantics,
+				field: proto3Field,
+			},
+			required: []string{"name"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			updateSwaggerObjectFromFieldBehavior(tt.args.s, tt.args.j, tt.args.reg, tt.args.field)
+			if !reflect.DeepEqual(tt.args.s.Required, tt.required) {
+				t.Errorf("updateSwaggerObjectFromFieldBehavior() = %v, want %v", tt.args.s.Required, tt.required)
+			}
+		})
+	}
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.prototext b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.prototext
new file mode 100644
index 00000000000..63a641be2b9
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.prototext
@@ -0,0 +1,32 @@
+file_to_generate:  "your/service/v1/your_service.proto"
+proto_file:  {
+ name:  "your/service/v1/your_service.proto"
+ package:  "your.service.v1"
+ message_type:  {
+  name:  "StringMessage"
+  field:  {
+   name:  "value"
+   number:  1
+   label:  LABEL_OPTIONAL
+   type:  TYPE_STRING
+   json_name:  "value"
+  }
+ }
+ service:  {
+  name:  "YourService"
+  method:  {
+   name:  "Echo"
+   input_type:  ".your.service.v1.StringMessage"
+   output_type:  ".your.service.v1.StringMessage"
+   options:  {
+    [google.api.http]:  {
+     post:  "/api/echo"
+    }
+   }
+  }
+ }
+ options:  {
+  go_package:  "github.com/yourorg/yourprotos/gen/go/your/service/v1"
+ }
+ syntax:  "proto3"
+}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.swagger.yaml b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.swagger.yaml
new file mode 100644
index 00000000000..89b65a9007f
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/path_item_object.swagger.yaml
@@ -0,0 +1,32 @@
+swagger: "2.0"
+info:
+  title: your/service/v1/your_service.proto
+  version: version not set
+tags:
+  - name: YourService
+consumes:
+  - application/json
+produces:
+  - application/json
+paths:
+  /api/echo:
+    post:
+      operationId: YourService_Echo
+      responses:
+        "200":
+          description: A successful response.
+          schema:
+            $ref: '#/definitions/v1StringMessage'
+      parameters:
+        - name: value
+          in: query
+          required: false
+          type: string
+      tags:
+        - YourService
+definitions:
+  v1StringMessage:
+    type: object
+    properties:
+      value:
+        type: string
diff --git a/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.prototext b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.prototext
new file mode 100644
index 00000000000..42ed06f5592
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.prototext
@@ -0,0 +1,32 @@
+file_to_generate: "test/service/v1/service.proto"
+proto_file: {
+  name: "test/service/v1/service.proto"
+  package: "test.service.v1"
+  message_type: {
+    name: "TestMessage"
+    field: {
+      name: "value"
+      number: 1
+      label: LABEL_OPTIONAL
+      type: TYPE_STRING
+      json_name: "value"
+    }
+  }
+  service: {
+    name: "TestService"
+    method: {
+      name: "Test"
+      input_type: ".test.service.v1.TestMessage"
+      output_type: ".test.service.v1.TestMessage"
+      options: {
+        [google.api.http]: {
+          post: "/v1/test"
+          body: "*"
+        }
+      }
+    }
+  }
+  options: {
+    go_package: "github.com/grpc-ecosystem/grpc-gateway/v2/test/service/v1;servicev1"
+  }
+}
\ No newline at end of file
diff --git a/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.swagger.yaml b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.swagger.yaml
new file mode 100644
index 00000000000..e4230eb15fc
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/testdata/generator/x_go_type.swagger.yaml
@@ -0,0 +1,37 @@
+swagger: "2.0"
+info:
+  title: test/service/v1/service.proto
+  version: version not set
+tags:
+- name: TestService
+consumes:
+- application/json
+produces:
+- application/json
+paths:
+  /v1/test:
+    post:
+      operationId: TestService_Test
+      responses:
+        "200":
+          description: A successful response.
+          schema:
+            $ref: '#/definitions/v1TestMessage'
+      parameters:
+      - name: body
+        in: body
+        required: true
+        schema:
+          $ref: '#/definitions/v1TestMessage'
+      tags:
+      - TestService
+definitions:
+  v1TestMessage:
+    type: object
+    properties:
+      value:
+        type: string
+    x-go-type:
+      import:
+        package: "github.com/grpc-ecosystem/grpc-gateway/v2/test/service/v1"
+      type: "TestMessage"
\ No newline at end of file
diff --git a/protoc-gen-openapiv3/internal/genopenapi/types.go b/protoc-gen-openapiv3/internal/genopenapi/types.go
new file mode 100644
index 00000000000..02c85784128
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/types.go
@@ -0,0 +1,361 @@
+package genopenapi
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	"gopkg.in/yaml.v3"
+)
+
+type param struct {
+	*descriptor.File
+	reg *descriptor.Registry
+}
+
+// http://swagger.io/specification/#infoObject
+type openapiInfoObject struct {
+	Title          string `json:"title" yaml:"title"`
+	Description    string `json:"description,omitempty" yaml:"description,omitempty"`
+	TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
+	Version        string `json:"version" yaml:"version"`
+
+	Contact *openapiContactObject `json:"contact,omitempty" yaml:"contact,omitempty"`
+	License *openapiLicenseObject `json:"license,omitempty" yaml:"license,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+// https://swagger.io/specification/#tagObject
+type openapiTagObject struct {
+	Name         string                              `json:"name" yaml:"name"`
+	Description  string                              `json:"description,omitempty" yaml:"description,omitempty"`
+	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+// http://swagger.io/specification/#contactObject
+type openapiContactObject struct {
+	Name  string `json:"name,omitempty" yaml:"name,omitempty"`
+	URL   string `json:"url,omitempty" yaml:"url,omitempty"`
+	Email string `json:"email,omitempty" yaml:"email,omitempty"`
+}
+
+// http://swagger.io/specification/#licenseObject
+type openapiLicenseObject struct {
+	Name string `json:"name,omitempty" yaml:"name,omitempty"`
+	URL  string `json:"url,omitempty" yaml:"url,omitempty"`
+}
+
+// http://swagger.io/specification/#externalDocumentationObject
+type openapiExternalDocumentationObject struct {
+	Description string `json:"description,omitempty" yaml:"description,omitempty"`
+	URL         string `json:"url,omitempty" yaml:"url,omitempty"`
+}
+
+type extension struct {
+	key   string          `json:"-" yaml:"-"`
+	value json.RawMessage `json:"-" yaml:"-"`
+}
+
+// http://swagger.io/specification/#swaggerObject
+type openapiSwaggerObject struct {
+	Swagger             string                              `json:"swagger" yaml:"swagger"`
+	Info                openapiInfoObject                   `json:"info" yaml:"info"`
+	Tags                []openapiTagObject                  `json:"tags,omitempty" yaml:"tags,omitempty"`
+	Host                string                              `json:"host,omitempty" yaml:"host,omitempty"`
+	BasePath            string                              `json:"basePath,omitempty" yaml:"basePath,omitempty"`
+	Schemes             []string                            `json:"schemes,omitempty" yaml:"schemes,omitempty"`
+	Consumes            []string                            `json:"consumes" yaml:"consumes"`
+	Produces            []string                            `json:"produces" yaml:"produces"`
+	Paths               openapiPathsObject                  `json:"paths" yaml:"paths"`
+	Definitions         openapiDefinitionsObject            `json:"definitions" yaml:"definitions"`
+	SecurityDefinitions openapiSecurityDefinitionsObject    `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"`
+	Security            []openapiSecurityRequirementObject  `json:"security,omitempty" yaml:"security,omitempty"`
+	ExternalDocs        *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+// http://swagger.io/specification/#securityDefinitionsObject
+type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject
+
+// http://swagger.io/specification/#securitySchemeObject
+type openapiSecuritySchemeObject struct {
+	Type             string              `json:"type" yaml:"type"`
+	Description      string              `json:"description,omitempty" yaml:"description,omitempty"`
+	Name             string              `json:"name,omitempty" yaml:"name,omitempty"`
+	In               string              `json:"in,omitempty" yaml:"in,omitempty"`
+	Flow             string              `json:"flow,omitempty" yaml:"flow,omitempty"`
+	AuthorizationURL string              `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
+	TokenURL         string              `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
+	Scopes           openapiScopesObject `json:"scopes,omitempty" yaml:"scopes,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+// http://swagger.io/specification/#scopesObject
+type openapiScopesObject map[string]string
+
+// http://swagger.io/specification/#securityRequirementObject
+type openapiSecurityRequirementObject map[string][]string
+
+// http://swagger.io/specification/#pathsObject
+type openapiPathsObject []pathData
+
+type pathData struct {
+	Path           string
+	PathItemObject openapiPathItemObject
+}
+
+// http://swagger.io/specification/#pathItemObject
+type openapiPathItemObject struct {
+	Get     *openapiOperationObject `json:"get,omitempty" yaml:"get,omitempty"`
+	Delete  *openapiOperationObject `json:"delete,omitempty" yaml:"delete,omitempty"`
+	Post    *openapiOperationObject `json:"post,omitempty" yaml:"post,omitempty"`
+	Put     *openapiOperationObject `json:"put,omitempty" yaml:"put,omitempty"`
+	Patch   *openapiOperationObject `json:"patch,omitempty" yaml:"patch,omitempty"`
+	Head    *openapiOperationObject `json:"head,omitempty" yaml:"head,omitempty"`
+	Options *openapiOperationObject `json:"options,omitempty" yaml:"options,omitempty"`
+	// While TRACE is supported in OpenAPI v3, it is not supported in OpenAPI v2
+	// Trace   *openapiOperationObject `json:"trace,omitempty" yaml:"trace,omitempty"`
+}
+
+// http://swagger.io/specification/#operationObject
+type openapiOperationObject struct {
+	Summary     string                  `json:"summary,omitempty" yaml:"summary,omitempty"`
+	Description string                  `json:"description,omitempty" yaml:"description,omitempty"`
+	OperationID string                  `json:"operationId" yaml:"operationId"`
+	Responses   openapiResponsesObject  `json:"responses" yaml:"responses"`
+	Parameters  openapiParametersObject `json:"parameters,omitempty" yaml:"parameters,omitempty"`
+	Tags        []string                `json:"tags,omitempty" yaml:"tags,omitempty"`
+	Deprecated  bool                    `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
+	Consumes    []string                `json:"consumes,omitempty" yaml:"consumes,omitempty"`
+	Produces    []string                `json:"produces,omitempty" yaml:"produces,omitempty"`
+
+	Security     *[]openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"`
+	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+type openapiParametersObject []openapiParameterObject
+
+// http://swagger.io/specification/#parameterObject
+type openapiParameterObject struct {
+	Name             string              `json:"name" yaml:"name"`
+	Description      string              `json:"description,omitempty" yaml:"description,omitempty"`
+	In               string              `json:"in,omitempty" yaml:"in,omitempty"`
+	Required         bool                `json:"required" yaml:"required"`
+	Type             string              `json:"type,omitempty" yaml:"type,omitempty"`
+	Format           string              `json:"format,omitempty" yaml:"format,omitempty"`
+	UniqueItems      bool                `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
+	Items            *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"`
+	Enum             interface{}         `json:"enum,omitempty" yaml:"enum,omitempty"`
+	CollectionFormat string              `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"`
+	Default          interface{}         `json:"default,omitempty" yaml:"default,omitempty"`
+	MinItems         *int                `json:"minItems,omitempty" yaml:"minItems,omitempty"`
+	Pattern          string              `json:"pattern,omitempty" yaml:"pattern,omitempty"`
+
+	// Or you can explicitly refer to another type. If this is defined all
+	// other fields should be empty
+	Schema *openapiSchemaObject `json:"schema,omitempty" yaml:"schema,omitempty"`
+
+	extensions []extension
+}
+
+// core part of schema, which is common to itemsObject and schemaObject.
+// http://swagger.io/specification/v2/#itemsObject
+// The OAS3 spec (https://swagger.io/specification/#schemaObject) defines the
+// `nullable` field as part of a Schema Object. This behavior has been
+// "back-ported" to OAS2 as the Specification Extension `x-nullable`, and is
+// supported by generation tools such as swagger-codegen and go-swagger.
+// For protoc-gen-openapiv3, we'd want to add `nullable` instead.
+type schemaCore struct {
+	Type      string     `json:"type,omitempty" yaml:"type,omitempty"`
+	Format    string     `json:"format,omitempty" yaml:"format,omitempty"`
+	Ref       string     `json:"$ref,omitempty" yaml:"$ref,omitempty"`
+	XNullable bool       `json:"x-nullable,omitempty" yaml:"x-nullable,omitempty"`
+	Example   RawExample `json:"example,omitempty" yaml:"example,omitempty"`
+
+	Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"`
+
+	// If the item is an enumeration include a list of all the *NAMES* of the
+	// enum values.  I'm not sure how well this will work but assuming all enums
+	// start from 0 index it will be great. I don't think that is a good assumption.
+	Enum    interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`
+	Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
+}
+
+type allOfEntry struct {
+	Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
+}
+
+type RawExample json.RawMessage
+
+func (m RawExample) MarshalJSON() ([]byte, error) {
+	return (json.RawMessage)(m).MarshalJSON()
+}
+
+func (m *RawExample) UnmarshalJSON(data []byte) error {
+	return (*json.RawMessage)(m).UnmarshalJSON(data)
+}
+
+// MarshalYAML implements yaml.Marshaler interface.
+//
+// It converts RawExample to one of yaml-supported types and returns it.
+//
+// From yaml.Marshaler docs: The Marshaler interface may be implemented
+// by types to customize their behavior when being marshaled into a YAML
+// document. The returned value is marshaled in place of the original
+// value implementing Marshaler.
+func (e RawExample) MarshalYAML() (interface{}, error) {
+	// From docs, json.Unmarshal will store one of next types to data:
+	// - bool, for JSON booleans;
+	// - float64, for JSON numbers;
+	// - string, for JSON strings;
+	// - []interface{}, for JSON arrays;
+	// - map[string]interface{}, for JSON objects;
+	// - nil for JSON null.
+	var data interface{}
+	if err := json.Unmarshal(e, &data); err != nil {
+		return nil, err
+	}
+
+	return data, nil
+}
+
+func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error {
+	name, ok := fullyQualifiedNameToOpenAPIName(ref, reg)
+	if !ok {
+		return fmt.Errorf("setRefFromFQN: can't resolve OpenAPI name from %q", ref)
+	}
+	s.Ref = fmt.Sprintf("#/definitions/%s", name)
+	return nil
+}
+
+type openapiItemsObject openapiSchemaObject
+
+// http://swagger.io/specification/#responsesObject
+type openapiResponsesObject map[string]openapiResponseObject
+
+// http://swagger.io/specification/#responseObject
+type openapiResponseObject struct {
+	Description string                 `json:"description" yaml:"description"`
+	Schema      openapiSchemaObject    `json:"schema" yaml:"schema"`
+	Examples    map[string]interface{} `json:"examples,omitempty" yaml:"examples,omitempty"`
+	Headers     openapiHeadersObject   `json:"headers,omitempty" yaml:"headers,omitempty"`
+
+	extensions []extension `json:"-" yaml:"-"`
+}
+
+type openapiHeadersObject map[string]openapiHeaderObject
+
+// http://swagger.io/specification/#headerObject
+type openapiHeaderObject struct {
+	Description string     `json:"description,omitempty" yaml:"description,omitempty"`
+	Type        string     `json:"type,omitempty" yaml:"type,omitempty"`
+	Format      string     `json:"format,omitempty" yaml:"format,omitempty"`
+	Default     RawExample `json:"default,omitempty" yaml:"default,omitempty"`
+	Pattern     string     `json:"pattern,omitempty" yaml:"pattern,omitempty"`
+}
+
+type keyVal struct {
+	Key   string
+	Value interface{}
+}
+
+type openapiSchemaObjectProperties []keyVal
+
+func (p openapiSchemaObjectProperties) MarshalYAML() (interface{}, error) {
+	n := yaml.Node{
+		Kind:    yaml.MappingNode,
+		Content: make([]*yaml.Node, len(p)*2),
+	}
+	for i, v := range p {
+		keyNode := yaml.Node{}
+		if err := keyNode.Encode(v.Key); err != nil {
+			return nil, err
+		}
+		valueNode := yaml.Node{}
+		if err := valueNode.Encode(v.Value); err != nil {
+			return nil, err
+		}
+		n.Content[i*2+0] = &keyNode
+		n.Content[i*2+1] = &valueNode
+	}
+	return n, nil
+}
+
+func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) {
+	var buf bytes.Buffer
+	buf.WriteString("{")
+	for i, kv := range op {
+		if i != 0 {
+			buf.WriteString(",")
+		}
+		key, err := json.Marshal(kv.Key)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(key)
+		buf.WriteString(":")
+		val, err := json.Marshal(kv.Value)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(val)
+	}
+
+	buf.WriteString("}")
+	return buf.Bytes(), nil
+}
+
+// http://swagger.io/specification/#schemaObject
+type openapiSchemaObject struct {
+	schemaCore `yaml:",inline"`
+	// Properties can be recursively defined
+	Properties           *openapiSchemaObjectProperties `json:"properties,omitempty" yaml:"properties,omitempty"`
+	AdditionalProperties *openapiSchemaObject           `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"`
+
+	Description string `json:"description,omitempty" yaml:"description,omitempty"`
+	Title       string `json:"title,omitempty" yaml:"title,omitempty"`
+
+	ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+
+	ReadOnly         bool     `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
+	MultipleOf       float64  `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
+	Maximum          float64  `json:"maximum,omitempty" yaml:"maximum,omitempty"`
+	ExclusiveMaximum bool     `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"`
+	Minimum          float64  `json:"minimum,omitempty" yaml:"minimum,omitempty"`
+	ExclusiveMinimum bool     `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"`
+	MaxLength        uint64   `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
+	MinLength        uint64   `json:"minLength,omitempty" yaml:"minLength,omitempty"`
+	Pattern          string   `json:"pattern,omitempty" yaml:"pattern,omitempty"`
+	MaxItems         uint64   `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
+	MinItems         uint64   `json:"minItems,omitempty" yaml:"minItems,omitempty"`
+	UniqueItems      bool     `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
+	MaxProperties    uint64   `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
+	MinProperties    uint64   `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
+	Required         []string `json:"required,omitempty" yaml:"required,omitempty"`
+
+	extensions []extension
+
+	AllOf []allOfEntry `json:"allOf,omitempty" yaml:"allOf,omitempty"`
+}
+
+// http://swagger.io/specification/#definitionsObject
+type openapiDefinitionsObject map[string]openapiSchemaObject
+
+// Internal type mapping from FQMN to descriptor.Message. Used as a set by the
+// findServiceMessages function.
+type messageMap map[string]*descriptor.Message
+
+// Internal type mapping from FQEN to descriptor.Enum. Used as a set by the
+// findServiceMessages function.
+type enumMap map[string]*descriptor.Enum
+
+// Internal type to store used references.
+type refMap map[string]struct{}
diff --git a/protoc-gen-openapiv3/internal/genopenapi/types_test.go b/protoc-gen-openapiv3/internal/genopenapi/types_test.go
new file mode 100644
index 00000000000..44596d52117
--- /dev/null
+++ b/protoc-gen-openapiv3/internal/genopenapi/types_test.go
@@ -0,0 +1,112 @@
+package genopenapi
+
+import (
+	"encoding/json"
+	"strings"
+	"testing"
+
+	"gopkg.in/yaml.v3"
+)
+
+func newSpaceReplacer() *strings.Replacer {
+	return strings.NewReplacer(" ", "", "\n", "", "\t", "")
+}
+
+func TestRawExample(t *testing.T) {
+	t.Parallel()
+
+	testCases := [...]struct {
+		In  RawExample
+		Exp string
+	}{{
+		In:  RawExample(`1`),
+		Exp: `1`,
+	}, {
+		In:  RawExample(`"1"`),
+		Exp: `"1"`,
+	}, {
+		In: RawExample(`{"hello":"worldr"}`),
+		Exp: `
+			hello:
+				worldr
+		`,
+	}}
+
+	sr := newSpaceReplacer()
+
+	for _, tc := range testCases {
+		tc := tc
+
+		t.Run(string(tc.In), func(t *testing.T) {
+			t.Parallel()
+
+			ex := tc.In
+
+			out, err := yaml.Marshal(ex)
+			switch {
+			case err != nil:
+				t.Fatalf("expect no yaml marshal error, got: %s", err)
+			case !json.Valid(tc.In):
+				t.Fatalf("json is invalid: %#q", tc.In)
+			case sr.Replace(tc.Exp) != sr.Replace(string(out)):
+				t.Fatalf("expected: %s, actual: %s", tc.Exp, out)
+			}
+
+			out, err = json.Marshal(tc.In)
+			switch {
+			case err != nil:
+				t.Fatalf("expect no json marshal error, got: %s", err)
+			case sr.Replace(string(tc.In)) != sr.Replace(string(out)):
+				t.Fatalf("expected: %s, actual: %s", tc.In, out)
+			}
+		})
+	}
+}
+
+func TestOpenapiSchemaObjectProperties(t *testing.T) {
+	t.Parallel()
+
+	v := map[string]interface{}{
+		"example": openapiSchemaObjectProperties{{
+			Key:   "test1",
+			Value: 1,
+		}, {
+			Key:   "test2",
+			Value: 2,
+		}},
+	}
+
+	t.Run("yaml", func(t *testing.T) {
+		t.Parallel()
+
+		const exp = `
+			example:
+				test1: 1
+				test2: 2
+			`
+
+		sr := newSpaceReplacer()
+
+		out, err := yaml.Marshal(v)
+		switch {
+		case err != nil:
+			t.Fatalf("expect no marshal error, got: %s", err)
+		case sr.Replace(exp) != sr.Replace(string(out)):
+			t.Fatalf("expected: %s, actual: %s", exp, out)
+		}
+	})
+
+	t.Run("json", func(t *testing.T) {
+		t.Parallel()
+
+		const exp = `{"example":{"test1":1,"test2":2}}`
+
+		got, err := json.Marshal(v)
+		switch {
+		case err != nil:
+			t.Fatalf("expect no marshal error, got: %s", err)
+		case exp != string(got):
+			t.Fatalf("expected: %s, actual: %s", exp, got)
+		}
+	})
+}
diff --git a/protoc-gen-openapiv3/main.go b/protoc-gen-openapiv3/main.go
new file mode 100644
index 00000000000..43f7593a477
--- /dev/null
+++ b/protoc-gen-openapiv3/main.go
@@ -0,0 +1,314 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"runtime/debug"
+	"strings"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/internal/genopenapi"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/pluginpb"
+)
+
+var (
+	importPrefix                   = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files")
+	file                           = flag.String("file", "-", "where to load data from")
+	allowDeleteBody                = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body")
+	grpcAPIConfiguration           = flag.String("grpc_api_configuration", "", "path to file which describes the gRPC API Configuration in YAML format")
+	allowMerge                     = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos")
+	mergeFileName                  = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge")
+	useJSONNamesForFields          = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions")
+	repeatedPathParamSeparator     = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`")
+	versionFlag                    = flag.Bool("version", false, "print the current version")
+	_                              = flag.Bool("allow_repeated_fields_in_body", true, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option. DEPRECATED: the value is ignored and always behaves as `true`.")
+	includePackageInTags           = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. If set and the `package` directive is shown in the proto file, the package name will be prepended to the service name")
+	useFQNForOpenAPIName           = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualified names from the proto definition (ie my.package.MyMessage.MyInnerMessage). DEPRECATED: prefer `openapi_naming_strategy=fqn`")
+	openAPINamingStrategy          = flag.String("openapi_naming_strategy", "", "use the given OpenAPI naming strategy. Allowed values are `legacy`, `fqn`, `simple`, `package`. If unset, either `legacy` or `fqn` are selected, depending on the value of the `fqn_for_openapi_name` flag")
+	useGoTemplate                  = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments")
+	goTemplateArgs                 = utilities.StringArrayFlag(flag.CommandLine, "go_template_args", "provide a custom value that can override a key in the Go template. Requires the `use_go_templates` option to be set")
+	ignoreComments                 = flag.Bool("ignore_comments", false, "if set, all protofile comments are excluded from output")
+	removeInternalComments         = flag.Bool("remove_internal_comments", false, "if set, removes all substrings in comments that start with `(--` and end with `--)` as specified in https://google.aip.dev/192#internal-comments")
+	disableDefaultErrors           = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling")
+	enumsAsInts                    = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values")
+	simpleOperationIDs             = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.")
+	proto3OptionalNullable         = flag.Bool("proto3_optional_nullable", false, "whether Proto3 Optional fields should be marked as x-nullable")
+	openAPIConfiguration           = flag.String("openapi_configuration", "", "path to file which describes the OpenAPI Configuration in YAML format")
+	generateUnboundMethods         = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation")
+	recursiveDepth                 = flag.Int("recursive-depth", 1000, "maximum recursion count allowed for a field type")
+	omitEnumDefaultValue           = flag.Bool("omit_enum_default_value", false, "if set, omit default enum value")
+	outputFormat                   = flag.String("output_format", string(genopenapi.FormatJSON), fmt.Sprintf("output content format. Allowed values are: `%s`, `%s`", genopenapi.FormatJSON, genopenapi.FormatYAML))
+	visibilityRestrictionSelectors = utilities.StringArrayFlag(flag.CommandLine, "visibility_restriction_selectors", "list of `google.api.VisibilityRule` visibility labels to include in the generated output when a visibility annotation is defined. Repeat this option to supply multiple values. Elements without visibility annotations are unaffected by this setting.")
+	disableServiceTags             = flag.Bool("disable_service_tags", false, "if set, disables generation of service tags. This is useful if you do not want to expose the names of your backend grpc services.")
+	disableDefaultResponses        = flag.Bool("disable_default_responses", false, "if set, disables generation of default responses. Useful if you have to support custom response codes that are not 200.")
+	useAllOfForRefs                = flag.Bool("use_allof_for_refs", false, "if set, will use allOf as container for $ref to preserve same-level properties.")
+	allowPatchFeature              = flag.Bool("allow_patch_feature", true, "whether to hide update_mask fields in PATCH requests from the generated swagger file.")
+	preserveRPCOrder               = flag.Bool("preserve_rpc_order", false, "if true, will ensure the order of paths emitted in openapi swagger files mirror the order of RPC methods found in proto files. If false, emitted paths will be ordered alphabetically.")
+	enableRpcDeprecation           = flag.Bool("enable_rpc_deprecation", false, "whether to process grpc method's deprecated option.")
+	expandSlashedPathPatterns      = flag.Bool("expand_slashed_path_patterns", false, "if set, expands path parameters with URI sub-paths into the URI. For example, \"/v1/{name=projects/*}/resource\" becomes \"/v1/projects/{project}/resource\".")
+	useProto3FieldSemantics        = flag.Bool("use_proto3_field_semantics", false, "if set, uses proto3 field semantics for the OpenAPI schema. This means that fields are required by default.")
+	generateXGoType                = flag.Bool("generate_x_go_type", false, "if set, generates x-go-type extension using the go_package option from proto files")
+
+	_ = flag.Bool("logtostderr", false, "Legacy glog compatibility. This flag is a no-op, you can safely remove it")
+)
+
+// Variables set by goreleaser at build time
+var (
+	version = "dev"
+	commit  = "unknown"
+	date    = "unknown"
+)
+
+func main() {
+	flag.Parse()
+
+	if *versionFlag {
+		if commit == "unknown" {
+			buildInfo, ok := debug.ReadBuildInfo()
+			if ok {
+				version = buildInfo.Main.Version
+				for _, setting := range buildInfo.Settings {
+					if setting.Key == "vcs.revision" {
+						commit = setting.Value
+					}
+					if setting.Key == "vcs.time" {
+						date = setting.Value
+					}
+				}
+			}
+		}
+		fmt.Printf("Version %v, commit %v, built at %v\n", version, commit, date)
+		os.Exit(0)
+	}
+
+	reg := descriptor.NewRegistry()
+	if grpclog.V(1) {
+		grpclog.Info("Processing code generator request")
+	}
+	f := os.Stdin
+	if *file != "-" {
+		var err error
+		f, err = os.Open(*file)
+		if err != nil {
+			grpclog.Fatal(err)
+		}
+	}
+	if grpclog.V(1) {
+		grpclog.Info("Parsing code generator request")
+	}
+	req, err := codegenerator.ParseRequest(f)
+	if err != nil {
+		grpclog.Fatal(err)
+	}
+	if grpclog.V(1) {
+		grpclog.Info("Parsed code generator request")
+	}
+	pkgMap := make(map[string]string)
+	if req.Parameter != nil {
+		if err := parseReqParam(req.GetParameter(), flag.CommandLine, pkgMap); err != nil {
+			grpclog.Fatalf("Error parsing flags: %v", err)
+		}
+	}
+
+	reg.SetPrefix(*importPrefix)
+	reg.SetAllowDeleteBody(*allowDeleteBody)
+	reg.SetAllowMerge(*allowMerge)
+	reg.SetMergeFileName(*mergeFileName)
+	reg.SetUseJSONNamesForFields(*useJSONNamesForFields)
+	reg.SetUseProto3FieldSemantics(*useProto3FieldSemantics)
+
+	flag.Visit(func(f *flag.Flag) {
+		if f.Name == "allow_repeated_fields_in_body" {
+			grpclog.Warning("The `allow_repeated_fields_in_body` flag is deprecated and will always behave as `true`.")
+		}
+	})
+
+	reg.SetIncludePackageInTags(*includePackageInTags)
+
+	reg.SetUseFQNForOpenAPIName(*useFQNForOpenAPIName)
+	// Set the naming strategy either directly from the flag, or via the value of the legacy fqn_for_openapi_name
+	// flag.
+	namingStrategy := *openAPINamingStrategy
+	if *useFQNForOpenAPIName {
+		if namingStrategy != "" {
+			grpclog.Fatal("The deprecated `fqn_for_openapi_name` flag must remain unset if `openapi_naming_strategy` is set.")
+		}
+		grpclog.Warning("The `fqn_for_openapi_name` flag is deprecated. Please use `openapi_naming_strategy=fqn` instead.")
+		namingStrategy = "fqn"
+	} else if namingStrategy == "" {
+		namingStrategy = "legacy"
+	}
+	if strategyFn := genopenapi.LookupNamingStrategy(namingStrategy); strategyFn == nil {
+		emitError(fmt.Errorf("invalid naming strategy %q", namingStrategy))
+		return
+	}
+
+	if *useGoTemplate && *ignoreComments {
+		emitError(fmt.Errorf("`ignore_comments` and `use_go_templates` are mutually exclusive and cannot be enabled at the same time"))
+		return
+	}
+	reg.SetUseGoTemplate(*useGoTemplate)
+	reg.SetIgnoreComments(*ignoreComments)
+	reg.SetRemoveInternalComments(*removeInternalComments)
+
+	if len(*goTemplateArgs) > 0 && !*useGoTemplate {
+		emitError(fmt.Errorf("`go_template_args` requires `use_go_templates` to be enabled"))
+		return
+	}
+	reg.SetGoTemplateArgs(*goTemplateArgs)
+
+	reg.SetOpenAPINamingStrategy(namingStrategy)
+	reg.SetEnumsAsInts(*enumsAsInts)
+	reg.SetDisableDefaultErrors(*disableDefaultErrors)
+	reg.SetSimpleOperationIDs(*simpleOperationIDs)
+	reg.SetProto3OptionalNullable(*proto3OptionalNullable)
+	reg.SetGenerateUnboundMethods(*generateUnboundMethods)
+	reg.SetRecursiveDepth(*recursiveDepth)
+	reg.SetOmitEnumDefaultValue(*omitEnumDefaultValue)
+	reg.SetVisibilityRestrictionSelectors(*visibilityRestrictionSelectors)
+	reg.SetDisableServiceTags(*disableServiceTags)
+	reg.SetDisableDefaultResponses(*disableDefaultResponses)
+	reg.SetUseAllOfForRefs(*useAllOfForRefs)
+	reg.SetAllowPatchFeature(*allowPatchFeature)
+	reg.SetPreserveRPCOrder(*preserveRPCOrder)
+	reg.SetEnableRpcDeprecation(*enableRpcDeprecation)
+	reg.SetExpandSlashedPathPatterns(*expandSlashedPathPatterns)
+	reg.SetGenerateXGoType(*generateXGoType)
+
+	if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil {
+		emitError(err)
+		return
+	}
+	for k, v := range pkgMap {
+		reg.AddPkgMap(k, v)
+	}
+
+	if *grpcAPIConfiguration != "" {
+		if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil {
+			emitError(err)
+			return
+		}
+	}
+
+	format := genopenapi.Format(*outputFormat)
+	if err := format.Validate(); err != nil {
+		emitError(err)
+		return
+	}
+
+	g := genopenapi.New(reg, format)
+
+	if err := genopenapi.AddErrorDefs(reg); err != nil {
+		emitError(err)
+		return
+	}
+
+	if err := reg.Load(req); err != nil {
+		emitError(err)
+		return
+	}
+
+	if *openAPIConfiguration != "" {
+		if err := reg.LoadOpenAPIConfigFromYAML(*openAPIConfiguration); err != nil {
+			emitError(err)
+			return
+		}
+	}
+
+	targets := make([]*descriptor.File, 0, len(req.FileToGenerate))
+	for _, target := range req.FileToGenerate {
+		f, err := reg.LookupFile(target)
+		if err != nil {
+			grpclog.Fatal(err)
+		}
+		targets = append(targets, f)
+	}
+
+	out, err := g.Generate(targets)
+	if grpclog.V(1) {
+		grpclog.Info("Processed code generator request")
+	}
+	if err != nil {
+		emitError(err)
+		return
+	}
+	emitFiles(out)
+}
+
+func emitFiles(out []*descriptor.ResponseFile) {
+	files := make([]*pluginpb.CodeGeneratorResponse_File, len(out))
+	for idx, item := range out {
+		files[idx] = item.CodeGeneratorResponse_File
+	}
+	resp := &pluginpb.CodeGeneratorResponse{File: files}
+	codegenerator.SetSupportedFeaturesOnCodeGeneratorResponse(resp)
+	emitResp(resp)
+}
+
+func emitError(err error) {
+	emitResp(&pluginpb.CodeGeneratorResponse{Error: proto.String(err.Error())})
+}
+
+func emitResp(resp *pluginpb.CodeGeneratorResponse) {
+	buf, err := proto.Marshal(resp)
+	if err != nil {
+		grpclog.Fatal(err)
+	}
+	if _, err := os.Stdout.Write(buf); err != nil {
+		grpclog.Fatal(err)
+	}
+}
+
+// parseReqParam parses a CodeGeneratorRequest parameter and adds the
+// extracted values to the given FlagSet and pkgMap. Returns a non-nil
+// error if setting a flag failed.
+func parseReqParam(param string, f *flag.FlagSet, pkgMap map[string]string) error {
+	if param == "" {
+		return nil
+	}
+	for _, p := range strings.Split(param, ",") {
+		spec := strings.SplitN(p, "=", 2)
+		if len(spec) == 1 {
+			switch spec[0] {
+			case "allow_delete_body":
+				if err := f.Set(spec[0], "true"); err != nil {
+					return fmt.Errorf("cannot set flag %s: %w", p, err)
+				}
+				continue
+			case "allow_merge":
+				if err := f.Set(spec[0], "true"); err != nil {
+					return fmt.Errorf("cannot set flag %s: %w", p, err)
+				}
+				continue
+			case "allow_repeated_fields_in_body":
+				if err := f.Set(spec[0], "true"); err != nil {
+					return fmt.Errorf("cannot set flag %s: %w", p, err)
+				}
+				continue
+			case "include_package_in_tags":
+				if err := f.Set(spec[0], "true"); err != nil {
+					return fmt.Errorf("cannot set flag %s: %w", p, err)
+				}
+				continue
+			}
+			if err := f.Set(spec[0], ""); err != nil {
+				return fmt.Errorf("cannot set flag %s: %w", p, err)
+			}
+			continue
+		}
+		name, value := spec[0], spec[1]
+		if strings.HasPrefix(name, "M") {
+			pkgMap[name[1:]] = value
+			continue
+		}
+		if err := f.Set(name, value); err != nil {
+			return fmt.Errorf("cannot set flag %s: %w", p, err)
+		}
+	}
+	return nil
+}
diff --git a/protoc-gen-openapiv3/main_test.go b/protoc-gen-openapiv3/main_test.go
new file mode 100644
index 00000000000..a6f95c628ea
--- /dev/null
+++ b/protoc-gen-openapiv3/main_test.go
@@ -0,0 +1,260 @@
+package main
+
+import (
+	"errors"
+	"flag"
+	"reflect"
+	"testing"
+)
+
+func TestParseReqParam(t *testing.T) {
+
+	testcases := []struct {
+		name                   string
+		expected               map[string]string
+		request                string
+		expectedError          error
+		allowDeleteBodyV       bool
+		allowMergeV            bool
+		includePackageInTagsV  bool
+		fileV                  string
+		importPathV            string
+		mergeFileNameV         string
+		useFQNForOpenAPINameV  bool
+		openAPINamingStrategyV string
+	}{
+		{
+			// this one must be first - with no leading clearFlags call it
+			// verifies our expectation of default values as we reset by
+			// clearFlags
+			name:                  "Test 0",
+			expected:              map[string]string{},
+			request:               "",
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "-",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 1",
+			expected:              map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"},
+			request:               "allow_delete_body,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api",
+			allowDeleteBodyV:      true,
+			allowMergeV:           true,
+			includePackageInTagsV: true,
+			fileV:                 "./foo.pb",
+			importPathV:           "/bar/baz",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 2",
+			expected:              map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"},
+			request:               "allow_delete_body=true,allow_merge=true,allow_repeated_fields_in_body=true,include_package_in_tags=true,merge_file_name=test_name,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api",
+			allowDeleteBodyV:      true,
+			allowMergeV:           true,
+			includePackageInTagsV: true,
+			fileV:                 "./foo.pb",
+			importPathV:           "/bar/baz",
+			mergeFileNameV:        "test_name",
+		},
+		{
+			name:                  "Test 3",
+			expected:              map[string]string{"a/b/c.proto": "github.com/x/y/z", "f/g/h.proto": "github.com/1/2/3/"},
+			request:               "allow_delete_body=false,allow_merge=false,Ma/b/c.proto=github.com/x/y/z,Mf/g/h.proto=github.com/1/2/3/",
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 4",
+			expected:              map[string]string{},
+			request:               "",
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 5",
+			expected:              map[string]string{},
+			request:               "unknown_param=17",
+			expectedError:         errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"),
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 6",
+			expected:              map[string]string{},
+			request:               "Mfoo",
+			expectedError:         errors.New("cannot set flag Mfoo: no such flag -Mfoo"),
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 7",
+			expected:              map[string]string{},
+			request:               "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,merge_file_name",
+			allowDeleteBodyV:      true,
+			allowMergeV:           true,
+			includePackageInTagsV: true,
+			fileV:                 "",
+			importPathV:           "",
+			mergeFileNameV:        "",
+		},
+		{
+			name:                  "Test 8",
+			expected:              map[string]string{},
+			request:               "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name",
+			expectedError:         errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`),
+			allowDeleteBodyV:      true,
+			allowMergeV:           true,
+			includePackageInTagsV: false,
+			fileV:                 "",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 9",
+			expected:              map[string]string{},
+			request:               "include_package_in_tags=3",
+			expectedError:         errors.New(`cannot set flag include_package_in_tags=3: parse error`),
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 10",
+			expected:              map[string]string{},
+			request:               "fqn_for_openapi_name=3",
+			expectedError:         errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`),
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			useFQNForOpenAPINameV: false,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                  "Test 11",
+			expected:              map[string]string{},
+			request:               "fqn_for_openapi_name=true",
+			allowDeleteBodyV:      false,
+			allowMergeV:           false,
+			includePackageInTagsV: false,
+			useFQNForOpenAPINameV: true,
+			fileV:                 "stdin",
+			importPathV:           "",
+			mergeFileNameV:        "apidocs",
+		},
+		{
+			name:                   "Test 12",
+			expected:               map[string]string{},
+			request:                "openapi_naming_strategy=simple",
+			allowDeleteBodyV:       false,
+			allowMergeV:            false,
+			includePackageInTagsV:  false,
+			useFQNForOpenAPINameV:  false,
+			openAPINamingStrategyV: "simple",
+			fileV:                  "stdin",
+			importPathV:            "",
+			mergeFileNameV:         "apidocs",
+		},
+	}
+
+	for i, tc := range testcases {
+		t.Run(tc.name, func(tt *testing.T) {
+			f := flag.CommandLine
+			pkgMap := make(map[string]string)
+			err := parseReqParam(tc.request, f, pkgMap)
+			if tc.expectedError == nil {
+				if err != nil {
+					tt.Errorf("unexpected parse error '%v'", err)
+				}
+				if !reflect.DeepEqual(pkgMap, tc.expected) {
+					tt.Errorf("pkgMap parse error, expected '%v', got '%v'", tc.expected, pkgMap)
+				}
+			} else {
+				if err == nil {
+					tt.Error("expected parse error not returned")
+				}
+				if !reflect.DeepEqual(pkgMap, tc.expected) {
+					tt.Errorf("pkgMap parse error, expected '%v', got '%v'", tc.expected, pkgMap)
+				}
+				if err.Error() != tc.expectedError.Error() {
+					tt.Errorf("expected error malformed, expected %q, got %q", tc.expectedError.Error(), err.Error())
+				}
+			}
+			checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.openAPINamingStrategyV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i)
+
+			clearFlags()
+		})
+	}
+}
+
+func checkFlags(
+	allowDeleteV,
+	allowMergeV,
+	includePackageInTagsV bool,
+	useFQNForOpenAPINameV bool,
+	openAPINamingStrategyV,
+	fileV,
+	importPathV,
+	mergeFileNameV string,
+	t *testing.T,
+	tid int,
+) {
+	if *importPrefix != importPathV {
+		t.Errorf("Test %v: import_prefix misparsed, expected '%v', got '%v'", tid, importPathV, *importPrefix)
+	}
+	if *file != fileV {
+		t.Errorf("Test %v: file misparsed, expected '%v', got '%v'", tid, fileV, *file)
+	}
+	if *allowDeleteBody != allowDeleteV {
+		t.Errorf("Test %v: allow_delete_body misparsed, expected '%v', got '%v'", tid, allowDeleteV, *allowDeleteBody)
+	}
+	if *allowMerge != allowMergeV {
+		t.Errorf("Test %v: allow_merge misparsed, expected '%v', got '%v'", tid, allowMergeV, *allowMerge)
+	}
+	if *mergeFileName != mergeFileNameV {
+		t.Errorf("Test %v: merge_file_name misparsed, expected '%v', got '%v'", tid, mergeFileNameV, *mergeFileName)
+	}
+	if *includePackageInTags != includePackageInTagsV {
+		t.Errorf("Test %v: include_package_in_tags misparsed, expected '%v', got '%v'", tid, includePackageInTagsV, *includePackageInTags)
+	}
+	if *useFQNForOpenAPIName != useFQNForOpenAPINameV {
+		t.Errorf("Test %v: fqn_for_openapi_name misparsed, expected '%v', got '%v'", tid, useFQNForOpenAPINameV, *useFQNForOpenAPIName)
+	}
+	if *openAPINamingStrategy != openAPINamingStrategyV {
+		t.Errorf("Test %v: openapi_naming_strategy misparsed, expected '%v', got '%v'", tid, openAPINamingStrategyV, *openAPINamingStrategy)
+	}
+}
+
+func clearFlags() {
+	*importPrefix = ""
+	*file = "stdin"
+	*allowDeleteBody = false
+	*allowMerge = false
+	*includePackageInTags = false
+	*mergeFileName = "apidocs"
+	*useFQNForOpenAPIName = false
+	*openAPINamingStrategy = ""
+}
diff --git a/protoc-gen-openapiv3/options/BUILD.bazel b/protoc-gen-openapiv3/options/BUILD.bazel
new file mode 100644
index 00000000000..a9b18bb531a
--- /dev/null
+++ b/protoc-gen-openapiv3/options/BUILD.bazel
@@ -0,0 +1,44 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+    name = "options_proto_files",
+    srcs = [
+        "annotations.proto",
+        "openapiv3.proto",
+    ],
+)
+
+go_library(
+    name = "options",
+    embed = [":options_go_proto"],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options",
+)
+
+proto_library(
+    name = "options_proto",
+    srcs = [
+        "annotations.proto",
+        "openapiv3.proto",
+    ],
+    deps = [
+        "@com_google_protobuf//:descriptor_proto",
+        "@com_google_protobuf//:struct_proto",
+    ],
+)
+
+go_proto_library(
+    name = "options_go_proto",
+    compilers = ["//:go_apiv2"],
+    importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options",
+    proto = ":options_proto",
+)
+
+alias(
+    name = "go_default_library",
+    actual = ":options",
+    visibility = ["//visibility:public"],
+)
diff --git a/protoc-gen-openapiv3/options/annotations.pb.go b/protoc-gen-openapiv3/options/annotations.pb.go
new file mode 100644
index 00000000000..fca788288dd
--- /dev/null
+++ b/protoc-gen-openapiv3/options/annotations.pb.go
@@ -0,0 +1,269 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.0
+// 	protoc        (unknown)
+// source: protoc-gen-openapiv3/options/annotations.proto
+
+//go:build !protoopaque
+
+package options
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+)
+
+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)
+)
+
+var file_protoc_gen_openapiv3_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{
+	{
+		ExtendedType:  (*descriptorpb.FileOptions)(nil),
+		ExtensionType: (*Swagger)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger",
+		Tag:           "bytes,1043,opt,name=openapiv2_swagger",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.MethodOptions)(nil),
+		ExtensionType: (*Operation)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation",
+		Tag:           "bytes,1043,opt,name=openapiv2_operation",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.MessageOptions)(nil),
+		ExtensionType: (*Schema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema",
+		Tag:           "bytes,1043,opt,name=openapiv2_schema",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.EnumOptions)(nil),
+		ExtensionType: (*EnumSchema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum",
+		Tag:           "bytes,1043,opt,name=openapiv2_enum",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.ServiceOptions)(nil),
+		ExtensionType: (*Tag)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag",
+		Tag:           "bytes,1043,opt,name=openapiv2_tag",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.FieldOptions)(nil),
+		ExtensionType: (*JSONSchema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field",
+		Tag:           "bytes,1043,opt,name=openapiv2_field",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+}
+
+// Extension fields to descriptorpb.FileOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Swagger openapiv2_swagger = 1043;
+	E_Openapiv2Swagger = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[0]
+)
+
+// Extension fields to descriptorpb.MethodOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Operation openapiv2_operation = 1043;
+	E_Openapiv2Operation = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[1]
+)
+
+// Extension fields to descriptorpb.MessageOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Schema openapiv2_schema = 1043;
+	E_Openapiv2Schema = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[2]
+)
+
+// Extension fields to descriptorpb.EnumOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.EnumSchema openapiv2_enum = 1043;
+	E_Openapiv2Enum = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[3]
+)
+
+// Extension fields to descriptorpb.ServiceOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Tag openapiv2_tag = 1043;
+	E_Openapiv2Tag = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[4]
+)
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.JSONSchema openapiv2_field = 1043;
+	E_Openapiv2Field = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[5]
+)
+
+var File_protoc_gen_openapiv3_options_annotations_proto protoreflect.FileDescriptor
+
+var file_protoc_gen_openapiv3_options_annotations_proto_rawDesc = []byte{
+	0x0a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61,
+	0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x12, 0x29, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f,
+	0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73,
+	0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x7e, 0x0a, 0x11, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72,
+	0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+	0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93,
+	0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x32, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x3a, 0x86, 0x01, 0x0a, 0x13,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x4f, 0x70, 0x65, 0x72, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x7e, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x32, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x61, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x3a, 0x7b, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x32, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x45, 0x6e, 0x75,
+	0x6d, 0x3a, 0x75, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x74,
+	0x61, 0x67, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x32, 0x54, 0x61, 0x67, 0x3a, 0x7e, 0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1d, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69,
+	0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53,
+	0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x32, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68,
+	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73,
+	0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e,
+	0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_protoc_gen_openapiv3_options_annotations_proto_goTypes = []any{
+	(*descriptorpb.FileOptions)(nil),    // 0: google.protobuf.FileOptions
+	(*descriptorpb.MethodOptions)(nil),  // 1: google.protobuf.MethodOptions
+	(*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
+	(*descriptorpb.EnumOptions)(nil),    // 3: google.protobuf.EnumOptions
+	(*descriptorpb.ServiceOptions)(nil), // 4: google.protobuf.ServiceOptions
+	(*descriptorpb.FieldOptions)(nil),   // 5: google.protobuf.FieldOptions
+	(*Swagger)(nil),                     // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	(*Operation)(nil),                   // 7: grpc.gateway.protoc_gen_openapiv3.options.Operation
+	(*Schema)(nil),                      // 8: grpc.gateway.protoc_gen_openapiv3.options.Schema
+	(*EnumSchema)(nil),                  // 9: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	(*Tag)(nil),                         // 10: grpc.gateway.protoc_gen_openapiv3.options.Tag
+	(*JSONSchema)(nil),                  // 11: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+}
+var file_protoc_gen_openapiv3_options_annotations_proto_depIdxs = []int32{
+	0,  // 0: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions
+	1,  // 1: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation:extendee -> google.protobuf.MethodOptions
+	2,  // 2: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema:extendee -> google.protobuf.MessageOptions
+	3,  // 3: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum:extendee -> google.protobuf.EnumOptions
+	4,  // 4: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag:extendee -> google.protobuf.ServiceOptions
+	5,  // 5: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field:extendee -> google.protobuf.FieldOptions
+	6,  // 6: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	7,  // 7: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation
+	8,  // 8: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Schema
+	9,  // 9: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum:type_name -> grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	10, // 10: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag
+	11, // 11: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	12, // [12:12] is the sub-list for method output_type
+	12, // [12:12] is the sub-list for method input_type
+	6,  // [6:12] is the sub-list for extension type_name
+	0,  // [0:6] is the sub-list for extension extendee
+	0,  // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_protoc_gen_openapiv3_options_annotations_proto_init() }
+func file_protoc_gen_openapiv3_options_annotations_proto_init() {
+	if File_protoc_gen_openapiv3_options_annotations_proto != nil {
+		return
+	}
+	file_protoc_gen_openapiv3_options_openapiv3_proto_init()
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protoc_gen_openapiv3_options_annotations_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 6,
+			NumServices:   0,
+		},
+		GoTypes:           file_protoc_gen_openapiv3_options_annotations_proto_goTypes,
+		DependencyIndexes: file_protoc_gen_openapiv3_options_annotations_proto_depIdxs,
+		ExtensionInfos:    file_protoc_gen_openapiv3_options_annotations_proto_extTypes,
+	}.Build()
+	File_protoc_gen_openapiv3_options_annotations_proto = out.File
+	file_protoc_gen_openapiv3_options_annotations_proto_rawDesc = nil
+	file_protoc_gen_openapiv3_options_annotations_proto_goTypes = nil
+	file_protoc_gen_openapiv3_options_annotations_proto_depIdxs = nil
+}
diff --git a/protoc-gen-openapiv3/options/annotations.proto b/protoc-gen-openapiv3/options/annotations.proto
new file mode 100644
index 00000000000..c67ca482759
--- /dev/null
+++ b/protoc-gen-openapiv3/options/annotations.proto
@@ -0,0 +1,51 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_openapiv3.options;
+
+import "google/protobuf/descriptor.proto";
+import "protoc-gen-openapiv3/options/openapiv3.proto";
+
+option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options";
+
+extend google.protobuf.FileOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Swagger openapiv2_swagger = 1043;
+}
+extend google.protobuf.MethodOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Operation openapiv2_operation = 1043;
+}
+extend google.protobuf.MessageOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Schema openapiv2_schema = 1043;
+}
+extend google.protobuf.EnumOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  EnumSchema openapiv2_enum = 1043;
+}
+extend google.protobuf.ServiceOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Tag openapiv2_tag = 1043;
+}
+extend google.protobuf.FieldOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  JSONSchema openapiv2_field = 1043;
+}
diff --git a/protoc-gen-openapiv3/options/annotations.swagger.json b/protoc-gen-openapiv3/options/annotations.swagger.json
new file mode 100644
index 00000000000..0b787d88730
--- /dev/null
+++ b/protoc-gen-openapiv3/options/annotations.swagger.json
@@ -0,0 +1,44 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "protoc-gen-openapiv3/options/annotations.proto",
+    "version": "version not set"
+  },
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {},
+  "definitions": {
+    "protobufAny": {
+      "type": "object",
+      "properties": {
+        "@type": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": {}
+    },
+    "rpcStatus": {
+      "type": "object",
+      "properties": {
+        "code": {
+          "type": "integer",
+          "format": "int32"
+        },
+        "message": {
+          "type": "string"
+        },
+        "details": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "$ref": "#/definitions/protobufAny"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/protoc-gen-openapiv3/options/annotations_protoopaque.pb.go b/protoc-gen-openapiv3/options/annotations_protoopaque.pb.go
new file mode 100644
index 00000000000..3b87ed04bde
--- /dev/null
+++ b/protoc-gen-openapiv3/options/annotations_protoopaque.pb.go
@@ -0,0 +1,269 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.0
+// 	protoc        (unknown)
+// source: protoc-gen-openapiv3/options/annotations.proto
+
+//go:build protoopaque
+
+package options
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+)
+
+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)
+)
+
+var file_protoc_gen_openapiv3_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{
+	{
+		ExtendedType:  (*descriptorpb.FileOptions)(nil),
+		ExtensionType: (*Swagger)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger",
+		Tag:           "bytes,1043,opt,name=openapiv2_swagger",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.MethodOptions)(nil),
+		ExtensionType: (*Operation)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation",
+		Tag:           "bytes,1043,opt,name=openapiv2_operation",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.MessageOptions)(nil),
+		ExtensionType: (*Schema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema",
+		Tag:           "bytes,1043,opt,name=openapiv2_schema",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.EnumOptions)(nil),
+		ExtensionType: (*EnumSchema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum",
+		Tag:           "bytes,1043,opt,name=openapiv2_enum",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.ServiceOptions)(nil),
+		ExtensionType: (*Tag)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag",
+		Tag:           "bytes,1043,opt,name=openapiv2_tag",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.FieldOptions)(nil),
+		ExtensionType: (*JSONSchema)(nil),
+		Field:         1043,
+		Name:          "grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field",
+		Tag:           "bytes,1043,opt,name=openapiv2_field",
+		Filename:      "protoc-gen-openapiv3/options/annotations.proto",
+	},
+}
+
+// Extension fields to descriptorpb.FileOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Swagger openapiv2_swagger = 1043;
+	E_Openapiv2Swagger = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[0]
+)
+
+// Extension fields to descriptorpb.MethodOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Operation openapiv2_operation = 1043;
+	E_Openapiv2Operation = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[1]
+)
+
+// Extension fields to descriptorpb.MessageOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Schema openapiv2_schema = 1043;
+	E_Openapiv2Schema = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[2]
+)
+
+// Extension fields to descriptorpb.EnumOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.EnumSchema openapiv2_enum = 1043;
+	E_Openapiv2Enum = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[3]
+)
+
+// Extension fields to descriptorpb.ServiceOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.Tag openapiv2_tag = 1043;
+	E_Openapiv2Tag = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[4]
+)
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+	// ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+	//
+	// All IDs are the same, as assigned. It is okay that they are the same, as they extend
+	// different descriptor messages.
+	//
+	// optional grpc.gateway.protoc_gen_openapiv3.options.JSONSchema openapiv2_field = 1043;
+	E_Openapiv2Field = &file_protoc_gen_openapiv3_options_annotations_proto_extTypes[5]
+)
+
+var File_protoc_gen_openapiv3_options_annotations_proto protoreflect.FileDescriptor
+
+var file_protoc_gen_openapiv3_options_annotations_proto_rawDesc = []byte{
+	0x0a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61,
+	0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x12, 0x29, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f,
+	0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73,
+	0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x7e, 0x0a, 0x11, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72,
+	0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+	0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93,
+	0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x52, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x32, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x3a, 0x86, 0x01, 0x0a, 0x13,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x4f, 0x70, 0x65, 0x72, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x7e, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x32, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x61, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x3a, 0x7b, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x32, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x45, 0x6e, 0x75,
+	0x6d, 0x3a, 0x75, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x74,
+	0x61, 0x67, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x32, 0x54, 0x61, 0x67, 0x3a, 0x7e, 0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x32, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1d, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69,
+	0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53,
+	0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x32, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68,
+	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73,
+	0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e,
+	0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_protoc_gen_openapiv3_options_annotations_proto_goTypes = []any{
+	(*descriptorpb.FileOptions)(nil),    // 0: google.protobuf.FileOptions
+	(*descriptorpb.MethodOptions)(nil),  // 1: google.protobuf.MethodOptions
+	(*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
+	(*descriptorpb.EnumOptions)(nil),    // 3: google.protobuf.EnumOptions
+	(*descriptorpb.ServiceOptions)(nil), // 4: google.protobuf.ServiceOptions
+	(*descriptorpb.FieldOptions)(nil),   // 5: google.protobuf.FieldOptions
+	(*Swagger)(nil),                     // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	(*Operation)(nil),                   // 7: grpc.gateway.protoc_gen_openapiv3.options.Operation
+	(*Schema)(nil),                      // 8: grpc.gateway.protoc_gen_openapiv3.options.Schema
+	(*EnumSchema)(nil),                  // 9: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	(*Tag)(nil),                         // 10: grpc.gateway.protoc_gen_openapiv3.options.Tag
+	(*JSONSchema)(nil),                  // 11: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+}
+var file_protoc_gen_openapiv3_options_annotations_proto_depIdxs = []int32{
+	0,  // 0: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions
+	1,  // 1: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation:extendee -> google.protobuf.MethodOptions
+	2,  // 2: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema:extendee -> google.protobuf.MessageOptions
+	3,  // 3: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum:extendee -> google.protobuf.EnumOptions
+	4,  // 4: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag:extendee -> google.protobuf.ServiceOptions
+	5,  // 5: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field:extendee -> google.protobuf.FieldOptions
+	6,  // 6: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_swagger:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	7,  // 7: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_operation:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation
+	8,  // 8: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Schema
+	9,  // 9: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_enum:type_name -> grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	10, // 10: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_tag:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag
+	11, // 11: grpc.gateway.protoc_gen_openapiv3.options.openapiv2_field:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	12, // [12:12] is the sub-list for method output_type
+	12, // [12:12] is the sub-list for method input_type
+	6,  // [6:12] is the sub-list for extension type_name
+	0,  // [0:6] is the sub-list for extension extendee
+	0,  // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_protoc_gen_openapiv3_options_annotations_proto_init() }
+func file_protoc_gen_openapiv3_options_annotations_proto_init() {
+	if File_protoc_gen_openapiv3_options_annotations_proto != nil {
+		return
+	}
+	file_protoc_gen_openapiv3_options_openapiv3_proto_init()
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protoc_gen_openapiv3_options_annotations_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 6,
+			NumServices:   0,
+		},
+		GoTypes:           file_protoc_gen_openapiv3_options_annotations_proto_goTypes,
+		DependencyIndexes: file_protoc_gen_openapiv3_options_annotations_proto_depIdxs,
+		ExtensionInfos:    file_protoc_gen_openapiv3_options_annotations_proto_extTypes,
+	}.Build()
+	File_protoc_gen_openapiv3_options_annotations_proto = out.File
+	file_protoc_gen_openapiv3_options_annotations_proto_rawDesc = nil
+	file_protoc_gen_openapiv3_options_annotations_proto_goTypes = nil
+	file_protoc_gen_openapiv3_options_annotations_proto_depIdxs = nil
+}
diff --git a/protoc-gen-openapiv3/options/buf.gen.yaml b/protoc-gen-openapiv3/options/buf.gen.yaml
new file mode 100644
index 00000000000..07dfb958f1e
--- /dev/null
+++ b/protoc-gen-openapiv3/options/buf.gen.yaml
@@ -0,0 +1,7 @@
+version: v2
+plugins:
+  - remote: buf.build/protocolbuffers/go:v1.36.0
+    out: .
+    opt:
+      - paths=source_relative
+      - default_api_level=API_HYBRID
diff --git a/protoc-gen-openapiv3/options/openapiv3.pb.go b/protoc-gen-openapiv3/options/openapiv3.pb.go
new file mode 100644
index 00000000000..b5f8bd86ce2
--- /dev/null
+++ b/protoc-gen-openapiv3/options/openapiv3.pb.go
@@ -0,0 +1,4263 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.0
+// 	protoc        (unknown)
+// source: protoc-gen-openapiv3/options/openapiv3.proto
+
+//go:build !protoopaque
+
+package options
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	structpb "google.golang.org/protobuf/types/known/structpb"
+	reflect "reflect"
+)
+
+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)
+)
+
+// Scheme describes the schemes supported by the OpenAPI Swagger
+// and Operation objects.
+type Scheme int32
+
+const (
+	Scheme_UNKNOWN Scheme = 0
+	Scheme_HTTP    Scheme = 1
+	Scheme_HTTPS   Scheme = 2
+	Scheme_WS      Scheme = 3
+	Scheme_WSS     Scheme = 4
+)
+
+// Enum value maps for Scheme.
+var (
+	Scheme_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "HTTP",
+		2: "HTTPS",
+		3: "WS",
+		4: "WSS",
+	}
+	Scheme_value = map[string]int32{
+		"UNKNOWN": 0,
+		"HTTP":    1,
+		"HTTPS":   2,
+		"WS":      3,
+		"WSS":     4,
+	}
+)
+
+func (x Scheme) Enum() *Scheme {
+	p := new(Scheme)
+	*p = x
+	return p
+}
+
+func (x Scheme) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Scheme) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[0].Descriptor()
+}
+
+func (Scheme) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[0]
+}
+
+func (x Scheme) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// `Type` is a supported HTTP header type.
+// See https://swagger.io/specification/v2/#parameterType.
+type HeaderParameter_Type int32
+
+const (
+	HeaderParameter_UNKNOWN HeaderParameter_Type = 0
+	HeaderParameter_STRING  HeaderParameter_Type = 1
+	HeaderParameter_NUMBER  HeaderParameter_Type = 2
+	HeaderParameter_INTEGER HeaderParameter_Type = 3
+	HeaderParameter_BOOLEAN HeaderParameter_Type = 4
+)
+
+// Enum value maps for HeaderParameter_Type.
+var (
+	HeaderParameter_Type_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "STRING",
+		2: "NUMBER",
+		3: "INTEGER",
+		4: "BOOLEAN",
+	}
+	HeaderParameter_Type_value = map[string]int32{
+		"UNKNOWN": 0,
+		"STRING":  1,
+		"NUMBER":  2,
+		"INTEGER": 3,
+		"BOOLEAN": 4,
+	}
+)
+
+func (x HeaderParameter_Type) Enum() *HeaderParameter_Type {
+	p := new(HeaderParameter_Type)
+	*p = x
+	return p
+}
+
+func (x HeaderParameter_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (HeaderParameter_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[1].Descriptor()
+}
+
+func (HeaderParameter_Type) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[1]
+}
+
+func (x HeaderParameter_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+type JSONSchema_JSONSchemaSimpleTypes int32
+
+const (
+	JSONSchema_UNKNOWN JSONSchema_JSONSchemaSimpleTypes = 0
+	JSONSchema_ARRAY   JSONSchema_JSONSchemaSimpleTypes = 1
+	JSONSchema_BOOLEAN JSONSchema_JSONSchemaSimpleTypes = 2
+	JSONSchema_INTEGER JSONSchema_JSONSchemaSimpleTypes = 3
+	JSONSchema_NULL    JSONSchema_JSONSchemaSimpleTypes = 4
+	JSONSchema_NUMBER  JSONSchema_JSONSchemaSimpleTypes = 5
+	JSONSchema_OBJECT  JSONSchema_JSONSchemaSimpleTypes = 6
+	JSONSchema_STRING  JSONSchema_JSONSchemaSimpleTypes = 7
+)
+
+// Enum value maps for JSONSchema_JSONSchemaSimpleTypes.
+var (
+	JSONSchema_JSONSchemaSimpleTypes_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "ARRAY",
+		2: "BOOLEAN",
+		3: "INTEGER",
+		4: "NULL",
+		5: "NUMBER",
+		6: "OBJECT",
+		7: "STRING",
+	}
+	JSONSchema_JSONSchemaSimpleTypes_value = map[string]int32{
+		"UNKNOWN": 0,
+		"ARRAY":   1,
+		"BOOLEAN": 2,
+		"INTEGER": 3,
+		"NULL":    4,
+		"NUMBER":  5,
+		"OBJECT":  6,
+		"STRING":  7,
+	}
+)
+
+func (x JSONSchema_JSONSchemaSimpleTypes) Enum() *JSONSchema_JSONSchemaSimpleTypes {
+	p := new(JSONSchema_JSONSchemaSimpleTypes)
+	*p = x
+	return p
+}
+
+func (x JSONSchema_JSONSchemaSimpleTypes) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (JSONSchema_JSONSchemaSimpleTypes) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[2].Descriptor()
+}
+
+func (JSONSchema_JSONSchemaSimpleTypes) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[2]
+}
+
+func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The type of the security scheme. Valid values are "basic",
+// "apiKey" or "oauth2".
+type SecurityScheme_Type int32
+
+const (
+	SecurityScheme_TYPE_INVALID SecurityScheme_Type = 0
+	SecurityScheme_TYPE_BASIC   SecurityScheme_Type = 1
+	SecurityScheme_TYPE_API_KEY SecurityScheme_Type = 2
+	SecurityScheme_TYPE_OAUTH2  SecurityScheme_Type = 3
+)
+
+// Enum value maps for SecurityScheme_Type.
+var (
+	SecurityScheme_Type_name = map[int32]string{
+		0: "TYPE_INVALID",
+		1: "TYPE_BASIC",
+		2: "TYPE_API_KEY",
+		3: "TYPE_OAUTH2",
+	}
+	SecurityScheme_Type_value = map[string]int32{
+		"TYPE_INVALID": 0,
+		"TYPE_BASIC":   1,
+		"TYPE_API_KEY": 2,
+		"TYPE_OAUTH2":  3,
+	}
+)
+
+func (x SecurityScheme_Type) Enum() *SecurityScheme_Type {
+	p := new(SecurityScheme_Type)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[3].Descriptor()
+}
+
+func (SecurityScheme_Type) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[3]
+}
+
+func (x SecurityScheme_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The location of the API key. Valid values are "query" or "header".
+type SecurityScheme_In int32
+
+const (
+	SecurityScheme_IN_INVALID SecurityScheme_In = 0
+	SecurityScheme_IN_QUERY   SecurityScheme_In = 1
+	SecurityScheme_IN_HEADER  SecurityScheme_In = 2
+)
+
+// Enum value maps for SecurityScheme_In.
+var (
+	SecurityScheme_In_name = map[int32]string{
+		0: "IN_INVALID",
+		1: "IN_QUERY",
+		2: "IN_HEADER",
+	}
+	SecurityScheme_In_value = map[string]int32{
+		"IN_INVALID": 0,
+		"IN_QUERY":   1,
+		"IN_HEADER":  2,
+	}
+)
+
+func (x SecurityScheme_In) Enum() *SecurityScheme_In {
+	p := new(SecurityScheme_In)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_In) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_In) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[4].Descriptor()
+}
+
+func (SecurityScheme_In) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[4]
+}
+
+func (x SecurityScheme_In) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The flow used by the OAuth2 security scheme. Valid values are
+// "implicit", "password", "application" or "accessCode".
+type SecurityScheme_Flow int32
+
+const (
+	SecurityScheme_FLOW_INVALID     SecurityScheme_Flow = 0
+	SecurityScheme_FLOW_IMPLICIT    SecurityScheme_Flow = 1
+	SecurityScheme_FLOW_PASSWORD    SecurityScheme_Flow = 2
+	SecurityScheme_FLOW_APPLICATION SecurityScheme_Flow = 3
+	SecurityScheme_FLOW_ACCESS_CODE SecurityScheme_Flow = 4
+)
+
+// Enum value maps for SecurityScheme_Flow.
+var (
+	SecurityScheme_Flow_name = map[int32]string{
+		0: "FLOW_INVALID",
+		1: "FLOW_IMPLICIT",
+		2: "FLOW_PASSWORD",
+		3: "FLOW_APPLICATION",
+		4: "FLOW_ACCESS_CODE",
+	}
+	SecurityScheme_Flow_value = map[string]int32{
+		"FLOW_INVALID":     0,
+		"FLOW_IMPLICIT":    1,
+		"FLOW_PASSWORD":    2,
+		"FLOW_APPLICATION": 3,
+		"FLOW_ACCESS_CODE": 4,
+	}
+)
+
+func (x SecurityScheme_Flow) Enum() *SecurityScheme_Flow {
+	p := new(SecurityScheme_Flow)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_Flow) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_Flow) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[5].Descriptor()
+}
+
+func (SecurityScheme_Flow) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[5]
+}
+
+func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    title: "Echo API";
+//	    version: "1.0";
+//	    description: "";
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	  };
+//	  schemes: HTTPS;
+//	  consumes: "application/json";
+//	  produces: "application/json";
+//	};
+type Swagger struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// Specifies the OpenAPI Specification version being used. It can be
+	// used by the OpenAPI UI and other clients to interpret the API listing. The
+	// value MUST be "2.0".
+	Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"`
+	// Provides metadata about the API. The metadata can be used by the
+	// clients if needed.
+	Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"`
+	// The host (name or ip) serving the API. This MUST be the host only and does
+	// not include the scheme nor sub-paths. It MAY include a port. If the host is
+	// not included, the host serving the documentation is to be used (including
+	// the port). The host does not support path templating.
+	Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"`
+	// The base path on which the API is served, which is relative to the host. If
+	// it is not included, the API is served directly under the host. The value
+	// MUST start with a leading slash (/). The basePath does not support path
+	// templating.
+	// Note that using `base_path` does not change the endpoint paths that are
+	// generated in the resulting OpenAPI file. If you wish to use `base_path`
+	// with relatively generated OpenAPI paths, the `base_path` prefix must be
+	// manually removed from your `google.api.http` paths and your code changed to
+	// serve the API from the `base_path`.
+	BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"`
+	// The transfer protocol of the API. Values MUST be from the list: "http",
+	// "https", "ws", "wss". If the schemes is not included, the default scheme to
+	// be used is the one used to access the OpenAPI definition itself.
+	Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.Scheme" json:"schemes,omitempty"`
+	// A list of MIME types the APIs can consume. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"`
+	// A list of MIME types the APIs can produce. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"`
+	// An object to hold responses that can be used across operations. This
+	// property does not define global responses for all operations.
+	Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// Security scheme definitions that can be used across the specification.
+	SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"`
+	// A declaration of which security schemes are applied for the API as a whole.
+	// The list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements).
+	// Individual operations can override this definition.
+	Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"`
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []*Tag `protobuf:"bytes,13,rep,name=tags,proto3" json:"tags,omitempty"`
+	// Additional external documentation.
+	ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Swagger) Reset() {
+	*x = Swagger{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Swagger) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Swagger) ProtoMessage() {}
+
+func (x *Swagger) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Swagger) GetSwagger() string {
+	if x != nil {
+		return x.Swagger
+	}
+	return ""
+}
+
+func (x *Swagger) GetInfo() *Info {
+	if x != nil {
+		return x.Info
+	}
+	return nil
+}
+
+func (x *Swagger) GetHost() string {
+	if x != nil {
+		return x.Host
+	}
+	return ""
+}
+
+func (x *Swagger) GetBasePath() string {
+	if x != nil {
+		return x.BasePath
+	}
+	return ""
+}
+
+func (x *Swagger) GetSchemes() []Scheme {
+	if x != nil {
+		return x.Schemes
+	}
+	return nil
+}
+
+func (x *Swagger) GetConsumes() []string {
+	if x != nil {
+		return x.Consumes
+	}
+	return nil
+}
+
+func (x *Swagger) GetProduces() []string {
+	if x != nil {
+		return x.Produces
+	}
+	return nil
+}
+
+func (x *Swagger) GetResponses() map[string]*Response {
+	if x != nil {
+		return x.Responses
+	}
+	return nil
+}
+
+func (x *Swagger) GetSecurityDefinitions() *SecurityDefinitions {
+	if x != nil {
+		return x.SecurityDefinitions
+	}
+	return nil
+}
+
+func (x *Swagger) GetSecurity() []*SecurityRequirement {
+	if x != nil {
+		return x.Security
+	}
+	return nil
+}
+
+func (x *Swagger) GetTags() []*Tag {
+	if x != nil {
+		return x.Tags
+	}
+	return nil
+}
+
+func (x *Swagger) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.ExternalDocs
+	}
+	return nil
+}
+
+func (x *Swagger) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *Swagger) SetSwagger(v string) {
+	x.Swagger = v
+}
+
+func (x *Swagger) SetInfo(v *Info) {
+	x.Info = v
+}
+
+func (x *Swagger) SetHost(v string) {
+	x.Host = v
+}
+
+func (x *Swagger) SetBasePath(v string) {
+	x.BasePath = v
+}
+
+func (x *Swagger) SetSchemes(v []Scheme) {
+	x.Schemes = v
+}
+
+func (x *Swagger) SetConsumes(v []string) {
+	x.Consumes = v
+}
+
+func (x *Swagger) SetProduces(v []string) {
+	x.Produces = v
+}
+
+func (x *Swagger) SetResponses(v map[string]*Response) {
+	x.Responses = v
+}
+
+func (x *Swagger) SetSecurityDefinitions(v *SecurityDefinitions) {
+	x.SecurityDefinitions = v
+}
+
+func (x *Swagger) SetSecurity(v []*SecurityRequirement) {
+	x.Security = v
+}
+
+func (x *Swagger) SetTags(v []*Tag) {
+	x.Tags = v
+}
+
+func (x *Swagger) SetExternalDocs(v *ExternalDocumentation) {
+	x.ExternalDocs = v
+}
+
+func (x *Swagger) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *Swagger) HasInfo() bool {
+	if x == nil {
+		return false
+	}
+	return x.Info != nil
+}
+
+func (x *Swagger) HasSecurityDefinitions() bool {
+	if x == nil {
+		return false
+	}
+	return x.SecurityDefinitions != nil
+}
+
+func (x *Swagger) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.ExternalDocs != nil
+}
+
+func (x *Swagger) ClearInfo() {
+	x.Info = nil
+}
+
+func (x *Swagger) ClearSecurityDefinitions() {
+	x.SecurityDefinitions = nil
+}
+
+func (x *Swagger) ClearExternalDocs() {
+	x.ExternalDocs = nil
+}
+
+type Swagger_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Specifies the OpenAPI Specification version being used. It can be
+	// used by the OpenAPI UI and other clients to interpret the API listing. The
+	// value MUST be "2.0".
+	Swagger string
+	// Provides metadata about the API. The metadata can be used by the
+	// clients if needed.
+	Info *Info
+	// The host (name or ip) serving the API. This MUST be the host only and does
+	// not include the scheme nor sub-paths. It MAY include a port. If the host is
+	// not included, the host serving the documentation is to be used (including
+	// the port). The host does not support path templating.
+	Host string
+	// The base path on which the API is served, which is relative to the host. If
+	// it is not included, the API is served directly under the host. The value
+	// MUST start with a leading slash (/). The basePath does not support path
+	// templating.
+	// Note that using `base_path` does not change the endpoint paths that are
+	// generated in the resulting OpenAPI file. If you wish to use `base_path`
+	// with relatively generated OpenAPI paths, the `base_path` prefix must be
+	// manually removed from your `google.api.http` paths and your code changed to
+	// serve the API from the `base_path`.
+	BasePath string
+	// The transfer protocol of the API. Values MUST be from the list: "http",
+	// "https", "ws", "wss". If the schemes is not included, the default scheme to
+	// be used is the one used to access the OpenAPI definition itself.
+	Schemes []Scheme
+	// A list of MIME types the APIs can consume. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Consumes []string
+	// A list of MIME types the APIs can produce. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Produces []string
+	// An object to hold responses that can be used across operations. This
+	// property does not define global responses for all operations.
+	Responses map[string]*Response
+	// Security scheme definitions that can be used across the specification.
+	SecurityDefinitions *SecurityDefinitions
+	// A declaration of which security schemes are applied for the API as a whole.
+	// The list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements).
+	// Individual operations can override this definition.
+	Security []*SecurityRequirement
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []*Tag
+	// Additional external documentation.
+	ExternalDocs *ExternalDocumentation
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Swagger_builder) Build() *Swagger {
+	m0 := &Swagger{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Swagger = b.Swagger
+	x.Info = b.Info
+	x.Host = b.Host
+	x.BasePath = b.BasePath
+	x.Schemes = b.Schemes
+	x.Consumes = b.Consumes
+	x.Produces = b.Produces
+	x.Responses = b.Responses
+	x.SecurityDefinitions = b.SecurityDefinitions
+	x.Security = b.Security
+	x.Tags = b.Tags
+	x.ExternalDocs = b.ExternalDocs
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `Operation` is a representation of OpenAPI v2 specification's Operation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
+//
+// Example:
+//
+//	service EchoService {
+//	  rpc Echo(SimpleMessage) returns (SimpleMessage) {
+//	    option (google.api.http) = {
+//	      get: "/v1/example/echo/{id}"
+//	    };
+//
+//	    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
+//	      summary: "Get a message.";
+//	      operation_id: "getMessage";
+//	      tags: "echo";
+//	      responses: {
+//	        key: "200"
+//	          value: {
+//	          description: "OK";
+//	        }
+//	      }
+//	    };
+//	  }
+//	}
+type Operation struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"`
+	// A short summary of what the operation does. For maximum readability in the
+	// swagger-ui, this field SHOULD be less than 120 characters.
+	Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"`
+	// A verbose explanation of the operation behavior. GFM syntax can be used for
+	// rich text representation.
+	Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+	// Additional external documentation for this operation.
+	ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	// Unique string used to identify the operation. The id MUST be unique among
+	// all operations described in the API. Tools and libraries MAY use the
+	// operationId to uniquely identify an operation, therefore, it is recommended
+	// to follow common programming naming conventions.
+	OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"`
+	// A list of MIME types the operation can consume. This overrides the consumes
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"`
+	// A list of MIME types the operation can produce. This overrides the produces
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"`
+	// The list of possible responses as they are returned from executing this
+	// operation.
+	Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// The transfer protocol for the operation. Values MUST be from the list:
+	// "http", "https", "ws", "wss". The value overrides the OpenAPI Object
+	// schemes definition.
+	Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.Scheme" json:"schemes,omitempty"`
+	// Declares this operation to be deprecated. Usage of the declared operation
+	// should be refrained. Default value is false.
+	Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+	// A declaration of which security schemes are applied for this operation. The
+	// list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements). This
+	// definition overrides any declared top-level security. To remove a top-level
+	// security declaration, an empty array can be used.
+	Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// Custom parameters such as HTTP request headers.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/
+	// and https://swagger.io/specification/v2/#parameter-object.
+	Parameters    *Parameters `protobuf:"bytes,14,opt,name=parameters,proto3" json:"parameters,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Operation) Reset() {
+	*x = Operation{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Operation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Operation) ProtoMessage() {}
+
+func (x *Operation) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Operation) GetTags() []string {
+	if x != nil {
+		return x.Tags
+	}
+	return nil
+}
+
+func (x *Operation) GetSummary() string {
+	if x != nil {
+		return x.Summary
+	}
+	return ""
+}
+
+func (x *Operation) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Operation) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.ExternalDocs
+	}
+	return nil
+}
+
+func (x *Operation) GetOperationId() string {
+	if x != nil {
+		return x.OperationId
+	}
+	return ""
+}
+
+func (x *Operation) GetConsumes() []string {
+	if x != nil {
+		return x.Consumes
+	}
+	return nil
+}
+
+func (x *Operation) GetProduces() []string {
+	if x != nil {
+		return x.Produces
+	}
+	return nil
+}
+
+func (x *Operation) GetResponses() map[string]*Response {
+	if x != nil {
+		return x.Responses
+	}
+	return nil
+}
+
+func (x *Operation) GetSchemes() []Scheme {
+	if x != nil {
+		return x.Schemes
+	}
+	return nil
+}
+
+func (x *Operation) GetDeprecated() bool {
+	if x != nil {
+		return x.Deprecated
+	}
+	return false
+}
+
+func (x *Operation) GetSecurity() []*SecurityRequirement {
+	if x != nil {
+		return x.Security
+	}
+	return nil
+}
+
+func (x *Operation) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *Operation) GetParameters() *Parameters {
+	if x != nil {
+		return x.Parameters
+	}
+	return nil
+}
+
+func (x *Operation) SetTags(v []string) {
+	x.Tags = v
+}
+
+func (x *Operation) SetSummary(v string) {
+	x.Summary = v
+}
+
+func (x *Operation) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *Operation) SetExternalDocs(v *ExternalDocumentation) {
+	x.ExternalDocs = v
+}
+
+func (x *Operation) SetOperationId(v string) {
+	x.OperationId = v
+}
+
+func (x *Operation) SetConsumes(v []string) {
+	x.Consumes = v
+}
+
+func (x *Operation) SetProduces(v []string) {
+	x.Produces = v
+}
+
+func (x *Operation) SetResponses(v map[string]*Response) {
+	x.Responses = v
+}
+
+func (x *Operation) SetSchemes(v []Scheme) {
+	x.Schemes = v
+}
+
+func (x *Operation) SetDeprecated(v bool) {
+	x.Deprecated = v
+}
+
+func (x *Operation) SetSecurity(v []*SecurityRequirement) {
+	x.Security = v
+}
+
+func (x *Operation) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *Operation) SetParameters(v *Parameters) {
+	x.Parameters = v
+}
+
+func (x *Operation) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.ExternalDocs != nil
+}
+
+func (x *Operation) HasParameters() bool {
+	if x == nil {
+		return false
+	}
+	return x.Parameters != nil
+}
+
+func (x *Operation) ClearExternalDocs() {
+	x.ExternalDocs = nil
+}
+
+func (x *Operation) ClearParameters() {
+	x.Parameters = nil
+}
+
+type Operation_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []string
+	// A short summary of what the operation does. For maximum readability in the
+	// swagger-ui, this field SHOULD be less than 120 characters.
+	Summary string
+	// A verbose explanation of the operation behavior. GFM syntax can be used for
+	// rich text representation.
+	Description string
+	// Additional external documentation for this operation.
+	ExternalDocs *ExternalDocumentation
+	// Unique string used to identify the operation. The id MUST be unique among
+	// all operations described in the API. Tools and libraries MAY use the
+	// operationId to uniquely identify an operation, therefore, it is recommended
+	// to follow common programming naming conventions.
+	OperationId string
+	// A list of MIME types the operation can consume. This overrides the consumes
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Consumes []string
+	// A list of MIME types the operation can produce. This overrides the produces
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Produces []string
+	// The list of possible responses as they are returned from executing this
+	// operation.
+	Responses map[string]*Response
+	// The transfer protocol for the operation. Values MUST be from the list:
+	// "http", "https", "ws", "wss". The value overrides the OpenAPI Object
+	// schemes definition.
+	Schemes []Scheme
+	// Declares this operation to be deprecated. Usage of the declared operation
+	// should be refrained. Default value is false.
+	Deprecated bool
+	// A declaration of which security schemes are applied for this operation. The
+	// list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements). This
+	// definition overrides any declared top-level security. To remove a top-level
+	// security declaration, an empty array can be used.
+	Security []*SecurityRequirement
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+	// Custom parameters such as HTTP request headers.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/
+	// and https://swagger.io/specification/v2/#parameter-object.
+	Parameters *Parameters
+}
+
+func (b0 Operation_builder) Build() *Operation {
+	m0 := &Operation{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Tags = b.Tags
+	x.Summary = b.Summary
+	x.Description = b.Description
+	x.ExternalDocs = b.ExternalDocs
+	x.OperationId = b.OperationId
+	x.Consumes = b.Consumes
+	x.Produces = b.Produces
+	x.Responses = b.Responses
+	x.Schemes = b.Schemes
+	x.Deprecated = b.Deprecated
+	x.Security = b.Security
+	x.Extensions = b.Extensions
+	x.Parameters = b.Parameters
+	return m0
+}
+
+// `Parameters` is a representation of OpenAPI v2 specification's parameters object.
+// Note: This technically breaks compatibility with the OpenAPI 2 definition structure as we only
+// allow header parameters to be set here since we do not want users specifying custom non-header
+// parameters beyond those inferred from the Protobuf schema.
+// See: https://swagger.io/specification/v2/#parameter-object
+type Parameters struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// `Headers` is one or more HTTP header parameter.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
+	Headers       []*HeaderParameter `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Parameters) Reset() {
+	*x = Parameters{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Parameters) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Parameters) ProtoMessage() {}
+
+func (x *Parameters) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Parameters) GetHeaders() []*HeaderParameter {
+	if x != nil {
+		return x.Headers
+	}
+	return nil
+}
+
+func (x *Parameters) SetHeaders(v []*HeaderParameter) {
+	x.Headers = v
+}
+
+type Parameters_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Headers` is one or more HTTP header parameter.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
+	Headers []*HeaderParameter
+}
+
+func (b0 Parameters_builder) Build() *Parameters {
+	m0 := &Parameters{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Headers = b.Headers
+	return m0
+}
+
+// `HeaderParameter` a HTTP header parameter.
+// See: https://swagger.io/specification/v2/#parameter-object
+type HeaderParameter struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// `Name` is the header name.
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// `Description` is a short description of the header.
+	Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	// `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	// See: https://swagger.io/specification/v2/#parameterType.
+	Type HeaderParameter_Type `protobuf:"varint,3,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter_Type" json:"type,omitempty"`
+	// `Format` The extending format for the previously mentioned type.
+	Format string `protobuf:"bytes,4,opt,name=format,proto3" json:"format,omitempty"`
+	// `Required` indicates if the header is optional
+	Required      bool `protobuf:"varint,5,opt,name=required,proto3" json:"required,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *HeaderParameter) Reset() {
+	*x = HeaderParameter{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *HeaderParameter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HeaderParameter) ProtoMessage() {}
+
+func (x *HeaderParameter) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *HeaderParameter) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetType() HeaderParameter_Type {
+	if x != nil {
+		return x.Type
+	}
+	return HeaderParameter_UNKNOWN
+}
+
+func (x *HeaderParameter) GetFormat() string {
+	if x != nil {
+		return x.Format
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+func (x *HeaderParameter) SetName(v string) {
+	x.Name = v
+}
+
+func (x *HeaderParameter) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *HeaderParameter) SetType(v HeaderParameter_Type) {
+	x.Type = v
+}
+
+func (x *HeaderParameter) SetFormat(v string) {
+	x.Format = v
+}
+
+func (x *HeaderParameter) SetRequired(v bool) {
+	x.Required = v
+}
+
+type HeaderParameter_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Name` is the header name.
+	Name string
+	// `Description` is a short description of the header.
+	Description string
+	// `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	// See: https://swagger.io/specification/v2/#parameterType.
+	Type HeaderParameter_Type
+	// `Format` The extending format for the previously mentioned type.
+	Format string
+	// `Required` indicates if the header is optional
+	Required bool
+}
+
+func (b0 HeaderParameter_builder) Build() *HeaderParameter {
+	m0 := &HeaderParameter{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Name = b.Name
+	x.Description = b.Description
+	x.Type = b.Type
+	x.Format = b.Format
+	x.Required = b.Required
+	return m0
+}
+
+// `Header` is a representation of OpenAPI v2 specification's Header object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+type Header struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// `Description` is a short description of the header.
+	Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	// The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	// `Format` The extending format for the previously mentioned type.
+	Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"`
+	// `Default` Declares the value of the header that the server will use if none is provided.
+	// See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+	// Unlike JSON Schema this value MUST conform to the defined type for the header.
+	Default string `protobuf:"bytes,6,opt,name=default,proto3" json:"default,omitempty"`
+	// 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+	Pattern       string `protobuf:"bytes,13,opt,name=pattern,proto3" json:"pattern,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Header) Reset() {
+	*x = Header{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Header) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Header) ProtoMessage() {}
+
+func (x *Header) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Header) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Header) GetType() string {
+	if x != nil {
+		return x.Type
+	}
+	return ""
+}
+
+func (x *Header) GetFormat() string {
+	if x != nil {
+		return x.Format
+	}
+	return ""
+}
+
+func (x *Header) GetDefault() string {
+	if x != nil {
+		return x.Default
+	}
+	return ""
+}
+
+func (x *Header) GetPattern() string {
+	if x != nil {
+		return x.Pattern
+	}
+	return ""
+}
+
+func (x *Header) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *Header) SetType(v string) {
+	x.Type = v
+}
+
+func (x *Header) SetFormat(v string) {
+	x.Format = v
+}
+
+func (x *Header) SetDefault(v string) {
+	x.Default = v
+}
+
+func (x *Header) SetPattern(v string) {
+	x.Pattern = v
+}
+
+type Header_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Description` is a short description of the header.
+	Description string
+	// The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	Type string
+	// `Format` The extending format for the previously mentioned type.
+	Format string
+	// `Default` Declares the value of the header that the server will use if none is provided.
+	// See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+	// Unlike JSON Schema this value MUST conform to the defined type for the header.
+	Default string
+	// 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+	Pattern string
+}
+
+func (b0 Header_builder) Build() *Header {
+	m0 := &Header{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Description = b.Description
+	x.Type = b.Type
+	x.Format = b.Format
+	x.Default = b.Default
+	x.Pattern = b.Pattern
+	return m0
+}
+
+// `Response` is a representation of OpenAPI v2 specification's Response object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
+type Response struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// `Description` is a short description of the response.
+	// GFM syntax can be used for rich text representation.
+	Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	// `Schema` optionally defines the structure of the response.
+	// If `Schema` is not provided, it means there is no content to the response.
+	Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"`
+	// `Headers` A list of headers that are sent with the response.
+	// `Header` name is expected to be a string in the canonical format of the MIME header key
+	// See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+	Headers map[string]*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// `Examples` gives per-mimetype response examples.
+	// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+	Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Response) Reset() {
+	*x = Response{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Response) ProtoMessage() {}
+
+func (x *Response) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Response) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Response) GetSchema() *Schema {
+	if x != nil {
+		return x.Schema
+	}
+	return nil
+}
+
+func (x *Response) GetHeaders() map[string]*Header {
+	if x != nil {
+		return x.Headers
+	}
+	return nil
+}
+
+func (x *Response) GetExamples() map[string]string {
+	if x != nil {
+		return x.Examples
+	}
+	return nil
+}
+
+func (x *Response) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *Response) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *Response) SetSchema(v *Schema) {
+	x.Schema = v
+}
+
+func (x *Response) SetHeaders(v map[string]*Header) {
+	x.Headers = v
+}
+
+func (x *Response) SetExamples(v map[string]string) {
+	x.Examples = v
+}
+
+func (x *Response) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *Response) HasSchema() bool {
+	if x == nil {
+		return false
+	}
+	return x.Schema != nil
+}
+
+func (x *Response) ClearSchema() {
+	x.Schema = nil
+}
+
+type Response_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Description` is a short description of the response.
+	// GFM syntax can be used for rich text representation.
+	Description string
+	// `Schema` optionally defines the structure of the response.
+	// If `Schema` is not provided, it means there is no content to the response.
+	Schema *Schema
+	// `Headers` A list of headers that are sent with the response.
+	// `Header` name is expected to be a string in the canonical format of the MIME header key
+	// See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+	Headers map[string]*Header
+	// `Examples` gives per-mimetype response examples.
+	// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+	Examples map[string]string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Response_builder) Build() *Response {
+	m0 := &Response{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Description = b.Description
+	x.Schema = b.Schema
+	x.Headers = b.Headers
+	x.Examples = b.Examples
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `Info` is a representation of OpenAPI v2 specification's Info object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    title: "Echo API";
+//	    version: "1.0";
+//	    description: "";
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	  };
+//	  ...
+//	};
+type Info struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// The title of the application.
+	Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+	// A short description of the application. GFM syntax can be used for rich
+	// text representation.
+	Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	// The Terms of Service for the API.
+	TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"`
+	// The contact information for the exposed API.
+	Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"`
+	// The license information for the exposed API.
+	License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"`
+	// Provides the version of the application API (not to be confused
+	// with the specification version).
+	Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Info) Reset() {
+	*x = Info{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Info) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Info) ProtoMessage() {}
+
+func (x *Info) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Info) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *Info) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Info) GetTermsOfService() string {
+	if x != nil {
+		return x.TermsOfService
+	}
+	return ""
+}
+
+func (x *Info) GetContact() *Contact {
+	if x != nil {
+		return x.Contact
+	}
+	return nil
+}
+
+func (x *Info) GetLicense() *License {
+	if x != nil {
+		return x.License
+	}
+	return nil
+}
+
+func (x *Info) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *Info) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *Info) SetTitle(v string) {
+	x.Title = v
+}
+
+func (x *Info) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *Info) SetTermsOfService(v string) {
+	x.TermsOfService = v
+}
+
+func (x *Info) SetContact(v *Contact) {
+	x.Contact = v
+}
+
+func (x *Info) SetLicense(v *License) {
+	x.License = v
+}
+
+func (x *Info) SetVersion(v string) {
+	x.Version = v
+}
+
+func (x *Info) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *Info) HasContact() bool {
+	if x == nil {
+		return false
+	}
+	return x.Contact != nil
+}
+
+func (x *Info) HasLicense() bool {
+	if x == nil {
+		return false
+	}
+	return x.License != nil
+}
+
+func (x *Info) ClearContact() {
+	x.Contact = nil
+}
+
+func (x *Info) ClearLicense() {
+	x.License = nil
+}
+
+type Info_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The title of the application.
+	Title string
+	// A short description of the application. GFM syntax can be used for rich
+	// text representation.
+	Description string
+	// The Terms of Service for the API.
+	TermsOfService string
+	// The contact information for the exposed API.
+	Contact *Contact
+	// The license information for the exposed API.
+	License *License
+	// Provides the version of the application API (not to be confused
+	// with the specification version).
+	Version string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Info_builder) Build() *Info {
+	m0 := &Info{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Title = b.Title
+	x.Description = b.Description
+	x.TermsOfService = b.TermsOfService
+	x.Contact = b.Contact
+	x.License = b.License
+	x.Version = b.Version
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `Contact` is a representation of OpenAPI v2 specification's Contact object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    ...
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    ...
+//	  };
+//	  ...
+//	};
+type Contact struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// The identifying name of the contact person/organization.
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// The URL pointing to the contact information. MUST be in the format of a
+	// URL.
+	Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	// The email address of the contact person/organization. MUST be in the format
+	// of an email address.
+	Email         string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Contact) Reset() {
+	*x = Contact{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Contact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Contact) ProtoMessage() {}
+
+func (x *Contact) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Contact) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Contact) GetUrl() string {
+	if x != nil {
+		return x.Url
+	}
+	return ""
+}
+
+func (x *Contact) GetEmail() string {
+	if x != nil {
+		return x.Email
+	}
+	return ""
+}
+
+func (x *Contact) SetName(v string) {
+	x.Name = v
+}
+
+func (x *Contact) SetUrl(v string) {
+	x.Url = v
+}
+
+func (x *Contact) SetEmail(v string) {
+	x.Email = v
+}
+
+type Contact_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The identifying name of the contact person/organization.
+	Name string
+	// The URL pointing to the contact information. MUST be in the format of a
+	// URL.
+	Url string
+	// The email address of the contact person/organization. MUST be in the format
+	// of an email address.
+	Email string
+}
+
+func (b0 Contact_builder) Build() *Contact {
+	m0 := &Contact{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Name = b.Name
+	x.Url = b.Url
+	x.Email = b.Email
+	return m0
+}
+
+// `License` is a representation of OpenAPI v2 specification's License object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    ...
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	    ...
+//	  };
+//	  ...
+//	};
+type License struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// The license name used for the API.
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// A URL to the license used for the API. MUST be in the format of a URL.
+	Url           string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *License) Reset() {
+	*x = License{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *License) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*License) ProtoMessage() {}
+
+func (x *License) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *License) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *License) GetUrl() string {
+	if x != nil {
+		return x.Url
+	}
+	return ""
+}
+
+func (x *License) SetName(v string) {
+	x.Name = v
+}
+
+func (x *License) SetUrl(v string) {
+	x.Url = v
+}
+
+type License_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The license name used for the API.
+	Name string
+	// A URL to the license used for the API. MUST be in the format of a URL.
+	Url string
+}
+
+func (b0 License_builder) Build() *License {
+	m0 := &License{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Name = b.Name
+	x.Url = b.Url
+	return m0
+}
+
+// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
+// ExternalDocumentation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  ...
+//	  external_docs: {
+//	    description: "More about gRPC-Gateway";
+//	    url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	  }
+//	  ...
+//	};
+type ExternalDocumentation struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// A short description of the target documentation. GFM syntax can be used for
+	// rich text representation.
+	Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	// The URL for the target documentation. Value MUST be in the format
+	// of a URL.
+	Url           string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ExternalDocumentation) Reset() {
+	*x = ExternalDocumentation{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ExternalDocumentation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExternalDocumentation) ProtoMessage() {}
+
+func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *ExternalDocumentation) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *ExternalDocumentation) GetUrl() string {
+	if x != nil {
+		return x.Url
+	}
+	return ""
+}
+
+func (x *ExternalDocumentation) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *ExternalDocumentation) SetUrl(v string) {
+	x.Url = v
+}
+
+type ExternalDocumentation_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A short description of the target documentation. GFM syntax can be used for
+	// rich text representation.
+	Description string
+	// The URL for the target documentation. Value MUST be in the format
+	// of a URL.
+	Url string
+}
+
+func (b0 ExternalDocumentation_builder) Build() *ExternalDocumentation {
+	m0 := &ExternalDocumentation{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Description = b.Description
+	x.Url = b.Url
+	return m0
+}
+
+// `Schema` is a representation of OpenAPI v2 specification's Schema object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+type Schema struct {
+	state      protoimpl.MessageState `protogen:"hybrid.v1"`
+	JsonSchema *JSONSchema            `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"`
+	// Adds support for polymorphism. The discriminator is the schema property
+	// name that is used to differentiate between other schema that inherit this
+	// schema. The property name used MUST be defined at this schema and it MUST
+	// be in the required property list. When used, the value MUST be the name of
+	// this schema or any schema that inherits it.
+	Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"`
+	// Relevant only for Schema "properties" definitions. Declares the property as
+	// "read only". This means that it MAY be sent as part of a response but MUST
+	// NOT be sent as part of the request. Properties marked as readOnly being
+	// true SHOULD NOT be in the required list of the defined schema. Default
+	// value is false.
+	ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	// A free-form property to include an example of an instance for this schema in JSON.
+	// This is copied verbatim to the output.
+	Example       string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Schema) Reset() {
+	*x = Schema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Schema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema) ProtoMessage() {}
+
+func (x *Schema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Schema) GetJsonSchema() *JSONSchema {
+	if x != nil {
+		return x.JsonSchema
+	}
+	return nil
+}
+
+func (x *Schema) GetDiscriminator() string {
+	if x != nil {
+		return x.Discriminator
+	}
+	return ""
+}
+
+func (x *Schema) GetReadOnly() bool {
+	if x != nil {
+		return x.ReadOnly
+	}
+	return false
+}
+
+func (x *Schema) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.ExternalDocs
+	}
+	return nil
+}
+
+func (x *Schema) GetExample() string {
+	if x != nil {
+		return x.Example
+	}
+	return ""
+}
+
+func (x *Schema) SetJsonSchema(v *JSONSchema) {
+	x.JsonSchema = v
+}
+
+func (x *Schema) SetDiscriminator(v string) {
+	x.Discriminator = v
+}
+
+func (x *Schema) SetReadOnly(v bool) {
+	x.ReadOnly = v
+}
+
+func (x *Schema) SetExternalDocs(v *ExternalDocumentation) {
+	x.ExternalDocs = v
+}
+
+func (x *Schema) SetExample(v string) {
+	x.Example = v
+}
+
+func (x *Schema) HasJsonSchema() bool {
+	if x == nil {
+		return false
+	}
+	return x.JsonSchema != nil
+}
+
+func (x *Schema) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.ExternalDocs != nil
+}
+
+func (x *Schema) ClearJsonSchema() {
+	x.JsonSchema = nil
+}
+
+func (x *Schema) ClearExternalDocs() {
+	x.ExternalDocs = nil
+}
+
+type Schema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	JsonSchema *JSONSchema
+	// Adds support for polymorphism. The discriminator is the schema property
+	// name that is used to differentiate between other schema that inherit this
+	// schema. The property name used MUST be defined at this schema and it MUST
+	// be in the required property list. When used, the value MUST be the name of
+	// this schema or any schema that inherits it.
+	Discriminator string
+	// Relevant only for Schema "properties" definitions. Declares the property as
+	// "read only". This means that it MAY be sent as part of a response but MUST
+	// NOT be sent as part of the request. Properties marked as readOnly being
+	// true SHOULD NOT be in the required list of the defined schema. Default
+	// value is false.
+	ReadOnly bool
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation
+	// A free-form property to include an example of an instance for this schema in JSON.
+	// This is copied verbatim to the output.
+	Example string
+}
+
+func (b0 Schema_builder) Build() *Schema {
+	m0 := &Schema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.JsonSchema = b.JsonSchema
+	x.Discriminator = b.Discriminator
+	x.ReadOnly = b.ReadOnly
+	x.ExternalDocs = b.ExternalDocs
+	x.Example = b.Example
+	return m0
+}
+
+// `EnumSchema` is subset of fields from the OpenAPI v2 specification's Schema object.
+// Only fields that are applicable to Enums are included
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
+//	  ...
+//	  title: "MyEnum";
+//	  description:"This is my nice enum";
+//	  example: "ZERO";
+//	  required: true;
+//	  ...
+//	};
+type EnumSchema struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// A short description of the schema.
+	Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	Default     string `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
+	// The title of the schema.
+	Title    string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
+	Required bool   `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"`
+	ReadOnly bool   `protobuf:"varint,5,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation `protobuf:"bytes,6,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	Example      string                 `protobuf:"bytes,7,opt,name=example,proto3" json:"example,omitempty"`
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string `protobuf:"bytes,8,opt,name=ref,proto3" json:"ref,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *EnumSchema) Reset() {
+	*x = EnumSchema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EnumSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnumSchema) ProtoMessage() {}
+
+func (x *EnumSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *EnumSchema) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetDefault() string {
+	if x != nil {
+		return x.Default
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+func (x *EnumSchema) GetReadOnly() bool {
+	if x != nil {
+		return x.ReadOnly
+	}
+	return false
+}
+
+func (x *EnumSchema) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.ExternalDocs
+	}
+	return nil
+}
+
+func (x *EnumSchema) GetExample() string {
+	if x != nil {
+		return x.Example
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetRef() string {
+	if x != nil {
+		return x.Ref
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *EnumSchema) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *EnumSchema) SetDefault(v string) {
+	x.Default = v
+}
+
+func (x *EnumSchema) SetTitle(v string) {
+	x.Title = v
+}
+
+func (x *EnumSchema) SetRequired(v bool) {
+	x.Required = v
+}
+
+func (x *EnumSchema) SetReadOnly(v bool) {
+	x.ReadOnly = v
+}
+
+func (x *EnumSchema) SetExternalDocs(v *ExternalDocumentation) {
+	x.ExternalDocs = v
+}
+
+func (x *EnumSchema) SetExample(v string) {
+	x.Example = v
+}
+
+func (x *EnumSchema) SetRef(v string) {
+	x.Ref = v
+}
+
+func (x *EnumSchema) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *EnumSchema) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.ExternalDocs != nil
+}
+
+func (x *EnumSchema) ClearExternalDocs() {
+	x.ExternalDocs = nil
+}
+
+type EnumSchema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A short description of the schema.
+	Description string
+	Default     string
+	// The title of the schema.
+	Title    string
+	Required bool
+	ReadOnly bool
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation
+	Example      string
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 EnumSchema_builder) Build() *EnumSchema {
+	m0 := &EnumSchema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Description = b.Description
+	x.Default = b.Default
+	x.Title = b.Title
+	x.Required = b.Required
+	x.ReadOnly = b.ReadOnly
+	x.ExternalDocs = b.ExternalDocs
+	x.Example = b.Example
+	x.Ref = b.Ref
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `JSONSchema` represents properties from JSON Schema taken, and as used, in
+// the OpenAPI v2 spec.
+//
+// This includes changes made by OpenAPI v2.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
+// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
+//
+// Example:
+//
+//	message SimpleMessage {
+//	  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
+//	    json_schema: {
+//	      title: "SimpleMessage"
+//	      description: "A simple message."
+//	      required: ["id"]
+//	    }
+//	  };
+//
+//	  // Id represents the message identifier.
+//	  string id = 1; [
+//	      (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+//	        description: "The unique identifier of the simple message."
+//	      }];
+//	}
+type JSONSchema struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"`
+	// The title of the schema.
+	Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"`
+	// A short description of the schema.
+	Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
+	Default     string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"`
+	ReadOnly    bool   `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	// A free-form property to include a JSON example of this field. This is copied
+	// verbatim to the output swagger.json. Quotes must be escaped.
+	// This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+	Example    string  `protobuf:"bytes,9,opt,name=example,proto3" json:"example,omitempty"`
+	MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"`
+	// Maximum represents an inclusive upper limit for a numeric instance. The
+	// value of MUST be a number,
+	Maximum          float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"`
+	ExclusiveMaximum bool    `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"`
+	// minimum represents an inclusive lower limit for a numeric instance. The
+	// value of MUST be a number,
+	Minimum          float64  `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"`
+	ExclusiveMinimum bool     `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"`
+	MaxLength        uint64   `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"`
+	MinLength        uint64   `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"`
+	Pattern          string   `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"`
+	MaxItems         uint64   `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"`
+	MinItems         uint64   `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"`
+	UniqueItems      bool     `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"`
+	MaxProperties    uint64   `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"`
+	MinProperties    uint64   `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"`
+	Required         []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"`
+	// Items in 'array' must be unique.
+	Array []string                           `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"`
+	Type  []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"`
+	// `Format`
+	Format string `protobuf:"bytes,36,opt,name=format,proto3" json:"format,omitempty"`
+	// Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+	Enum []string `protobuf:"bytes,46,rep,name=enum,proto3" json:"enum,omitempty"`
+	// Additional field level properties used when generating the OpenAPI v2 file.
+	FieldConfiguration *JSONSchema_FieldConfiguration `protobuf:"bytes,1001,opt,name=field_configuration,json=fieldConfiguration,proto3" json:"field_configuration,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,48,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *JSONSchema) Reset() {
+	*x = JSONSchema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *JSONSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JSONSchema) ProtoMessage() {}
+
+func (x *JSONSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *JSONSchema) GetRef() string {
+	if x != nil {
+		return x.Ref
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetDefault() string {
+	if x != nil {
+		return x.Default
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetReadOnly() bool {
+	if x != nil {
+		return x.ReadOnly
+	}
+	return false
+}
+
+func (x *JSONSchema) GetExample() string {
+	if x != nil {
+		return x.Example
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetMultipleOf() float64 {
+	if x != nil {
+		return x.MultipleOf
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMaximum() float64 {
+	if x != nil {
+		return x.Maximum
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetExclusiveMaximum() bool {
+	if x != nil {
+		return x.ExclusiveMaximum
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMinimum() float64 {
+	if x != nil {
+		return x.Minimum
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetExclusiveMinimum() bool {
+	if x != nil {
+		return x.ExclusiveMinimum
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMaxLength() uint64 {
+	if x != nil {
+		return x.MaxLength
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinLength() uint64 {
+	if x != nil {
+		return x.MinLength
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetPattern() string {
+	if x != nil {
+		return x.Pattern
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetMaxItems() uint64 {
+	if x != nil {
+		return x.MaxItems
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinItems() uint64 {
+	if x != nil {
+		return x.MinItems
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetUniqueItems() bool {
+	if x != nil {
+		return x.UniqueItems
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMaxProperties() uint64 {
+	if x != nil {
+		return x.MaxProperties
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinProperties() uint64 {
+	if x != nil {
+		return x.MinProperties
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetRequired() []string {
+	if x != nil {
+		return x.Required
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetArray() []string {
+	if x != nil {
+		return x.Array
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes {
+	if x != nil {
+		return x.Type
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetFormat() string {
+	if x != nil {
+		return x.Format
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetEnum() []string {
+	if x != nil {
+		return x.Enum
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetFieldConfiguration() *JSONSchema_FieldConfiguration {
+	if x != nil {
+		return x.FieldConfiguration
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *JSONSchema) SetRef(v string) {
+	x.Ref = v
+}
+
+func (x *JSONSchema) SetTitle(v string) {
+	x.Title = v
+}
+
+func (x *JSONSchema) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *JSONSchema) SetDefault(v string) {
+	x.Default = v
+}
+
+func (x *JSONSchema) SetReadOnly(v bool) {
+	x.ReadOnly = v
+}
+
+func (x *JSONSchema) SetExample(v string) {
+	x.Example = v
+}
+
+func (x *JSONSchema) SetMultipleOf(v float64) {
+	x.MultipleOf = v
+}
+
+func (x *JSONSchema) SetMaximum(v float64) {
+	x.Maximum = v
+}
+
+func (x *JSONSchema) SetExclusiveMaximum(v bool) {
+	x.ExclusiveMaximum = v
+}
+
+func (x *JSONSchema) SetMinimum(v float64) {
+	x.Minimum = v
+}
+
+func (x *JSONSchema) SetExclusiveMinimum(v bool) {
+	x.ExclusiveMinimum = v
+}
+
+func (x *JSONSchema) SetMaxLength(v uint64) {
+	x.MaxLength = v
+}
+
+func (x *JSONSchema) SetMinLength(v uint64) {
+	x.MinLength = v
+}
+
+func (x *JSONSchema) SetPattern(v string) {
+	x.Pattern = v
+}
+
+func (x *JSONSchema) SetMaxItems(v uint64) {
+	x.MaxItems = v
+}
+
+func (x *JSONSchema) SetMinItems(v uint64) {
+	x.MinItems = v
+}
+
+func (x *JSONSchema) SetUniqueItems(v bool) {
+	x.UniqueItems = v
+}
+
+func (x *JSONSchema) SetMaxProperties(v uint64) {
+	x.MaxProperties = v
+}
+
+func (x *JSONSchema) SetMinProperties(v uint64) {
+	x.MinProperties = v
+}
+
+func (x *JSONSchema) SetRequired(v []string) {
+	x.Required = v
+}
+
+func (x *JSONSchema) SetArray(v []string) {
+	x.Array = v
+}
+
+func (x *JSONSchema) SetType(v []JSONSchema_JSONSchemaSimpleTypes) {
+	x.Type = v
+}
+
+func (x *JSONSchema) SetFormat(v string) {
+	x.Format = v
+}
+
+func (x *JSONSchema) SetEnum(v []string) {
+	x.Enum = v
+}
+
+func (x *JSONSchema) SetFieldConfiguration(v *JSONSchema_FieldConfiguration) {
+	x.FieldConfiguration = v
+}
+
+func (x *JSONSchema) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *JSONSchema) HasFieldConfiguration() bool {
+	if x == nil {
+		return false
+	}
+	return x.FieldConfiguration != nil
+}
+
+func (x *JSONSchema) ClearFieldConfiguration() {
+	x.FieldConfiguration = nil
+}
+
+type JSONSchema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string
+	// The title of the schema.
+	Title string
+	// A short description of the schema.
+	Description string
+	Default     string
+	ReadOnly    bool
+	// A free-form property to include a JSON example of this field. This is copied
+	// verbatim to the output swagger.json. Quotes must be escaped.
+	// This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+	Example    string
+	MultipleOf float64
+	// Maximum represents an inclusive upper limit for a numeric instance. The
+	// value of MUST be a number,
+	Maximum          float64
+	ExclusiveMaximum bool
+	// minimum represents an inclusive lower limit for a numeric instance. The
+	// value of MUST be a number,
+	Minimum          float64
+	ExclusiveMinimum bool
+	MaxLength        uint64
+	MinLength        uint64
+	Pattern          string
+	MaxItems         uint64
+	MinItems         uint64
+	UniqueItems      bool
+	MaxProperties    uint64
+	MinProperties    uint64
+	Required         []string
+	// Items in 'array' must be unique.
+	Array []string
+	Type  []JSONSchema_JSONSchemaSimpleTypes
+	// `Format`
+	Format string
+	// Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+	Enum []string
+	// Additional field level properties used when generating the OpenAPI v2 file.
+	FieldConfiguration *JSONSchema_FieldConfiguration
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 JSONSchema_builder) Build() *JSONSchema {
+	m0 := &JSONSchema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Ref = b.Ref
+	x.Title = b.Title
+	x.Description = b.Description
+	x.Default = b.Default
+	x.ReadOnly = b.ReadOnly
+	x.Example = b.Example
+	x.MultipleOf = b.MultipleOf
+	x.Maximum = b.Maximum
+	x.ExclusiveMaximum = b.ExclusiveMaximum
+	x.Minimum = b.Minimum
+	x.ExclusiveMinimum = b.ExclusiveMinimum
+	x.MaxLength = b.MaxLength
+	x.MinLength = b.MinLength
+	x.Pattern = b.Pattern
+	x.MaxItems = b.MaxItems
+	x.MinItems = b.MinItems
+	x.UniqueItems = b.UniqueItems
+	x.MaxProperties = b.MaxProperties
+	x.MinProperties = b.MinProperties
+	x.Required = b.Required
+	x.Array = b.Array
+	x.Type = b.Type
+	x.Format = b.Format
+	x.Enum = b.Enum
+	x.FieldConfiguration = b.FieldConfiguration
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `Tag` is a representation of OpenAPI v2 specification's Tag object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
+type Tag struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// The name of the tag. Use it to allow override of the name of a
+	// global Tag object, then use that name to reference the tag throughout the
+	// OpenAPI file.
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// A short description for the tag. GFM syntax can be used for rich text
+	// representation.
+	Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	// Additional external documentation for this tag.
+	ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,4,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Tag) Reset() {
+	*x = Tag{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[13]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Tag) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Tag) ProtoMessage() {}
+
+func (x *Tag) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[13]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Tag) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Tag) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *Tag) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.ExternalDocs
+	}
+	return nil
+}
+
+func (x *Tag) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *Tag) SetName(v string) {
+	x.Name = v
+}
+
+func (x *Tag) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *Tag) SetExternalDocs(v *ExternalDocumentation) {
+	x.ExternalDocs = v
+}
+
+func (x *Tag) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *Tag) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.ExternalDocs != nil
+}
+
+func (x *Tag) ClearExternalDocs() {
+	x.ExternalDocs = nil
+}
+
+type Tag_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The name of the tag. Use it to allow override of the name of a
+	// global Tag object, then use that name to reference the tag throughout the
+	// OpenAPI file.
+	Name string
+	// A short description for the tag. GFM syntax can be used for rich text
+	// representation.
+	Description string
+	// Additional external documentation for this tag.
+	ExternalDocs *ExternalDocumentation
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Tag_builder) Build() *Tag {
+	m0 := &Tag{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Name = b.Name
+	x.Description = b.Description
+	x.ExternalDocs = b.ExternalDocs
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
+// Security Definitions object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
+//
+// A declaration of the security schemes available to be used in the
+// specification. This does not enforce the security schemes on the operations
+// and only serves to provide the relevant details for each scheme.
+type SecurityDefinitions struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// A single security scheme definition, mapping a "name" to the scheme it
+	// defines.
+	Security      map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SecurityDefinitions) Reset() {
+	*x = SecurityDefinitions{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[14]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityDefinitions) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityDefinitions) ProtoMessage() {}
+
+func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[14]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme {
+	if x != nil {
+		return x.Security
+	}
+	return nil
+}
+
+func (x *SecurityDefinitions) SetSecurity(v map[string]*SecurityScheme) {
+	x.Security = v
+}
+
+type SecurityDefinitions_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A single security scheme definition, mapping a "name" to the scheme it
+	// defines.
+	Security map[string]*SecurityScheme
+}
+
+func (b0 SecurityDefinitions_builder) Build() *SecurityDefinitions {
+	m0 := &SecurityDefinitions{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Security = b.Security
+	return m0
+}
+
+// `SecurityScheme` is a representation of OpenAPI v2 specification's
+// Security Scheme object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
+//
+// Allows the definition of a security scheme that can be used by the
+// operations. Supported schemes are basic authentication, an API key (either as
+// a header or as a query parameter) and OAuth2's common flows (implicit,
+// password, application and access code).
+type SecurityScheme struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// The type of the security scheme. Valid values are "basic",
+	// "apiKey" or "oauth2".
+	Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_Type" json:"type,omitempty"`
+	// A short description for security scheme.
+	Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	// The name of the header or query parameter to be used.
+	// Valid for apiKey.
+	Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+	// The location of the API key. Valid values are "query" or
+	// "header".
+	// Valid for apiKey.
+	In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_In" json:"in,omitempty"`
+	// The flow used by the OAuth2 security scheme. Valid values are
+	// "implicit", "password", "application" or "accessCode".
+	// Valid for oauth2.
+	Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_Flow" json:"flow,omitempty"`
+	// The authorization URL to be used for this flow. This SHOULD be in
+	// the form of a URL.
+	// Valid for oauth2/implicit and oauth2/accessCode.
+	AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"`
+	// The token URL to be used for this flow. This SHOULD be in the
+	// form of a URL.
+	// Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+	TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"`
+	// The available scopes for the OAuth2 security scheme.
+	// Valid for oauth2.
+	Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"`
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions    map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SecurityScheme) Reset() {
+	*x = SecurityScheme{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[15]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityScheme) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityScheme) ProtoMessage() {}
+
+func (x *SecurityScheme) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[15]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityScheme) GetType() SecurityScheme_Type {
+	if x != nil {
+		return x.Type
+	}
+	return SecurityScheme_TYPE_INVALID
+}
+
+func (x *SecurityScheme) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetIn() SecurityScheme_In {
+	if x != nil {
+		return x.In
+	}
+	return SecurityScheme_IN_INVALID
+}
+
+func (x *SecurityScheme) GetFlow() SecurityScheme_Flow {
+	if x != nil {
+		return x.Flow
+	}
+	return SecurityScheme_FLOW_INVALID
+}
+
+func (x *SecurityScheme) GetAuthorizationUrl() string {
+	if x != nil {
+		return x.AuthorizationUrl
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetTokenUrl() string {
+	if x != nil {
+		return x.TokenUrl
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetScopes() *Scopes {
+	if x != nil {
+		return x.Scopes
+	}
+	return nil
+}
+
+func (x *SecurityScheme) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.Extensions
+	}
+	return nil
+}
+
+func (x *SecurityScheme) SetType(v SecurityScheme_Type) {
+	x.Type = v
+}
+
+func (x *SecurityScheme) SetDescription(v string) {
+	x.Description = v
+}
+
+func (x *SecurityScheme) SetName(v string) {
+	x.Name = v
+}
+
+func (x *SecurityScheme) SetIn(v SecurityScheme_In) {
+	x.In = v
+}
+
+func (x *SecurityScheme) SetFlow(v SecurityScheme_Flow) {
+	x.Flow = v
+}
+
+func (x *SecurityScheme) SetAuthorizationUrl(v string) {
+	x.AuthorizationUrl = v
+}
+
+func (x *SecurityScheme) SetTokenUrl(v string) {
+	x.TokenUrl = v
+}
+
+func (x *SecurityScheme) SetScopes(v *Scopes) {
+	x.Scopes = v
+}
+
+func (x *SecurityScheme) SetExtensions(v map[string]*structpb.Value) {
+	x.Extensions = v
+}
+
+func (x *SecurityScheme) HasScopes() bool {
+	if x == nil {
+		return false
+	}
+	return x.Scopes != nil
+}
+
+func (x *SecurityScheme) ClearScopes() {
+	x.Scopes = nil
+}
+
+type SecurityScheme_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The type of the security scheme. Valid values are "basic",
+	// "apiKey" or "oauth2".
+	Type SecurityScheme_Type
+	// A short description for security scheme.
+	Description string
+	// The name of the header or query parameter to be used.
+	// Valid for apiKey.
+	Name string
+	// The location of the API key. Valid values are "query" or
+	// "header".
+	// Valid for apiKey.
+	In SecurityScheme_In
+	// The flow used by the OAuth2 security scheme. Valid values are
+	// "implicit", "password", "application" or "accessCode".
+	// Valid for oauth2.
+	Flow SecurityScheme_Flow
+	// The authorization URL to be used for this flow. This SHOULD be in
+	// the form of a URL.
+	// Valid for oauth2/implicit and oauth2/accessCode.
+	AuthorizationUrl string
+	// The token URL to be used for this flow. This SHOULD be in the
+	// form of a URL.
+	// Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+	TokenUrl string
+	// The available scopes for the OAuth2 security scheme.
+	// Valid for oauth2.
+	Scopes *Scopes
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 SecurityScheme_builder) Build() *SecurityScheme {
+	m0 := &SecurityScheme{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Type = b.Type
+	x.Description = b.Description
+	x.Name = b.Name
+	x.In = b.In
+	x.Flow = b.Flow
+	x.AuthorizationUrl = b.AuthorizationUrl
+	x.TokenUrl = b.TokenUrl
+	x.Scopes = b.Scopes
+	x.Extensions = b.Extensions
+	return m0
+}
+
+// `SecurityRequirement` is a representation of OpenAPI v2 specification's
+// Security Requirement object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
+//
+// Lists the required security schemes to execute this operation. The object can
+// have multiple security schemes declared in it which are all required (that
+// is, there is a logical AND between the schemes).
+//
+// The name used for each property MUST correspond to a security scheme
+// declared in the Security Definitions.
+type SecurityRequirement struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// Each name must correspond to a security scheme which is declared in
+	// the Security Definitions. If the security scheme is of type "oauth2",
+	// then the value is a list of scope names required for the execution.
+	// For other security scheme types, the array MUST be empty.
+	SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *SecurityRequirement) Reset() {
+	*x = SecurityRequirement{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[16]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityRequirement) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityRequirement) ProtoMessage() {}
+
+func (x *SecurityRequirement) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[16]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue {
+	if x != nil {
+		return x.SecurityRequirement
+	}
+	return nil
+}
+
+func (x *SecurityRequirement) SetSecurityRequirement(v map[string]*SecurityRequirement_SecurityRequirementValue) {
+	x.SecurityRequirement = v
+}
+
+type SecurityRequirement_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Each name must correspond to a security scheme which is declared in
+	// the Security Definitions. If the security scheme is of type "oauth2",
+	// then the value is a list of scope names required for the execution.
+	// For other security scheme types, the array MUST be empty.
+	SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue
+}
+
+func (b0 SecurityRequirement_builder) Build() *SecurityRequirement {
+	m0 := &SecurityRequirement{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.SecurityRequirement = b.SecurityRequirement
+	return m0
+}
+
+// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
+//
+// Lists the available scopes for an OAuth2 security scheme.
+type Scopes struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// Maps between a name of a scope to a short description of it (as the value
+	// of the property).
+	Scope         map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Scopes) Reset() {
+	*x = Scopes{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[17]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Scopes) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Scopes) ProtoMessage() {}
+
+func (x *Scopes) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[17]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Scopes) GetScope() map[string]string {
+	if x != nil {
+		return x.Scope
+	}
+	return nil
+}
+
+func (x *Scopes) SetScope(v map[string]string) {
+	x.Scope = v
+}
+
+type Scopes_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Maps between a name of a scope to a short description of it (as the value
+	// of the property).
+	Scope map[string]string
+}
+
+func (b0 Scopes_builder) Build() *Scopes {
+	m0 := &Scopes{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Scope = b.Scope
+	return m0
+}
+
+// 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file.
+// These properties are not defined by OpenAPIv2, but they are used to control the generation.
+type JSONSchema_FieldConfiguration struct {
+	state protoimpl.MessageState `protogen:"hybrid.v1"`
+	// Alternative parameter name when used as path parameter. If set, this will
+	// be used as the complete parameter name when this field is used as a path
+	// parameter. Use this to avoid having auto generated path parameter names
+	// for overlapping paths.
+	PathParamName string `protobuf:"bytes,47,opt,name=path_param_name,json=pathParamName,proto3" json:"path_param_name,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *JSONSchema_FieldConfiguration) Reset() {
+	*x = JSONSchema_FieldConfiguration{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[27]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *JSONSchema_FieldConfiguration) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JSONSchema_FieldConfiguration) ProtoMessage() {}
+
+func (x *JSONSchema_FieldConfiguration) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[27]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *JSONSchema_FieldConfiguration) GetPathParamName() string {
+	if x != nil {
+		return x.PathParamName
+	}
+	return ""
+}
+
+func (x *JSONSchema_FieldConfiguration) SetPathParamName(v string) {
+	x.PathParamName = v
+}
+
+type JSONSchema_FieldConfiguration_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Alternative parameter name when used as path parameter. If set, this will
+	// be used as the complete parameter name when this field is used as a path
+	// parameter. Use this to avoid having auto generated path parameter names
+	// for overlapping paths.
+	PathParamName string
+}
+
+func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfiguration {
+	m0 := &JSONSchema_FieldConfiguration{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.PathParamName = b.PathParamName
+	return m0
+}
+
+// If the security scheme is of type "oauth2", then the value is a list of
+// scope names required for the execution. For other security scheme types,
+// the array MUST be empty.
+type SecurityRequirement_SecurityRequirementValue struct {
+	state         protoimpl.MessageState `protogen:"hybrid.v1"`
+	Scope         []string               `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) Reset() {
+	*x = SecurityRequirement_SecurityRequirementValue{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[32]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {}
+
+func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[32]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string {
+	if x != nil {
+		return x.Scope
+	}
+	return nil
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) SetScope(v []string) {
+	x.Scope = v
+}
+
+type SecurityRequirement_SecurityRequirementValue_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	Scope []string
+}
+
+func (b0 SecurityRequirement_SecurityRequirementValue_builder) Build() *SecurityRequirement_SecurityRequirementValue {
+	m0 := &SecurityRequirement_SecurityRequirementValue{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.Scope = b.Scope
+	return m0
+}
+
+var File_protoc_gen_openapiv3_options_openapiv3_proto protoreflect.FileDescriptor
+
+var file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc = []byte{
+	0x0a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63,
+	0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x08, 0x0a, 0x07, 0x53, 0x77, 0x61, 0x67,
+	0x67, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x12, 0x43, 0x0a,
+	0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e,
+	0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70,
+	0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50,
+	0x61, 0x74, 0x68, 0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73,
+	0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08,
+	0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
+	0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09,
+	0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x14, 0x73, 0x65, 0x63,
+	0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69,
+	0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69,
+	0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72,
+	0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73,
+	0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x65, 0x0a, 0x0d,
+	0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x0e, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44,
+	0x6f, 0x63, 0x73, 0x12, 0x62, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52,
+	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0xd6, 0x07,
+	0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74,
+	0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12,
+	0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 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, 0x65, 0x0a, 0x0d, 0x65,
+	0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45,
+	0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f,
+	0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+	0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
+	0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
+	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x61, 0x0a,
+	0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65,
+	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28,
+	0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x12, 0x1e, 0x0a,
+	0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x5a, 0x0a,
+	0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52,
+	0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x64, 0x0a, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+	0x55, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0e, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61,
+	0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f,
+	0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+	0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c,
+	0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+	0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0x62, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
+	0x74, 0x65, 0x72, 0x73, 0x12, 0x54, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
+	0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0xa3, 0x02, 0x0a, 0x0f, 0x48,
+	0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x3f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x48,
+	0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2e, 0x54,
+	0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72,
+	0x6d, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x45, 0x0a,
+	0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
+	0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0a,
+	0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e,
+	0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45,
+	0x41, 0x4e, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08,
+	0x22, 0xd8, 0x01, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
+	0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66,
+	0x61, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61,
+	0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x0d,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x4a, 0x04, 0x08,
+	0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a,
+	0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10,
+	0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08,
+	0x0e, 0x10, 0x0f, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a,
+	0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0x9a, 0x05, 0x0a, 0x08,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x5a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64,
+	0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
+	0x73, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+	0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66,
+	0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 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, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x65, 0x72,
+	0x6d, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x4f, 0x66, 0x53, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63,
+	0x74, 0x12, 0x4c, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c,
+	0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12,
+	0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x45,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a,
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x22, 0x45, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75,
+	0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x2f, 0x0a, 0x07, 0x4c, 0x69, 0x63, 0x65,
+	0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x4b, 0x0a, 0x15, 0x45, 0x78, 0x74,
+	0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xaa, 0x02, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x12, 0x56, 0x0a, 0x0b, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, 0x6a,
+	0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x69, 0x73,
+	0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12,
+	0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a, 0x0d,
+	0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44,
+	0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08,
+	0x04, 0x10, 0x05, 0x22, 0xe8, 0x03, 0x0a, 0x0a, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x69, 0x74, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
+	0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a,
+	0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e,
+	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
+	0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x10,
+	0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66,
+	0x12, 0x65, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd7,
+	0x0a, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a,
+	0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12,
+	0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+	0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08,
+	0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18,
+	0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x75, 0x6c, 0x74,
+	0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x6d,
+	0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78,
+	0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69,
+	0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65,
+	0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
+	0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d,
+	0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28,
+	0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78,
+	0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18,
+	0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65,
+	0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x6c,
+	0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x78,
+	0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x65,
+	0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x4c,
+	0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e,
+	0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12,
+	0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09,
+	0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x69,
+	0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e,
+	0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x18,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74,
+	0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65,
+	0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e,
+	0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18,
+	0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x5f, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a,
+	0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66,
+	0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0x2e, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x12, 0x7a, 0x0a, 0x13, 0x66, 0x69, 0x65,
+	0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x46,
+	0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+	0x6e, 0x52, 0x12, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x30, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f,
+	0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3c, 0x0a, 0x12,
+	0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x74,
+	0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53,
+	0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e,
+	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59,
+	0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12,
+	0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04,
+	0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52,
+	0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a,
+	0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02,
+	0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x12,
+	0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04,
+	0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e,
+	0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a,
+	0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0xd9, 0x02, 0x0a, 0x03, 0x54, 0x61, 0x67,
+	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e,
+	0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e,
+	0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+	0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x5e, 0x0a,
+	0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61,
+	0x67, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a,
+	0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0xf7, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x68, 0x0a, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4c,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69,
+	0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72,
+	0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53,
+	0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65,
+	0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x1a, 0x76, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+	0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e,
+	0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67,
+	0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xff,
+	0x06, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x65, 0x12, 0x52, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x02, 0x69,
+	0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x65, 0x2e, 0x49, 0x6e, 0x52, 0x02, 0x69, 0x6e, 0x12, 0x52, 0x0a, 0x04, 0x66, 0x6c, 0x6f,
+	0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x65, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x2b, 0x0a,
+	0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75,
+	0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
+	0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f,
+	0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
+	0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65,
+	0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70,
+	0x65, 0x73, 0x12, 0x69, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a,
+	0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0e,
+	0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x01, 0x12, 0x10,
+	0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02,
+	0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, 0x10,
+	0x03, 0x22, 0x31, 0x0a, 0x02, 0x49, 0x6e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x5f, 0x49, 0x4e,
+	0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x5f, 0x51, 0x55,
+	0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x48, 0x45, 0x41, 0x44,
+	0x45, 0x52, 0x10, 0x02, 0x22, 0x6a, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x10, 0x0a, 0x0c,
+	0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x11,
+	0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, 0x10,
+	0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f,
+	0x52, 0x44, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x50, 0x50,
+	0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c,
+	0x4f, 0x57, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x04,
+	0x22, 0xf6, 0x02, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71,
+	0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x8a, 0x01, 0x0a, 0x14, 0x73, 0x65, 0x63,
+	0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e,
+	0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75,
+	0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+	0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72,
+	0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x30, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x9f, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x6d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72,
+	0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x53, 0x63,
+	0x6f, 0x70, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x38, 0x0a, 0x0a, 0x53, 0x63, 0x6f, 0x70,
+	0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
+	0x38, 0x01, 0x2a, 0x3b, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x0b, 0x0a, 0x07,
+	0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54,
+	0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x12, 0x06,
+	0x0a, 0x02, 0x57, 0x53, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x57, 0x53, 0x53, 0x10, 0x04, 0x42,
+	0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72,
+	0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70,
+	0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
+}
+
+var file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
+var file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes = make([]protoimpl.MessageInfo, 35)
+var file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes = []any{
+	(Scheme)(0),                           // 0: grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	(HeaderParameter_Type)(0),             // 1: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.Type
+	(JSONSchema_JSONSchemaSimpleTypes)(0), // 2: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.JSONSchemaSimpleTypes
+	(SecurityScheme_Type)(0),              // 3: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Type
+	(SecurityScheme_In)(0),                // 4: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.In
+	(SecurityScheme_Flow)(0),              // 5: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Flow
+	(*Swagger)(nil),                       // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	(*Operation)(nil),                     // 7: grpc.gateway.protoc_gen_openapiv3.options.Operation
+	(*Parameters)(nil),                    // 8: grpc.gateway.protoc_gen_openapiv3.options.Parameters
+	(*HeaderParameter)(nil),               // 9: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter
+	(*Header)(nil),                        // 10: grpc.gateway.protoc_gen_openapiv3.options.Header
+	(*Response)(nil),                      // 11: grpc.gateway.protoc_gen_openapiv3.options.Response
+	(*Info)(nil),                          // 12: grpc.gateway.protoc_gen_openapiv3.options.Info
+	(*Contact)(nil),                       // 13: grpc.gateway.protoc_gen_openapiv3.options.Contact
+	(*License)(nil),                       // 14: grpc.gateway.protoc_gen_openapiv3.options.License
+	(*ExternalDocumentation)(nil),         // 15: grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	(*Schema)(nil),                        // 16: grpc.gateway.protoc_gen_openapiv3.options.Schema
+	(*EnumSchema)(nil),                    // 17: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	(*JSONSchema)(nil),                    // 18: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	(*Tag)(nil),                           // 19: grpc.gateway.protoc_gen_openapiv3.options.Tag
+	(*SecurityDefinitions)(nil),           // 20: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions
+	(*SecurityScheme)(nil),                // 21: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme
+	(*SecurityRequirement)(nil),           // 22: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	(*Scopes)(nil),                        // 23: grpc.gateway.protoc_gen_openapiv3.options.Scopes
+	nil,                                   // 24: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry
+	nil,                                   // 25: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry
+	nil,                                   // 26: grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry
+	nil,                                   // 27: grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry
+	nil,                                   // 28: grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry
+	nil,                                   // 29: grpc.gateway.protoc_gen_openapiv3.options.Response.ExamplesEntry
+	nil,                                   // 30: grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry
+	nil,                                   // 31: grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry
+	nil,                                   // 32: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry
+	(*JSONSchema_FieldConfiguration)(nil), // 33: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.FieldConfiguration
+	nil,                                   // 34: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry
+	nil,                                   // 35: grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry
+	nil,                                   // 36: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry
+	nil,                                   // 37: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry
+	(*SecurityRequirement_SecurityRequirementValue)(nil), // 38: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementValue
+	nil,                    // 39: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry
+	nil,                    // 40: grpc.gateway.protoc_gen_openapiv3.options.Scopes.ScopeEntry
+	(*structpb.Value)(nil), // 41: google.protobuf.Value
+}
+var file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs = []int32{
+	12, // 0: grpc.gateway.protoc_gen_openapiv3.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Info
+	0,  // 1: grpc.gateway.protoc_gen_openapiv3.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	24, // 2: grpc.gateway.protoc_gen_openapiv3.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry
+	20, // 3: grpc.gateway.protoc_gen_openapiv3.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions
+	22, // 4: grpc.gateway.protoc_gen_openapiv3.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	19, // 5: grpc.gateway.protoc_gen_openapiv3.options.Swagger.tags:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag
+	15, // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	25, // 7: grpc.gateway.protoc_gen_openapiv3.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry
+	15, // 8: grpc.gateway.protoc_gen_openapiv3.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	26, // 9: grpc.gateway.protoc_gen_openapiv3.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry
+	0,  // 10: grpc.gateway.protoc_gen_openapiv3.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	22, // 11: grpc.gateway.protoc_gen_openapiv3.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	27, // 12: grpc.gateway.protoc_gen_openapiv3.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry
+	8,  // 13: grpc.gateway.protoc_gen_openapiv3.options.Operation.parameters:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Parameters
+	9,  // 14: grpc.gateway.protoc_gen_openapiv3.options.Parameters.headers:type_name -> grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter
+	1,  // 15: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.Type
+	16, // 16: grpc.gateway.protoc_gen_openapiv3.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Schema
+	28, // 17: grpc.gateway.protoc_gen_openapiv3.options.Response.headers:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry
+	29, // 18: grpc.gateway.protoc_gen_openapiv3.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.ExamplesEntry
+	30, // 19: grpc.gateway.protoc_gen_openapiv3.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry
+	13, // 20: grpc.gateway.protoc_gen_openapiv3.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Contact
+	14, // 21: grpc.gateway.protoc_gen_openapiv3.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv3.options.License
+	31, // 22: grpc.gateway.protoc_gen_openapiv3.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry
+	18, // 23: grpc.gateway.protoc_gen_openapiv3.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	15, // 24: grpc.gateway.protoc_gen_openapiv3.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	15, // 25: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	32, // 26: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry
+	2,  // 27: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.JSONSchemaSimpleTypes
+	33, // 28: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.field_configuration:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.FieldConfiguration
+	34, // 29: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry
+	15, // 30: grpc.gateway.protoc_gen_openapiv3.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	35, // 31: grpc.gateway.protoc_gen_openapiv3.options.Tag.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry
+	36, // 32: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry
+	3,  // 33: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Type
+	4,  // 34: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.In
+	5,  // 35: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Flow
+	23, // 36: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scopes
+	37, // 37: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry
+	39, // 38: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry
+	40, // 39: grpc.gateway.protoc_gen_openapiv3.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scopes.ScopeEntry
+	11, // 40: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response
+	41, // 41: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	11, // 42: grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response
+	41, // 43: grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	10, // 44: grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Header
+	41, // 45: grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 46: grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 47: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 48: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 49: grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	21, // 50: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme
+	41, // 51: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	38, // 52: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementValue
+	53, // [53:53] is the sub-list for method output_type
+	53, // [53:53] is the sub-list for method input_type
+	53, // [53:53] is the sub-list for extension type_name
+	53, // [53:53] is the sub-list for extension extendee
+	0,  // [0:53] is the sub-list for field type_name
+}
+
+func init() { file_protoc_gen_openapiv3_options_openapiv3_proto_init() }
+func file_protoc_gen_openapiv3_options_openapiv3_proto_init() {
+	if File_protoc_gen_openapiv3_options_openapiv3_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc,
+			NumEnums:      6,
+			NumMessages:   35,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes,
+		DependencyIndexes: file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs,
+		EnumInfos:         file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes,
+		MessageInfos:      file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes,
+	}.Build()
+	File_protoc_gen_openapiv3_options_openapiv3_proto = out.File
+	file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc = nil
+	file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes = nil
+	file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs = nil
+}
diff --git a/protoc-gen-openapiv3/options/openapiv3.proto b/protoc-gen-openapiv3/options/openapiv3.proto
new file mode 100644
index 00000000000..a9acfbae237
--- /dev/null
+++ b/protoc-gen-openapiv3/options/openapiv3.proto
@@ -0,0 +1,759 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_openapiv3.options;
+
+import "google/protobuf/struct.proto";
+
+option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3/options";
+
+// Scheme describes the schemes supported by the OpenAPI Swagger
+// and Operation objects.
+enum Scheme {
+  UNKNOWN = 0;
+  HTTP = 1;
+  HTTPS = 2;
+  WS = 3;
+  WSS = 4;
+}
+
+// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      title: "Echo API";
+//      version: "1.0";
+//      description: "";
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//      };
+//    };
+//    schemes: HTTPS;
+//    consumes: "application/json";
+//    produces: "application/json";
+//  };
+//
+message Swagger {
+  // Specifies the OpenAPI Specification version being used. It can be
+  // used by the OpenAPI UI and other clients to interpret the API listing. The
+  // value MUST be "2.0".
+  string swagger = 1;
+  // Provides metadata about the API. The metadata can be used by the
+  // clients if needed.
+  Info info = 2;
+  // The host (name or ip) serving the API. This MUST be the host only and does
+  // not include the scheme nor sub-paths. It MAY include a port. If the host is
+  // not included, the host serving the documentation is to be used (including
+  // the port). The host does not support path templating.
+  string host = 3;
+  // The base path on which the API is served, which is relative to the host. If
+  // it is not included, the API is served directly under the host. The value
+  // MUST start with a leading slash (/). The basePath does not support path
+  // templating.
+  // Note that using `base_path` does not change the endpoint paths that are
+  // generated in the resulting OpenAPI file. If you wish to use `base_path`
+  // with relatively generated OpenAPI paths, the `base_path` prefix must be
+  // manually removed from your `google.api.http` paths and your code changed to
+  // serve the API from the `base_path`.
+  string base_path = 4;
+  // The transfer protocol of the API. Values MUST be from the list: "http",
+  // "https", "ws", "wss". If the schemes is not included, the default scheme to
+  // be used is the one used to access the OpenAPI definition itself.
+  repeated Scheme schemes = 5;
+  // A list of MIME types the APIs can consume. This is global to all APIs but
+  // can be overridden on specific API calls. Value MUST be as described under
+  // Mime Types.
+  repeated string consumes = 6;
+  // A list of MIME types the APIs can produce. This is global to all APIs but
+  // can be overridden on specific API calls. Value MUST be as described under
+  // Mime Types.
+  repeated string produces = 7;
+  // field 8 is reserved for 'paths'.
+  reserved 8;
+  // field 9 is reserved for 'definitions', which at this time are already
+  // exposed as and customizable as proto messages.
+  reserved 9;
+  // An object to hold responses that can be used across operations. This
+  // property does not define global responses for all operations.
+  map responses = 10;
+  // Security scheme definitions that can be used across the specification.
+  SecurityDefinitions security_definitions = 11;
+  // A declaration of which security schemes are applied for the API as a whole.
+  // The list of values describes alternative security schemes that can be used
+  // (that is, there is a logical OR between the security requirements).
+  // Individual operations can override this definition.
+  repeated SecurityRequirement security = 12;
+  // A list of tags for API documentation control. Tags can be used for logical
+  // grouping of operations by resources or any other qualifier.
+  repeated Tag tags = 13;
+  // Additional external documentation.
+  ExternalDocumentation external_docs = 14;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 15;
+}
+
+// `Operation` is a representation of OpenAPI v2 specification's Operation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
+//
+// Example:
+//
+//  service EchoService {
+//    rpc Echo(SimpleMessage) returns (SimpleMessage) {
+//      option (google.api.http) = {
+//        get: "/v1/example/echo/{id}"
+//      };
+//
+//      option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
+//        summary: "Get a message.";
+//        operation_id: "getMessage";
+//        tags: "echo";
+//        responses: {
+//          key: "200"
+//            value: {
+//            description: "OK";
+//          }
+//        }
+//      };
+//    }
+//  }
+message Operation {
+  // A list of tags for API documentation control. Tags can be used for logical
+  // grouping of operations by resources or any other qualifier.
+  repeated string tags = 1;
+  // A short summary of what the operation does. For maximum readability in the
+  // swagger-ui, this field SHOULD be less than 120 characters.
+  string summary = 2;
+  // A verbose explanation of the operation behavior. GFM syntax can be used for
+  // rich text representation.
+  string description = 3;
+  // Additional external documentation for this operation.
+  ExternalDocumentation external_docs = 4;
+  // Unique string used to identify the operation. The id MUST be unique among
+  // all operations described in the API. Tools and libraries MAY use the
+  // operationId to uniquely identify an operation, therefore, it is recommended
+  // to follow common programming naming conventions.
+  string operation_id = 5;
+  // A list of MIME types the operation can consume. This overrides the consumes
+  // definition at the OpenAPI Object. An empty value MAY be used to clear the
+  // global definition. Value MUST be as described under Mime Types.
+  repeated string consumes = 6;
+  // A list of MIME types the operation can produce. This overrides the produces
+  // definition at the OpenAPI Object. An empty value MAY be used to clear the
+  // global definition. Value MUST be as described under Mime Types.
+  repeated string produces = 7;
+  // field 8 is reserved for 'parameters'.
+  reserved 8;
+  // The list of possible responses as they are returned from executing this
+  // operation.
+  map responses = 9;
+  // The transfer protocol for the operation. Values MUST be from the list:
+  // "http", "https", "ws", "wss". The value overrides the OpenAPI Object
+  // schemes definition.
+  repeated Scheme schemes = 10;
+  // Declares this operation to be deprecated. Usage of the declared operation
+  // should be refrained. Default value is false.
+  bool deprecated = 11;
+  // A declaration of which security schemes are applied for this operation. The
+  // list of values describes alternative security schemes that can be used
+  // (that is, there is a logical OR between the security requirements). This
+  // definition overrides any declared top-level security. To remove a top-level
+  // security declaration, an empty array can be used.
+  repeated SecurityRequirement security = 12;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 13;
+  // Custom parameters such as HTTP request headers.
+  // See: https://swagger.io/docs/specification/2-0/describing-parameters/
+  // and https://swagger.io/specification/v2/#parameter-object.
+  Parameters parameters = 14;
+}
+
+// `Parameters` is a representation of OpenAPI v2 specification's parameters object.
+// Note: This technically breaks compatibility with the OpenAPI 2 definition structure as we only
+// allow header parameters to be set here since we do not want users specifying custom non-header
+// parameters beyond those inferred from the Protobuf schema.
+// See: https://swagger.io/specification/v2/#parameter-object
+message Parameters {
+  // `Headers` is one or more HTTP header parameter.
+  // See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
+  repeated HeaderParameter headers = 1;
+}
+
+// `HeaderParameter` a HTTP header parameter.
+// See: https://swagger.io/specification/v2/#parameter-object
+message HeaderParameter {
+  // `Type` is a supported HTTP header type.
+  // See https://swagger.io/specification/v2/#parameterType.
+  enum Type {
+    UNKNOWN = 0;
+    STRING = 1;
+    NUMBER = 2;
+    INTEGER = 3;
+    BOOLEAN = 4;
+  }
+
+  // `Name` is the header name.
+  string name = 1;
+  // `Description` is a short description of the header.
+  string description = 2;
+  // `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+  // See: https://swagger.io/specification/v2/#parameterType.
+  Type type = 3;
+  // `Format` The extending format for the previously mentioned type.
+  string format = 4;
+  // `Required` indicates if the header is optional
+  bool required = 5;
+  // field 6 is reserved for 'items', but in OpenAPI-specific way.
+  reserved 6;
+  // field 7 is reserved `Collection Format`. Determines the format of the array if type array is used.
+  reserved 7;
+}
+
+// `Header` is a representation of OpenAPI v2 specification's Header object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+//
+message Header {
+  // `Description` is a short description of the header.
+  string description = 1;
+  // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+  string type = 2;
+  // `Format` The extending format for the previously mentioned type.
+  string format = 3;
+  // field 4 is reserved for 'items', but in OpenAPI-specific way.
+  reserved 4;
+  // field 5 is reserved `Collection Format` Determines the format of the array if type array is used.
+  reserved 5;
+  // `Default` Declares the value of the header that the server will use if none is provided.
+  // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+  // Unlike JSON Schema this value MUST conform to the defined type for the header.
+  string default = 6;
+  // field 7 is reserved for 'maximum'.
+  reserved 7;
+  // field 8 is reserved for 'exclusiveMaximum'.
+  reserved 8;
+  // field 9 is reserved for 'minimum'.
+  reserved 9;
+  // field 10 is reserved for 'exclusiveMinimum'.
+  reserved 10;
+  // field 11 is reserved for 'maxLength'.
+  reserved 11;
+  // field 12 is reserved for 'minLength'.
+  reserved 12;
+  // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+  string pattern = 13;
+  // field 14 is reserved for 'maxItems'.
+  reserved 14;
+  // field 15 is reserved for 'minItems'.
+  reserved 15;
+  // field 16 is reserved for 'uniqueItems'.
+  reserved 16;
+  // field 17 is reserved for 'enum'.
+  reserved 17;
+  // field 18 is reserved for 'multipleOf'.
+  reserved 18;
+}
+
+// `Response` is a representation of OpenAPI v2 specification's Response object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
+//
+message Response {
+  // `Description` is a short description of the response.
+  // GFM syntax can be used for rich text representation.
+  string description = 1;
+  // `Schema` optionally defines the structure of the response.
+  // If `Schema` is not provided, it means there is no content to the response.
+  Schema schema = 2;
+  // `Headers` A list of headers that are sent with the response.
+  // `Header` name is expected to be a string in the canonical format of the MIME header key
+  // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+  map headers = 3;
+  // `Examples` gives per-mimetype response examples.
+  // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+  map examples = 4;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 5;
+}
+
+// `Info` is a representation of OpenAPI v2 specification's Info object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      title: "Echo API";
+//      version: "1.0";
+//      description: "";
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//      };
+//    };
+//    ...
+//  };
+//
+message Info {
+  // The title of the application.
+  string title = 1;
+  // A short description of the application. GFM syntax can be used for rich
+  // text representation.
+  string description = 2;
+  // The Terms of Service for the API.
+  string terms_of_service = 3;
+  // The contact information for the exposed API.
+  Contact contact = 4;
+  // The license information for the exposed API.
+  License license = 5;
+  // Provides the version of the application API (not to be confused
+  // with the specification version).
+  string version = 6;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 7;
+}
+
+// `Contact` is a representation of OpenAPI v2 specification's Contact object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      ...
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      ...
+//    };
+//    ...
+//  };
+//
+message Contact {
+  // The identifying name of the contact person/organization.
+  string name = 1;
+  // The URL pointing to the contact information. MUST be in the format of a
+  // URL.
+  string url = 2;
+  // The email address of the contact person/organization. MUST be in the format
+  // of an email address.
+  string email = 3;
+}
+
+// `License` is a representation of OpenAPI v2 specification's License object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      ...
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//      };
+//      ...
+//    };
+//    ...
+//  };
+//
+message License {
+  // The license name used for the API.
+  string name = 1;
+  // A URL to the license used for the API. MUST be in the format of a URL.
+  string url = 2;
+}
+
+// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
+// ExternalDocumentation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    ...
+//    external_docs: {
+//      description: "More about gRPC-Gateway";
+//      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//    }
+//    ...
+//  };
+//
+message ExternalDocumentation {
+  // A short description of the target documentation. GFM syntax can be used for
+  // rich text representation.
+  string description = 1;
+  // The URL for the target documentation. Value MUST be in the format
+  // of a URL.
+  string url = 2;
+}
+
+// `Schema` is a representation of OpenAPI v2 specification's Schema object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+message Schema {
+  JSONSchema json_schema = 1;
+  // Adds support for polymorphism. The discriminator is the schema property
+  // name that is used to differentiate between other schema that inherit this
+  // schema. The property name used MUST be defined at this schema and it MUST
+  // be in the required property list. When used, the value MUST be the name of
+  // this schema or any schema that inherits it.
+  string discriminator = 2;
+  // Relevant only for Schema "properties" definitions. Declares the property as
+  // "read only". This means that it MAY be sent as part of a response but MUST
+  // NOT be sent as part of the request. Properties marked as readOnly being
+  // true SHOULD NOT be in the required list of the defined schema. Default
+  // value is false.
+  bool read_only = 3;
+  // field 4 is reserved for 'xml'.
+  reserved 4;
+  // Additional external documentation for this schema.
+  ExternalDocumentation external_docs = 5;
+  // A free-form property to include an example of an instance for this schema in JSON.
+  // This is copied verbatim to the output.
+  string example = 6;
+}
+
+// `EnumSchema` is subset of fields from the OpenAPI v2 specification's Schema object.
+// Only fields that are applicable to Enums are included
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
+//    ...
+//    title: "MyEnum";
+//    description:"This is my nice enum";
+//    example: "ZERO";
+//    required: true;
+//    ...
+//  };
+//
+message EnumSchema {
+  // A short description of the schema.
+  string description = 1;
+  string default = 2;
+  // The title of the schema.
+  string title = 3;
+  bool required = 4;
+  bool read_only = 5;
+  // Additional external documentation for this schema.
+  ExternalDocumentation external_docs = 6;
+  string example = 7;
+  // Ref is used to define an external reference to include in the message.
+  // This could be a fully qualified proto message reference, and that type must
+  // be imported into the protofile. If no message is identified, the Ref will
+  // be used verbatim in the output.
+  // For example:
+  //  `ref: ".google.protobuf.Timestamp"`.
+  string ref = 8;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 9;
+}
+
+// `JSONSchema` represents properties from JSON Schema taken, and as used, in
+// the OpenAPI v2 spec.
+//
+// This includes changes made by OpenAPI v2.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
+// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
+//
+// Example:
+//
+//  message SimpleMessage {
+//    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
+//      json_schema: {
+//        title: "SimpleMessage"
+//        description: "A simple message."
+//        required: ["id"]
+//      }
+//    };
+//
+//    // Id represents the message identifier.
+//    string id = 1; [
+//        (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+//          description: "The unique identifier of the simple message."
+//        }];
+//  }
+//
+message JSONSchema {
+  // field 1 is reserved for '$id', omitted from OpenAPI v2.
+  reserved 1;
+  // field 2 is reserved for '$schema', omitted from OpenAPI v2.
+  reserved 2;
+  // Ref is used to define an external reference to include in the message.
+  // This could be a fully qualified proto message reference, and that type must
+  // be imported into the protofile. If no message is identified, the Ref will
+  // be used verbatim in the output.
+  // For example:
+  //  `ref: ".google.protobuf.Timestamp"`.
+  string ref = 3;
+  // field 4 is reserved for '$comment', omitted from OpenAPI v2.
+  reserved 4;
+  // The title of the schema.
+  string title = 5;
+  // A short description of the schema.
+  string description = 6;
+  string default = 7;
+  bool read_only = 8;
+  // A free-form property to include a JSON example of this field. This is copied
+  // verbatim to the output swagger.json. Quotes must be escaped.
+  // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+  string example = 9;
+  double multiple_of = 10;
+  // Maximum represents an inclusive upper limit for a numeric instance. The
+  // value of MUST be a number,
+  double maximum = 11;
+  bool exclusive_maximum = 12;
+  // minimum represents an inclusive lower limit for a numeric instance. The
+  // value of MUST be a number,
+  double minimum = 13;
+  bool exclusive_minimum = 14;
+  uint64 max_length = 15;
+  uint64 min_length = 16;
+  string pattern = 17;
+  // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2.
+  reserved 18;
+  // field 19 is reserved for 'items', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'items'?
+  reserved 19;
+  uint64 max_items = 20;
+  uint64 min_items = 21;
+  bool unique_items = 22;
+  // field 23 is reserved for 'contains', omitted from OpenAPI v2.
+  reserved 23;
+  uint64 max_properties = 24;
+  uint64 min_properties = 25;
+  repeated string required = 26;
+  // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific
+  // way. TODO(ivucica): add 'additionalProperties'?
+  reserved 27;
+  // field 28 is reserved for 'definitions', omitted from OpenAPI v2.
+  reserved 28;
+  // field 29 is reserved for 'properties', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'additionalProperties'?
+  reserved 29;
+  // following fields are reserved, as the properties have been omitted from
+  // OpenAPI v2:
+  // patternProperties, dependencies, propertyNames, const
+  reserved 30 to 33;
+  // Items in 'array' must be unique.
+  repeated string array = 34;
+
+  enum JSONSchemaSimpleTypes {
+    UNKNOWN = 0;
+    ARRAY = 1;
+    BOOLEAN = 2;
+    INTEGER = 3;
+    NULL = 4;
+    NUMBER = 5;
+    OBJECT = 6;
+    STRING = 7;
+  }
+
+  repeated JSONSchemaSimpleTypes type = 35;
+  // `Format`
+  string format = 36;
+  // following fields are reserved, as the properties have been omitted from
+  // OpenAPI v2: contentMediaType, contentEncoding, if, then, else
+  reserved 37 to 41;
+  // field 42 is reserved for 'allOf', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'allOf'?
+  reserved 42;
+  // following fields are reserved, as the properties have been omitted from
+  // OpenAPI v2:
+  // anyOf, oneOf, not
+  reserved 43 to 45;
+  // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+  repeated string enum = 46;
+
+  // Additional field level properties used when generating the OpenAPI v2 file.
+  FieldConfiguration field_configuration = 1001;
+
+  // 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file.
+  // These properties are not defined by OpenAPIv2, but they are used to control the generation.
+  message FieldConfiguration {
+    // Alternative parameter name when used as path parameter. If set, this will
+    // be used as the complete parameter name when this field is used as a path
+    // parameter. Use this to avoid having auto generated path parameter names
+    // for overlapping paths.
+    string path_param_name = 47;
+  }
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 48;
+}
+
+// `Tag` is a representation of OpenAPI v2 specification's Tag object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
+//
+message Tag {
+  // The name of the tag. Use it to allow override of the name of a
+  // global Tag object, then use that name to reference the tag throughout the
+  // OpenAPI file.
+  string name = 1;
+  // A short description for the tag. GFM syntax can be used for rich text
+  // representation.
+  string description = 2;
+  // Additional external documentation for this tag.
+  ExternalDocumentation external_docs = 3;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 4;
+}
+
+// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
+// Security Definitions object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
+//
+// A declaration of the security schemes available to be used in the
+// specification. This does not enforce the security schemes on the operations
+// and only serves to provide the relevant details for each scheme.
+message SecurityDefinitions {
+  // A single security scheme definition, mapping a "name" to the scheme it
+  // defines.
+  map security = 1;
+}
+
+// `SecurityScheme` is a representation of OpenAPI v2 specification's
+// Security Scheme object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
+//
+// Allows the definition of a security scheme that can be used by the
+// operations. Supported schemes are basic authentication, an API key (either as
+// a header or as a query parameter) and OAuth2's common flows (implicit,
+// password, application and access code).
+message SecurityScheme {
+  // The type of the security scheme. Valid values are "basic",
+  // "apiKey" or "oauth2".
+  enum Type {
+    TYPE_INVALID = 0;
+    TYPE_BASIC = 1;
+    TYPE_API_KEY = 2;
+    TYPE_OAUTH2 = 3;
+  }
+
+  // The location of the API key. Valid values are "query" or "header".
+  enum In {
+    IN_INVALID = 0;
+    IN_QUERY = 1;
+    IN_HEADER = 2;
+  }
+
+  // The flow used by the OAuth2 security scheme. Valid values are
+  // "implicit", "password", "application" or "accessCode".
+  enum Flow {
+    FLOW_INVALID = 0;
+    FLOW_IMPLICIT = 1;
+    FLOW_PASSWORD = 2;
+    FLOW_APPLICATION = 3;
+    FLOW_ACCESS_CODE = 4;
+  }
+
+  // The type of the security scheme. Valid values are "basic",
+  // "apiKey" or "oauth2".
+  Type type = 1;
+  // A short description for security scheme.
+  string description = 2;
+  // The name of the header or query parameter to be used.
+  // Valid for apiKey.
+  string name = 3;
+  // The location of the API key. Valid values are "query" or
+  // "header".
+  // Valid for apiKey.
+  In in = 4;
+  // The flow used by the OAuth2 security scheme. Valid values are
+  // "implicit", "password", "application" or "accessCode".
+  // Valid for oauth2.
+  Flow flow = 5;
+  // The authorization URL to be used for this flow. This SHOULD be in
+  // the form of a URL.
+  // Valid for oauth2/implicit and oauth2/accessCode.
+  string authorization_url = 6;
+  // The token URL to be used for this flow. This SHOULD be in the
+  // form of a URL.
+  // Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+  string token_url = 7;
+  // The available scopes for the OAuth2 security scheme.
+  // Valid for oauth2.
+  Scopes scopes = 8;
+  // Custom properties that start with "x-" such as "x-foo" used to describe
+  // extra functionality that is not covered by the standard OpenAPI Specification.
+  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+  map extensions = 9;
+}
+
+// `SecurityRequirement` is a representation of OpenAPI v2 specification's
+// Security Requirement object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
+//
+// Lists the required security schemes to execute this operation. The object can
+// have multiple security schemes declared in it which are all required (that
+// is, there is a logical AND between the schemes).
+//
+// The name used for each property MUST correspond to a security scheme
+// declared in the Security Definitions.
+message SecurityRequirement {
+  // If the security scheme is of type "oauth2", then the value is a list of
+  // scope names required for the execution. For other security scheme types,
+  // the array MUST be empty.
+  message SecurityRequirementValue {
+    repeated string scope = 1;
+  }
+  // Each name must correspond to a security scheme which is declared in
+  // the Security Definitions. If the security scheme is of type "oauth2",
+  // then the value is a list of scope names required for the execution.
+  // For other security scheme types, the array MUST be empty.
+  map security_requirement = 1;
+}
+
+// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
+//
+// Lists the available scopes for an OAuth2 security scheme.
+message Scopes {
+  // Maps between a name of a scope to a short description of it (as the value
+  // of the property).
+  map scope = 1;
+}
diff --git a/protoc-gen-openapiv3/options/openapiv3.swagger.json b/protoc-gen-openapiv3/options/openapiv3.swagger.json
new file mode 100644
index 00000000000..96c133b92ca
--- /dev/null
+++ b/protoc-gen-openapiv3/options/openapiv3.swagger.json
@@ -0,0 +1,44 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "protoc-gen-openapiv3/options/openapiv3.proto",
+    "version": "version not set"
+  },
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {},
+  "definitions": {
+    "protobufAny": {
+      "type": "object",
+      "properties": {
+        "@type": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": {}
+    },
+    "rpcStatus": {
+      "type": "object",
+      "properties": {
+        "code": {
+          "type": "integer",
+          "format": "int32"
+        },
+        "message": {
+          "type": "string"
+        },
+        "details": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "$ref": "#/definitions/protobufAny"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/protoc-gen-openapiv3/options/openapiv3_protoopaque.pb.go b/protoc-gen-openapiv3/options/openapiv3_protoopaque.pb.go
new file mode 100644
index 00000000000..85f40fce86f
--- /dev/null
+++ b/protoc-gen-openapiv3/options/openapiv3_protoopaque.pb.go
@@ -0,0 +1,4055 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.0
+// 	protoc        (unknown)
+// source: protoc-gen-openapiv3/options/openapiv3.proto
+
+//go:build protoopaque
+
+package options
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	structpb "google.golang.org/protobuf/types/known/structpb"
+	reflect "reflect"
+)
+
+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)
+)
+
+// Scheme describes the schemes supported by the OpenAPI Swagger
+// and Operation objects.
+type Scheme int32
+
+const (
+	Scheme_UNKNOWN Scheme = 0
+	Scheme_HTTP    Scheme = 1
+	Scheme_HTTPS   Scheme = 2
+	Scheme_WS      Scheme = 3
+	Scheme_WSS     Scheme = 4
+)
+
+// Enum value maps for Scheme.
+var (
+	Scheme_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "HTTP",
+		2: "HTTPS",
+		3: "WS",
+		4: "WSS",
+	}
+	Scheme_value = map[string]int32{
+		"UNKNOWN": 0,
+		"HTTP":    1,
+		"HTTPS":   2,
+		"WS":      3,
+		"WSS":     4,
+	}
+)
+
+func (x Scheme) Enum() *Scheme {
+	p := new(Scheme)
+	*p = x
+	return p
+}
+
+func (x Scheme) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Scheme) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[0].Descriptor()
+}
+
+func (Scheme) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[0]
+}
+
+func (x Scheme) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// `Type` is a supported HTTP header type.
+// See https://swagger.io/specification/v2/#parameterType.
+type HeaderParameter_Type int32
+
+const (
+	HeaderParameter_UNKNOWN HeaderParameter_Type = 0
+	HeaderParameter_STRING  HeaderParameter_Type = 1
+	HeaderParameter_NUMBER  HeaderParameter_Type = 2
+	HeaderParameter_INTEGER HeaderParameter_Type = 3
+	HeaderParameter_BOOLEAN HeaderParameter_Type = 4
+)
+
+// Enum value maps for HeaderParameter_Type.
+var (
+	HeaderParameter_Type_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "STRING",
+		2: "NUMBER",
+		3: "INTEGER",
+		4: "BOOLEAN",
+	}
+	HeaderParameter_Type_value = map[string]int32{
+		"UNKNOWN": 0,
+		"STRING":  1,
+		"NUMBER":  2,
+		"INTEGER": 3,
+		"BOOLEAN": 4,
+	}
+)
+
+func (x HeaderParameter_Type) Enum() *HeaderParameter_Type {
+	p := new(HeaderParameter_Type)
+	*p = x
+	return p
+}
+
+func (x HeaderParameter_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (HeaderParameter_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[1].Descriptor()
+}
+
+func (HeaderParameter_Type) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[1]
+}
+
+func (x HeaderParameter_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+type JSONSchema_JSONSchemaSimpleTypes int32
+
+const (
+	JSONSchema_UNKNOWN JSONSchema_JSONSchemaSimpleTypes = 0
+	JSONSchema_ARRAY   JSONSchema_JSONSchemaSimpleTypes = 1
+	JSONSchema_BOOLEAN JSONSchema_JSONSchemaSimpleTypes = 2
+	JSONSchema_INTEGER JSONSchema_JSONSchemaSimpleTypes = 3
+	JSONSchema_NULL    JSONSchema_JSONSchemaSimpleTypes = 4
+	JSONSchema_NUMBER  JSONSchema_JSONSchemaSimpleTypes = 5
+	JSONSchema_OBJECT  JSONSchema_JSONSchemaSimpleTypes = 6
+	JSONSchema_STRING  JSONSchema_JSONSchemaSimpleTypes = 7
+)
+
+// Enum value maps for JSONSchema_JSONSchemaSimpleTypes.
+var (
+	JSONSchema_JSONSchemaSimpleTypes_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "ARRAY",
+		2: "BOOLEAN",
+		3: "INTEGER",
+		4: "NULL",
+		5: "NUMBER",
+		6: "OBJECT",
+		7: "STRING",
+	}
+	JSONSchema_JSONSchemaSimpleTypes_value = map[string]int32{
+		"UNKNOWN": 0,
+		"ARRAY":   1,
+		"BOOLEAN": 2,
+		"INTEGER": 3,
+		"NULL":    4,
+		"NUMBER":  5,
+		"OBJECT":  6,
+		"STRING":  7,
+	}
+)
+
+func (x JSONSchema_JSONSchemaSimpleTypes) Enum() *JSONSchema_JSONSchemaSimpleTypes {
+	p := new(JSONSchema_JSONSchemaSimpleTypes)
+	*p = x
+	return p
+}
+
+func (x JSONSchema_JSONSchemaSimpleTypes) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (JSONSchema_JSONSchemaSimpleTypes) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[2].Descriptor()
+}
+
+func (JSONSchema_JSONSchemaSimpleTypes) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[2]
+}
+
+func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The type of the security scheme. Valid values are "basic",
+// "apiKey" or "oauth2".
+type SecurityScheme_Type int32
+
+const (
+	SecurityScheme_TYPE_INVALID SecurityScheme_Type = 0
+	SecurityScheme_TYPE_BASIC   SecurityScheme_Type = 1
+	SecurityScheme_TYPE_API_KEY SecurityScheme_Type = 2
+	SecurityScheme_TYPE_OAUTH2  SecurityScheme_Type = 3
+)
+
+// Enum value maps for SecurityScheme_Type.
+var (
+	SecurityScheme_Type_name = map[int32]string{
+		0: "TYPE_INVALID",
+		1: "TYPE_BASIC",
+		2: "TYPE_API_KEY",
+		3: "TYPE_OAUTH2",
+	}
+	SecurityScheme_Type_value = map[string]int32{
+		"TYPE_INVALID": 0,
+		"TYPE_BASIC":   1,
+		"TYPE_API_KEY": 2,
+		"TYPE_OAUTH2":  3,
+	}
+)
+
+func (x SecurityScheme_Type) Enum() *SecurityScheme_Type {
+	p := new(SecurityScheme_Type)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[3].Descriptor()
+}
+
+func (SecurityScheme_Type) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[3]
+}
+
+func (x SecurityScheme_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The location of the API key. Valid values are "query" or "header".
+type SecurityScheme_In int32
+
+const (
+	SecurityScheme_IN_INVALID SecurityScheme_In = 0
+	SecurityScheme_IN_QUERY   SecurityScheme_In = 1
+	SecurityScheme_IN_HEADER  SecurityScheme_In = 2
+)
+
+// Enum value maps for SecurityScheme_In.
+var (
+	SecurityScheme_In_name = map[int32]string{
+		0: "IN_INVALID",
+		1: "IN_QUERY",
+		2: "IN_HEADER",
+	}
+	SecurityScheme_In_value = map[string]int32{
+		"IN_INVALID": 0,
+		"IN_QUERY":   1,
+		"IN_HEADER":  2,
+	}
+)
+
+func (x SecurityScheme_In) Enum() *SecurityScheme_In {
+	p := new(SecurityScheme_In)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_In) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_In) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[4].Descriptor()
+}
+
+func (SecurityScheme_In) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[4]
+}
+
+func (x SecurityScheme_In) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// The flow used by the OAuth2 security scheme. Valid values are
+// "implicit", "password", "application" or "accessCode".
+type SecurityScheme_Flow int32
+
+const (
+	SecurityScheme_FLOW_INVALID     SecurityScheme_Flow = 0
+	SecurityScheme_FLOW_IMPLICIT    SecurityScheme_Flow = 1
+	SecurityScheme_FLOW_PASSWORD    SecurityScheme_Flow = 2
+	SecurityScheme_FLOW_APPLICATION SecurityScheme_Flow = 3
+	SecurityScheme_FLOW_ACCESS_CODE SecurityScheme_Flow = 4
+)
+
+// Enum value maps for SecurityScheme_Flow.
+var (
+	SecurityScheme_Flow_name = map[int32]string{
+		0: "FLOW_INVALID",
+		1: "FLOW_IMPLICIT",
+		2: "FLOW_PASSWORD",
+		3: "FLOW_APPLICATION",
+		4: "FLOW_ACCESS_CODE",
+	}
+	SecurityScheme_Flow_value = map[string]int32{
+		"FLOW_INVALID":     0,
+		"FLOW_IMPLICIT":    1,
+		"FLOW_PASSWORD":    2,
+		"FLOW_APPLICATION": 3,
+		"FLOW_ACCESS_CODE": 4,
+	}
+)
+
+func (x SecurityScheme_Flow) Enum() *SecurityScheme_Flow {
+	p := new(SecurityScheme_Flow)
+	*p = x
+	return p
+}
+
+func (x SecurityScheme_Flow) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SecurityScheme_Flow) Descriptor() protoreflect.EnumDescriptor {
+	return file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[5].Descriptor()
+}
+
+func (SecurityScheme_Flow) Type() protoreflect.EnumType {
+	return &file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes[5]
+}
+
+func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    title: "Echo API";
+//	    version: "1.0";
+//	    description: "";
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	  };
+//	  schemes: HTTPS;
+//	  consumes: "application/json";
+//	  produces: "application/json";
+//	};
+type Swagger struct {
+	state                          protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Swagger             string                     `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"`
+	xxx_hidden_Info                *Info                      `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"`
+	xxx_hidden_Host                string                     `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"`
+	xxx_hidden_BasePath            string                     `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"`
+	xxx_hidden_Schemes             []Scheme                   `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.Scheme" json:"schemes,omitempty"`
+	xxx_hidden_Consumes            []string                   `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"`
+	xxx_hidden_Produces            []string                   `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"`
+	xxx_hidden_Responses           map[string]*Response       `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	xxx_hidden_SecurityDefinitions *SecurityDefinitions       `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"`
+	xxx_hidden_Security            *[]*SecurityRequirement    `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"`
+	xxx_hidden_Tags                *[]*Tag                    `protobuf:"bytes,13,rep,name=tags,proto3" json:"tags,omitempty"`
+	xxx_hidden_ExternalDocs        *ExternalDocumentation     `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	xxx_hidden_Extensions          map[string]*structpb.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields                  protoimpl.UnknownFields
+	sizeCache                      protoimpl.SizeCache
+}
+
+func (x *Swagger) Reset() {
+	*x = Swagger{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Swagger) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Swagger) ProtoMessage() {}
+
+func (x *Swagger) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Swagger) GetSwagger() string {
+	if x != nil {
+		return x.xxx_hidden_Swagger
+	}
+	return ""
+}
+
+func (x *Swagger) GetInfo() *Info {
+	if x != nil {
+		return x.xxx_hidden_Info
+	}
+	return nil
+}
+
+func (x *Swagger) GetHost() string {
+	if x != nil {
+		return x.xxx_hidden_Host
+	}
+	return ""
+}
+
+func (x *Swagger) GetBasePath() string {
+	if x != nil {
+		return x.xxx_hidden_BasePath
+	}
+	return ""
+}
+
+func (x *Swagger) GetSchemes() []Scheme {
+	if x != nil {
+		return x.xxx_hidden_Schemes
+	}
+	return nil
+}
+
+func (x *Swagger) GetConsumes() []string {
+	if x != nil {
+		return x.xxx_hidden_Consumes
+	}
+	return nil
+}
+
+func (x *Swagger) GetProduces() []string {
+	if x != nil {
+		return x.xxx_hidden_Produces
+	}
+	return nil
+}
+
+func (x *Swagger) GetResponses() map[string]*Response {
+	if x != nil {
+		return x.xxx_hidden_Responses
+	}
+	return nil
+}
+
+func (x *Swagger) GetSecurityDefinitions() *SecurityDefinitions {
+	if x != nil {
+		return x.xxx_hidden_SecurityDefinitions
+	}
+	return nil
+}
+
+func (x *Swagger) GetSecurity() []*SecurityRequirement {
+	if x != nil {
+		if x.xxx_hidden_Security != nil {
+			return *x.xxx_hidden_Security
+		}
+	}
+	return nil
+}
+
+func (x *Swagger) GetTags() []*Tag {
+	if x != nil {
+		if x.xxx_hidden_Tags != nil {
+			return *x.xxx_hidden_Tags
+		}
+	}
+	return nil
+}
+
+func (x *Swagger) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.xxx_hidden_ExternalDocs
+	}
+	return nil
+}
+
+func (x *Swagger) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *Swagger) SetSwagger(v string) {
+	x.xxx_hidden_Swagger = v
+}
+
+func (x *Swagger) SetInfo(v *Info) {
+	x.xxx_hidden_Info = v
+}
+
+func (x *Swagger) SetHost(v string) {
+	x.xxx_hidden_Host = v
+}
+
+func (x *Swagger) SetBasePath(v string) {
+	x.xxx_hidden_BasePath = v
+}
+
+func (x *Swagger) SetSchemes(v []Scheme) {
+	x.xxx_hidden_Schemes = v
+}
+
+func (x *Swagger) SetConsumes(v []string) {
+	x.xxx_hidden_Consumes = v
+}
+
+func (x *Swagger) SetProduces(v []string) {
+	x.xxx_hidden_Produces = v
+}
+
+func (x *Swagger) SetResponses(v map[string]*Response) {
+	x.xxx_hidden_Responses = v
+}
+
+func (x *Swagger) SetSecurityDefinitions(v *SecurityDefinitions) {
+	x.xxx_hidden_SecurityDefinitions = v
+}
+
+func (x *Swagger) SetSecurity(v []*SecurityRequirement) {
+	x.xxx_hidden_Security = &v
+}
+
+func (x *Swagger) SetTags(v []*Tag) {
+	x.xxx_hidden_Tags = &v
+}
+
+func (x *Swagger) SetExternalDocs(v *ExternalDocumentation) {
+	x.xxx_hidden_ExternalDocs = v
+}
+
+func (x *Swagger) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *Swagger) HasInfo() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_Info != nil
+}
+
+func (x *Swagger) HasSecurityDefinitions() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_SecurityDefinitions != nil
+}
+
+func (x *Swagger) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_ExternalDocs != nil
+}
+
+func (x *Swagger) ClearInfo() {
+	x.xxx_hidden_Info = nil
+}
+
+func (x *Swagger) ClearSecurityDefinitions() {
+	x.xxx_hidden_SecurityDefinitions = nil
+}
+
+func (x *Swagger) ClearExternalDocs() {
+	x.xxx_hidden_ExternalDocs = nil
+}
+
+type Swagger_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Specifies the OpenAPI Specification version being used. It can be
+	// used by the OpenAPI UI and other clients to interpret the API listing. The
+	// value MUST be "2.0".
+	Swagger string
+	// Provides metadata about the API. The metadata can be used by the
+	// clients if needed.
+	Info *Info
+	// The host (name or ip) serving the API. This MUST be the host only and does
+	// not include the scheme nor sub-paths. It MAY include a port. If the host is
+	// not included, the host serving the documentation is to be used (including
+	// the port). The host does not support path templating.
+	Host string
+	// The base path on which the API is served, which is relative to the host. If
+	// it is not included, the API is served directly under the host. The value
+	// MUST start with a leading slash (/). The basePath does not support path
+	// templating.
+	// Note that using `base_path` does not change the endpoint paths that are
+	// generated in the resulting OpenAPI file. If you wish to use `base_path`
+	// with relatively generated OpenAPI paths, the `base_path` prefix must be
+	// manually removed from your `google.api.http` paths and your code changed to
+	// serve the API from the `base_path`.
+	BasePath string
+	// The transfer protocol of the API. Values MUST be from the list: "http",
+	// "https", "ws", "wss". If the schemes is not included, the default scheme to
+	// be used is the one used to access the OpenAPI definition itself.
+	Schemes []Scheme
+	// A list of MIME types the APIs can consume. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Consumes []string
+	// A list of MIME types the APIs can produce. This is global to all APIs but
+	// can be overridden on specific API calls. Value MUST be as described under
+	// Mime Types.
+	Produces []string
+	// An object to hold responses that can be used across operations. This
+	// property does not define global responses for all operations.
+	Responses map[string]*Response
+	// Security scheme definitions that can be used across the specification.
+	SecurityDefinitions *SecurityDefinitions
+	// A declaration of which security schemes are applied for the API as a whole.
+	// The list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements).
+	// Individual operations can override this definition.
+	Security []*SecurityRequirement
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []*Tag
+	// Additional external documentation.
+	ExternalDocs *ExternalDocumentation
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Swagger_builder) Build() *Swagger {
+	m0 := &Swagger{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Swagger = b.Swagger
+	x.xxx_hidden_Info = b.Info
+	x.xxx_hidden_Host = b.Host
+	x.xxx_hidden_BasePath = b.BasePath
+	x.xxx_hidden_Schemes = b.Schemes
+	x.xxx_hidden_Consumes = b.Consumes
+	x.xxx_hidden_Produces = b.Produces
+	x.xxx_hidden_Responses = b.Responses
+	x.xxx_hidden_SecurityDefinitions = b.SecurityDefinitions
+	x.xxx_hidden_Security = &b.Security
+	x.xxx_hidden_Tags = &b.Tags
+	x.xxx_hidden_ExternalDocs = b.ExternalDocs
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `Operation` is a representation of OpenAPI v2 specification's Operation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
+//
+// Example:
+//
+//	service EchoService {
+//	  rpc Echo(SimpleMessage) returns (SimpleMessage) {
+//	    option (google.api.http) = {
+//	      get: "/v1/example/echo/{id}"
+//	    };
+//
+//	    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
+//	      summary: "Get a message.";
+//	      operation_id: "getMessage";
+//	      tags: "echo";
+//	      responses: {
+//	        key: "200"
+//	          value: {
+//	          description: "OK";
+//	        }
+//	      }
+//	    };
+//	  }
+//	}
+type Operation struct {
+	state                   protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Tags         []string                   `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"`
+	xxx_hidden_Summary      string                     `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"`
+	xxx_hidden_Description  string                     `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_ExternalDocs *ExternalDocumentation     `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	xxx_hidden_OperationId  string                     `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"`
+	xxx_hidden_Consumes     []string                   `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"`
+	xxx_hidden_Produces     []string                   `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"`
+	xxx_hidden_Responses    map[string]*Response       `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	xxx_hidden_Schemes      []Scheme                   `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.Scheme" json:"schemes,omitempty"`
+	xxx_hidden_Deprecated   bool                       `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"`
+	xxx_hidden_Security     *[]*SecurityRequirement    `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"`
+	xxx_hidden_Extensions   map[string]*structpb.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	xxx_hidden_Parameters   *Parameters                `protobuf:"bytes,14,opt,name=parameters,proto3" json:"parameters,omitempty"`
+	unknownFields           protoimpl.UnknownFields
+	sizeCache               protoimpl.SizeCache
+}
+
+func (x *Operation) Reset() {
+	*x = Operation{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Operation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Operation) ProtoMessage() {}
+
+func (x *Operation) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Operation) GetTags() []string {
+	if x != nil {
+		return x.xxx_hidden_Tags
+	}
+	return nil
+}
+
+func (x *Operation) GetSummary() string {
+	if x != nil {
+		return x.xxx_hidden_Summary
+	}
+	return ""
+}
+
+func (x *Operation) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *Operation) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.xxx_hidden_ExternalDocs
+	}
+	return nil
+}
+
+func (x *Operation) GetOperationId() string {
+	if x != nil {
+		return x.xxx_hidden_OperationId
+	}
+	return ""
+}
+
+func (x *Operation) GetConsumes() []string {
+	if x != nil {
+		return x.xxx_hidden_Consumes
+	}
+	return nil
+}
+
+func (x *Operation) GetProduces() []string {
+	if x != nil {
+		return x.xxx_hidden_Produces
+	}
+	return nil
+}
+
+func (x *Operation) GetResponses() map[string]*Response {
+	if x != nil {
+		return x.xxx_hidden_Responses
+	}
+	return nil
+}
+
+func (x *Operation) GetSchemes() []Scheme {
+	if x != nil {
+		return x.xxx_hidden_Schemes
+	}
+	return nil
+}
+
+func (x *Operation) GetDeprecated() bool {
+	if x != nil {
+		return x.xxx_hidden_Deprecated
+	}
+	return false
+}
+
+func (x *Operation) GetSecurity() []*SecurityRequirement {
+	if x != nil {
+		if x.xxx_hidden_Security != nil {
+			return *x.xxx_hidden_Security
+		}
+	}
+	return nil
+}
+
+func (x *Operation) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *Operation) GetParameters() *Parameters {
+	if x != nil {
+		return x.xxx_hidden_Parameters
+	}
+	return nil
+}
+
+func (x *Operation) SetTags(v []string) {
+	x.xxx_hidden_Tags = v
+}
+
+func (x *Operation) SetSummary(v string) {
+	x.xxx_hidden_Summary = v
+}
+
+func (x *Operation) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *Operation) SetExternalDocs(v *ExternalDocumentation) {
+	x.xxx_hidden_ExternalDocs = v
+}
+
+func (x *Operation) SetOperationId(v string) {
+	x.xxx_hidden_OperationId = v
+}
+
+func (x *Operation) SetConsumes(v []string) {
+	x.xxx_hidden_Consumes = v
+}
+
+func (x *Operation) SetProduces(v []string) {
+	x.xxx_hidden_Produces = v
+}
+
+func (x *Operation) SetResponses(v map[string]*Response) {
+	x.xxx_hidden_Responses = v
+}
+
+func (x *Operation) SetSchemes(v []Scheme) {
+	x.xxx_hidden_Schemes = v
+}
+
+func (x *Operation) SetDeprecated(v bool) {
+	x.xxx_hidden_Deprecated = v
+}
+
+func (x *Operation) SetSecurity(v []*SecurityRequirement) {
+	x.xxx_hidden_Security = &v
+}
+
+func (x *Operation) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *Operation) SetParameters(v *Parameters) {
+	x.xxx_hidden_Parameters = v
+}
+
+func (x *Operation) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_ExternalDocs != nil
+}
+
+func (x *Operation) HasParameters() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_Parameters != nil
+}
+
+func (x *Operation) ClearExternalDocs() {
+	x.xxx_hidden_ExternalDocs = nil
+}
+
+func (x *Operation) ClearParameters() {
+	x.xxx_hidden_Parameters = nil
+}
+
+type Operation_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A list of tags for API documentation control. Tags can be used for logical
+	// grouping of operations by resources or any other qualifier.
+	Tags []string
+	// A short summary of what the operation does. For maximum readability in the
+	// swagger-ui, this field SHOULD be less than 120 characters.
+	Summary string
+	// A verbose explanation of the operation behavior. GFM syntax can be used for
+	// rich text representation.
+	Description string
+	// Additional external documentation for this operation.
+	ExternalDocs *ExternalDocumentation
+	// Unique string used to identify the operation. The id MUST be unique among
+	// all operations described in the API. Tools and libraries MAY use the
+	// operationId to uniquely identify an operation, therefore, it is recommended
+	// to follow common programming naming conventions.
+	OperationId string
+	// A list of MIME types the operation can consume. This overrides the consumes
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Consumes []string
+	// A list of MIME types the operation can produce. This overrides the produces
+	// definition at the OpenAPI Object. An empty value MAY be used to clear the
+	// global definition. Value MUST be as described under Mime Types.
+	Produces []string
+	// The list of possible responses as they are returned from executing this
+	// operation.
+	Responses map[string]*Response
+	// The transfer protocol for the operation. Values MUST be from the list:
+	// "http", "https", "ws", "wss". The value overrides the OpenAPI Object
+	// schemes definition.
+	Schemes []Scheme
+	// Declares this operation to be deprecated. Usage of the declared operation
+	// should be refrained. Default value is false.
+	Deprecated bool
+	// A declaration of which security schemes are applied for this operation. The
+	// list of values describes alternative security schemes that can be used
+	// (that is, there is a logical OR between the security requirements). This
+	// definition overrides any declared top-level security. To remove a top-level
+	// security declaration, an empty array can be used.
+	Security []*SecurityRequirement
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+	// Custom parameters such as HTTP request headers.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/
+	// and https://swagger.io/specification/v2/#parameter-object.
+	Parameters *Parameters
+}
+
+func (b0 Operation_builder) Build() *Operation {
+	m0 := &Operation{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Tags = b.Tags
+	x.xxx_hidden_Summary = b.Summary
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_ExternalDocs = b.ExternalDocs
+	x.xxx_hidden_OperationId = b.OperationId
+	x.xxx_hidden_Consumes = b.Consumes
+	x.xxx_hidden_Produces = b.Produces
+	x.xxx_hidden_Responses = b.Responses
+	x.xxx_hidden_Schemes = b.Schemes
+	x.xxx_hidden_Deprecated = b.Deprecated
+	x.xxx_hidden_Security = &b.Security
+	x.xxx_hidden_Extensions = b.Extensions
+	x.xxx_hidden_Parameters = b.Parameters
+	return m0
+}
+
+// `Parameters` is a representation of OpenAPI v2 specification's parameters object.
+// Note: This technically breaks compatibility with the OpenAPI 2 definition structure as we only
+// allow header parameters to be set here since we do not want users specifying custom non-header
+// parameters beyond those inferred from the Protobuf schema.
+// See: https://swagger.io/specification/v2/#parameter-object
+type Parameters struct {
+	state              protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Headers *[]*HeaderParameter    `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *Parameters) Reset() {
+	*x = Parameters{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Parameters) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Parameters) ProtoMessage() {}
+
+func (x *Parameters) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Parameters) GetHeaders() []*HeaderParameter {
+	if x != nil {
+		if x.xxx_hidden_Headers != nil {
+			return *x.xxx_hidden_Headers
+		}
+	}
+	return nil
+}
+
+func (x *Parameters) SetHeaders(v []*HeaderParameter) {
+	x.xxx_hidden_Headers = &v
+}
+
+type Parameters_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Headers` is one or more HTTP header parameter.
+	// See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
+	Headers []*HeaderParameter
+}
+
+func (b0 Parameters_builder) Build() *Parameters {
+	m0 := &Parameters{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Headers = &b.Headers
+	return m0
+}
+
+// `HeaderParameter` a HTTP header parameter.
+// See: https://swagger.io/specification/v2/#parameter-object
+type HeaderParameter struct {
+	state                  protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Name        string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	xxx_hidden_Description string                 `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Type        HeaderParameter_Type   `protobuf:"varint,3,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter_Type" json:"type,omitempty"`
+	xxx_hidden_Format      string                 `protobuf:"bytes,4,opt,name=format,proto3" json:"format,omitempty"`
+	xxx_hidden_Required    bool                   `protobuf:"varint,5,opt,name=required,proto3" json:"required,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *HeaderParameter) Reset() {
+	*x = HeaderParameter{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *HeaderParameter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HeaderParameter) ProtoMessage() {}
+
+func (x *HeaderParameter) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *HeaderParameter) GetName() string {
+	if x != nil {
+		return x.xxx_hidden_Name
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetType() HeaderParameter_Type {
+	if x != nil {
+		return x.xxx_hidden_Type
+	}
+	return HeaderParameter_UNKNOWN
+}
+
+func (x *HeaderParameter) GetFormat() string {
+	if x != nil {
+		return x.xxx_hidden_Format
+	}
+	return ""
+}
+
+func (x *HeaderParameter) GetRequired() bool {
+	if x != nil {
+		return x.xxx_hidden_Required
+	}
+	return false
+}
+
+func (x *HeaderParameter) SetName(v string) {
+	x.xxx_hidden_Name = v
+}
+
+func (x *HeaderParameter) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *HeaderParameter) SetType(v HeaderParameter_Type) {
+	x.xxx_hidden_Type = v
+}
+
+func (x *HeaderParameter) SetFormat(v string) {
+	x.xxx_hidden_Format = v
+}
+
+func (x *HeaderParameter) SetRequired(v bool) {
+	x.xxx_hidden_Required = v
+}
+
+type HeaderParameter_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Name` is the header name.
+	Name string
+	// `Description` is a short description of the header.
+	Description string
+	// `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	// See: https://swagger.io/specification/v2/#parameterType.
+	Type HeaderParameter_Type
+	// `Format` The extending format for the previously mentioned type.
+	Format string
+	// `Required` indicates if the header is optional
+	Required bool
+}
+
+func (b0 HeaderParameter_builder) Build() *HeaderParameter {
+	m0 := &HeaderParameter{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Name = b.Name
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Type = b.Type
+	x.xxx_hidden_Format = b.Format
+	x.xxx_hidden_Required = b.Required
+	return m0
+}
+
+// `Header` is a representation of OpenAPI v2 specification's Header object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+type Header struct {
+	state                  protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Description string                 `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Type        string                 `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	xxx_hidden_Format      string                 `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"`
+	xxx_hidden_Default     string                 `protobuf:"bytes,6,opt,name=default,proto3" json:"default,omitempty"`
+	xxx_hidden_Pattern     string                 `protobuf:"bytes,13,opt,name=pattern,proto3" json:"pattern,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *Header) Reset() {
+	*x = Header{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Header) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Header) ProtoMessage() {}
+
+func (x *Header) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Header) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *Header) GetType() string {
+	if x != nil {
+		return x.xxx_hidden_Type
+	}
+	return ""
+}
+
+func (x *Header) GetFormat() string {
+	if x != nil {
+		return x.xxx_hidden_Format
+	}
+	return ""
+}
+
+func (x *Header) GetDefault() string {
+	if x != nil {
+		return x.xxx_hidden_Default
+	}
+	return ""
+}
+
+func (x *Header) GetPattern() string {
+	if x != nil {
+		return x.xxx_hidden_Pattern
+	}
+	return ""
+}
+
+func (x *Header) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *Header) SetType(v string) {
+	x.xxx_hidden_Type = v
+}
+
+func (x *Header) SetFormat(v string) {
+	x.xxx_hidden_Format = v
+}
+
+func (x *Header) SetDefault(v string) {
+	x.xxx_hidden_Default = v
+}
+
+func (x *Header) SetPattern(v string) {
+	x.xxx_hidden_Pattern = v
+}
+
+type Header_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Description` is a short description of the header.
+	Description string
+	// The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+	Type string
+	// `Format` The extending format for the previously mentioned type.
+	Format string
+	// `Default` Declares the value of the header that the server will use if none is provided.
+	// See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+	// Unlike JSON Schema this value MUST conform to the defined type for the header.
+	Default string
+	// 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+	Pattern string
+}
+
+func (b0 Header_builder) Build() *Header {
+	m0 := &Header{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Type = b.Type
+	x.xxx_hidden_Format = b.Format
+	x.xxx_hidden_Default = b.Default
+	x.xxx_hidden_Pattern = b.Pattern
+	return m0
+}
+
+// `Response` is a representation of OpenAPI v2 specification's Response object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
+type Response struct {
+	state                  protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Description string                     `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Schema      *Schema                    `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"`
+	xxx_hidden_Headers     map[string]*Header         `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	xxx_hidden_Examples    map[string]string          `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	xxx_hidden_Extensions  map[string]*structpb.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *Response) Reset() {
+	*x = Response{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Response) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Response) ProtoMessage() {}
+
+func (x *Response) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Response) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *Response) GetSchema() *Schema {
+	if x != nil {
+		return x.xxx_hidden_Schema
+	}
+	return nil
+}
+
+func (x *Response) GetHeaders() map[string]*Header {
+	if x != nil {
+		return x.xxx_hidden_Headers
+	}
+	return nil
+}
+
+func (x *Response) GetExamples() map[string]string {
+	if x != nil {
+		return x.xxx_hidden_Examples
+	}
+	return nil
+}
+
+func (x *Response) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *Response) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *Response) SetSchema(v *Schema) {
+	x.xxx_hidden_Schema = v
+}
+
+func (x *Response) SetHeaders(v map[string]*Header) {
+	x.xxx_hidden_Headers = v
+}
+
+func (x *Response) SetExamples(v map[string]string) {
+	x.xxx_hidden_Examples = v
+}
+
+func (x *Response) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *Response) HasSchema() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_Schema != nil
+}
+
+func (x *Response) ClearSchema() {
+	x.xxx_hidden_Schema = nil
+}
+
+type Response_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// `Description` is a short description of the response.
+	// GFM syntax can be used for rich text representation.
+	Description string
+	// `Schema` optionally defines the structure of the response.
+	// If `Schema` is not provided, it means there is no content to the response.
+	Schema *Schema
+	// `Headers` A list of headers that are sent with the response.
+	// `Header` name is expected to be a string in the canonical format of the MIME header key
+	// See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+	Headers map[string]*Header
+	// `Examples` gives per-mimetype response examples.
+	// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+	Examples map[string]string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Response_builder) Build() *Response {
+	m0 := &Response{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Schema = b.Schema
+	x.xxx_hidden_Headers = b.Headers
+	x.xxx_hidden_Examples = b.Examples
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `Info` is a representation of OpenAPI v2 specification's Info object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    title: "Echo API";
+//	    version: "1.0";
+//	    description: "";
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	  };
+//	  ...
+//	};
+type Info struct {
+	state                     protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Title          string                     `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+	xxx_hidden_Description    string                     `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_TermsOfService string                     `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"`
+	xxx_hidden_Contact        *Contact                   `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"`
+	xxx_hidden_License        *License                   `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"`
+	xxx_hidden_Version        string                     `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"`
+	xxx_hidden_Extensions     map[string]*structpb.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields             protoimpl.UnknownFields
+	sizeCache                 protoimpl.SizeCache
+}
+
+func (x *Info) Reset() {
+	*x = Info{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Info) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Info) ProtoMessage() {}
+
+func (x *Info) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Info) GetTitle() string {
+	if x != nil {
+		return x.xxx_hidden_Title
+	}
+	return ""
+}
+
+func (x *Info) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *Info) GetTermsOfService() string {
+	if x != nil {
+		return x.xxx_hidden_TermsOfService
+	}
+	return ""
+}
+
+func (x *Info) GetContact() *Contact {
+	if x != nil {
+		return x.xxx_hidden_Contact
+	}
+	return nil
+}
+
+func (x *Info) GetLicense() *License {
+	if x != nil {
+		return x.xxx_hidden_License
+	}
+	return nil
+}
+
+func (x *Info) GetVersion() string {
+	if x != nil {
+		return x.xxx_hidden_Version
+	}
+	return ""
+}
+
+func (x *Info) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *Info) SetTitle(v string) {
+	x.xxx_hidden_Title = v
+}
+
+func (x *Info) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *Info) SetTermsOfService(v string) {
+	x.xxx_hidden_TermsOfService = v
+}
+
+func (x *Info) SetContact(v *Contact) {
+	x.xxx_hidden_Contact = v
+}
+
+func (x *Info) SetLicense(v *License) {
+	x.xxx_hidden_License = v
+}
+
+func (x *Info) SetVersion(v string) {
+	x.xxx_hidden_Version = v
+}
+
+func (x *Info) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *Info) HasContact() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_Contact != nil
+}
+
+func (x *Info) HasLicense() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_License != nil
+}
+
+func (x *Info) ClearContact() {
+	x.xxx_hidden_Contact = nil
+}
+
+func (x *Info) ClearLicense() {
+	x.xxx_hidden_License = nil
+}
+
+type Info_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The title of the application.
+	Title string
+	// A short description of the application. GFM syntax can be used for rich
+	// text representation.
+	Description string
+	// The Terms of Service for the API.
+	TermsOfService string
+	// The contact information for the exposed API.
+	Contact *Contact
+	// The license information for the exposed API.
+	License *License
+	// Provides the version of the application API (not to be confused
+	// with the specification version).
+	Version string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Info_builder) Build() *Info {
+	m0 := &Info{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Title = b.Title
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_TermsOfService = b.TermsOfService
+	x.xxx_hidden_Contact = b.Contact
+	x.xxx_hidden_License = b.License
+	x.xxx_hidden_Version = b.Version
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `Contact` is a representation of OpenAPI v2 specification's Contact object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    ...
+//	    contact: {
+//	      name: "gRPC-Gateway project";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	      email: "none@example.com";
+//	    };
+//	    ...
+//	  };
+//	  ...
+//	};
+type Contact struct {
+	state            protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Name  string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	xxx_hidden_Url   string                 `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	xxx_hidden_Email string                 `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Contact) Reset() {
+	*x = Contact{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Contact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Contact) ProtoMessage() {}
+
+func (x *Contact) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Contact) GetName() string {
+	if x != nil {
+		return x.xxx_hidden_Name
+	}
+	return ""
+}
+
+func (x *Contact) GetUrl() string {
+	if x != nil {
+		return x.xxx_hidden_Url
+	}
+	return ""
+}
+
+func (x *Contact) GetEmail() string {
+	if x != nil {
+		return x.xxx_hidden_Email
+	}
+	return ""
+}
+
+func (x *Contact) SetName(v string) {
+	x.xxx_hidden_Name = v
+}
+
+func (x *Contact) SetUrl(v string) {
+	x.xxx_hidden_Url = v
+}
+
+func (x *Contact) SetEmail(v string) {
+	x.xxx_hidden_Email = v
+}
+
+type Contact_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The identifying name of the contact person/organization.
+	Name string
+	// The URL pointing to the contact information. MUST be in the format of a
+	// URL.
+	Url string
+	// The email address of the contact person/organization. MUST be in the format
+	// of an email address.
+	Email string
+}
+
+func (b0 Contact_builder) Build() *Contact {
+	m0 := &Contact{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Name = b.Name
+	x.xxx_hidden_Url = b.Url
+	x.xxx_hidden_Email = b.Email
+	return m0
+}
+
+// `License` is a representation of OpenAPI v2 specification's License object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  info: {
+//	    ...
+//	    license: {
+//	      name: "BSD 3-Clause License";
+//	      url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
+//	    };
+//	    ...
+//	  };
+//	  ...
+//	};
+type License struct {
+	state           protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Name string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	xxx_hidden_Url  string                 `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *License) Reset() {
+	*x = License{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *License) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*License) ProtoMessage() {}
+
+func (x *License) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *License) GetName() string {
+	if x != nil {
+		return x.xxx_hidden_Name
+	}
+	return ""
+}
+
+func (x *License) GetUrl() string {
+	if x != nil {
+		return x.xxx_hidden_Url
+	}
+	return ""
+}
+
+func (x *License) SetName(v string) {
+	x.xxx_hidden_Name = v
+}
+
+func (x *License) SetUrl(v string) {
+	x.xxx_hidden_Url = v
+}
+
+type License_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The license name used for the API.
+	Name string
+	// A URL to the license used for the API. MUST be in the format of a URL.
+	Url string
+}
+
+func (b0 License_builder) Build() *License {
+	m0 := &License{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Name = b.Name
+	x.xxx_hidden_Url = b.Url
+	return m0
+}
+
+// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
+// ExternalDocumentation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//	  ...
+//	  external_docs: {
+//	    description: "More about gRPC-Gateway";
+//	    url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//	  }
+//	  ...
+//	};
+type ExternalDocumentation struct {
+	state                  protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Description string                 `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Url         string                 `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *ExternalDocumentation) Reset() {
+	*x = ExternalDocumentation{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ExternalDocumentation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExternalDocumentation) ProtoMessage() {}
+
+func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *ExternalDocumentation) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *ExternalDocumentation) GetUrl() string {
+	if x != nil {
+		return x.xxx_hidden_Url
+	}
+	return ""
+}
+
+func (x *ExternalDocumentation) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *ExternalDocumentation) SetUrl(v string) {
+	x.xxx_hidden_Url = v
+}
+
+type ExternalDocumentation_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A short description of the target documentation. GFM syntax can be used for
+	// rich text representation.
+	Description string
+	// The URL for the target documentation. Value MUST be in the format
+	// of a URL.
+	Url string
+}
+
+func (b0 ExternalDocumentation_builder) Build() *ExternalDocumentation {
+	m0 := &ExternalDocumentation{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Url = b.Url
+	return m0
+}
+
+// `Schema` is a representation of OpenAPI v2 specification's Schema object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+type Schema struct {
+	state                    protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_JsonSchema    *JSONSchema            `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"`
+	xxx_hidden_Discriminator string                 `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"`
+	xxx_hidden_ReadOnly      bool                   `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	xxx_hidden_ExternalDocs  *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	xxx_hidden_Example       string                 `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *Schema) Reset() {
+	*x = Schema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Schema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Schema) ProtoMessage() {}
+
+func (x *Schema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Schema) GetJsonSchema() *JSONSchema {
+	if x != nil {
+		return x.xxx_hidden_JsonSchema
+	}
+	return nil
+}
+
+func (x *Schema) GetDiscriminator() string {
+	if x != nil {
+		return x.xxx_hidden_Discriminator
+	}
+	return ""
+}
+
+func (x *Schema) GetReadOnly() bool {
+	if x != nil {
+		return x.xxx_hidden_ReadOnly
+	}
+	return false
+}
+
+func (x *Schema) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.xxx_hidden_ExternalDocs
+	}
+	return nil
+}
+
+func (x *Schema) GetExample() string {
+	if x != nil {
+		return x.xxx_hidden_Example
+	}
+	return ""
+}
+
+func (x *Schema) SetJsonSchema(v *JSONSchema) {
+	x.xxx_hidden_JsonSchema = v
+}
+
+func (x *Schema) SetDiscriminator(v string) {
+	x.xxx_hidden_Discriminator = v
+}
+
+func (x *Schema) SetReadOnly(v bool) {
+	x.xxx_hidden_ReadOnly = v
+}
+
+func (x *Schema) SetExternalDocs(v *ExternalDocumentation) {
+	x.xxx_hidden_ExternalDocs = v
+}
+
+func (x *Schema) SetExample(v string) {
+	x.xxx_hidden_Example = v
+}
+
+func (x *Schema) HasJsonSchema() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_JsonSchema != nil
+}
+
+func (x *Schema) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_ExternalDocs != nil
+}
+
+func (x *Schema) ClearJsonSchema() {
+	x.xxx_hidden_JsonSchema = nil
+}
+
+func (x *Schema) ClearExternalDocs() {
+	x.xxx_hidden_ExternalDocs = nil
+}
+
+type Schema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	JsonSchema *JSONSchema
+	// Adds support for polymorphism. The discriminator is the schema property
+	// name that is used to differentiate between other schema that inherit this
+	// schema. The property name used MUST be defined at this schema and it MUST
+	// be in the required property list. When used, the value MUST be the name of
+	// this schema or any schema that inherits it.
+	Discriminator string
+	// Relevant only for Schema "properties" definitions. Declares the property as
+	// "read only". This means that it MAY be sent as part of a response but MUST
+	// NOT be sent as part of the request. Properties marked as readOnly being
+	// true SHOULD NOT be in the required list of the defined schema. Default
+	// value is false.
+	ReadOnly bool
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation
+	// A free-form property to include an example of an instance for this schema in JSON.
+	// This is copied verbatim to the output.
+	Example string
+}
+
+func (b0 Schema_builder) Build() *Schema {
+	m0 := &Schema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_JsonSchema = b.JsonSchema
+	x.xxx_hidden_Discriminator = b.Discriminator
+	x.xxx_hidden_ReadOnly = b.ReadOnly
+	x.xxx_hidden_ExternalDocs = b.ExternalDocs
+	x.xxx_hidden_Example = b.Example
+	return m0
+}
+
+// `EnumSchema` is subset of fields from the OpenAPI v2 specification's Schema object.
+// Only fields that are applicable to Enums are included
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// Example:
+//
+//	option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
+//	  ...
+//	  title: "MyEnum";
+//	  description:"This is my nice enum";
+//	  example: "ZERO";
+//	  required: true;
+//	  ...
+//	};
+type EnumSchema struct {
+	state                   protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Description  string                     `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Default      string                     `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"`
+	xxx_hidden_Title        string                     `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
+	xxx_hidden_Required     bool                       `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"`
+	xxx_hidden_ReadOnly     bool                       `protobuf:"varint,5,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	xxx_hidden_ExternalDocs *ExternalDocumentation     `protobuf:"bytes,6,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	xxx_hidden_Example      string                     `protobuf:"bytes,7,opt,name=example,proto3" json:"example,omitempty"`
+	xxx_hidden_Ref          string                     `protobuf:"bytes,8,opt,name=ref,proto3" json:"ref,omitempty"`
+	xxx_hidden_Extensions   map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields           protoimpl.UnknownFields
+	sizeCache               protoimpl.SizeCache
+}
+
+func (x *EnumSchema) Reset() {
+	*x = EnumSchema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EnumSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnumSchema) ProtoMessage() {}
+
+func (x *EnumSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *EnumSchema) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetDefault() string {
+	if x != nil {
+		return x.xxx_hidden_Default
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetTitle() string {
+	if x != nil {
+		return x.xxx_hidden_Title
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetRequired() bool {
+	if x != nil {
+		return x.xxx_hidden_Required
+	}
+	return false
+}
+
+func (x *EnumSchema) GetReadOnly() bool {
+	if x != nil {
+		return x.xxx_hidden_ReadOnly
+	}
+	return false
+}
+
+func (x *EnumSchema) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.xxx_hidden_ExternalDocs
+	}
+	return nil
+}
+
+func (x *EnumSchema) GetExample() string {
+	if x != nil {
+		return x.xxx_hidden_Example
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetRef() string {
+	if x != nil {
+		return x.xxx_hidden_Ref
+	}
+	return ""
+}
+
+func (x *EnumSchema) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *EnumSchema) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *EnumSchema) SetDefault(v string) {
+	x.xxx_hidden_Default = v
+}
+
+func (x *EnumSchema) SetTitle(v string) {
+	x.xxx_hidden_Title = v
+}
+
+func (x *EnumSchema) SetRequired(v bool) {
+	x.xxx_hidden_Required = v
+}
+
+func (x *EnumSchema) SetReadOnly(v bool) {
+	x.xxx_hidden_ReadOnly = v
+}
+
+func (x *EnumSchema) SetExternalDocs(v *ExternalDocumentation) {
+	x.xxx_hidden_ExternalDocs = v
+}
+
+func (x *EnumSchema) SetExample(v string) {
+	x.xxx_hidden_Example = v
+}
+
+func (x *EnumSchema) SetRef(v string) {
+	x.xxx_hidden_Ref = v
+}
+
+func (x *EnumSchema) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *EnumSchema) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_ExternalDocs != nil
+}
+
+func (x *EnumSchema) ClearExternalDocs() {
+	x.xxx_hidden_ExternalDocs = nil
+}
+
+type EnumSchema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A short description of the schema.
+	Description string
+	Default     string
+	// The title of the schema.
+	Title    string
+	Required bool
+	ReadOnly bool
+	// Additional external documentation for this schema.
+	ExternalDocs *ExternalDocumentation
+	Example      string
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 EnumSchema_builder) Build() *EnumSchema {
+	m0 := &EnumSchema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Default = b.Default
+	x.xxx_hidden_Title = b.Title
+	x.xxx_hidden_Required = b.Required
+	x.xxx_hidden_ReadOnly = b.ReadOnly
+	x.xxx_hidden_ExternalDocs = b.ExternalDocs
+	x.xxx_hidden_Example = b.Example
+	x.xxx_hidden_Ref = b.Ref
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `JSONSchema` represents properties from JSON Schema taken, and as used, in
+// the OpenAPI v2 spec.
+//
+// This includes changes made by OpenAPI v2.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
+// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
+//
+// Example:
+//
+//	message SimpleMessage {
+//	  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
+//	    json_schema: {
+//	      title: "SimpleMessage"
+//	      description: "A simple message."
+//	      required: ["id"]
+//	    }
+//	  };
+//
+//	  // Id represents the message identifier.
+//	  string id = 1; [
+//	      (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+//	        description: "The unique identifier of the simple message."
+//	      }];
+//	}
+type JSONSchema struct {
+	state                         protoimpl.MessageState             `protogen:"opaque.v1"`
+	xxx_hidden_Ref                string                             `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"`
+	xxx_hidden_Title              string                             `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"`
+	xxx_hidden_Description        string                             `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Default            string                             `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"`
+	xxx_hidden_ReadOnly           bool                               `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
+	xxx_hidden_Example            string                             `protobuf:"bytes,9,opt,name=example,proto3" json:"example,omitempty"`
+	xxx_hidden_MultipleOf         float64                            `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"`
+	xxx_hidden_Maximum            float64                            `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"`
+	xxx_hidden_ExclusiveMaximum   bool                               `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"`
+	xxx_hidden_Minimum            float64                            `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"`
+	xxx_hidden_ExclusiveMinimum   bool                               `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"`
+	xxx_hidden_MaxLength          uint64                             `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"`
+	xxx_hidden_MinLength          uint64                             `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"`
+	xxx_hidden_Pattern            string                             `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"`
+	xxx_hidden_MaxItems           uint64                             `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"`
+	xxx_hidden_MinItems           uint64                             `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"`
+	xxx_hidden_UniqueItems        bool                               `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"`
+	xxx_hidden_MaxProperties      uint64                             `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"`
+	xxx_hidden_MinProperties      uint64                             `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"`
+	xxx_hidden_Required           []string                           `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"`
+	xxx_hidden_Array              []string                           `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"`
+	xxx_hidden_Type               []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"`
+	xxx_hidden_Format             string                             `protobuf:"bytes,36,opt,name=format,proto3" json:"format,omitempty"`
+	xxx_hidden_Enum               []string                           `protobuf:"bytes,46,rep,name=enum,proto3" json:"enum,omitempty"`
+	xxx_hidden_FieldConfiguration *JSONSchema_FieldConfiguration     `protobuf:"bytes,1001,opt,name=field_configuration,json=fieldConfiguration,proto3" json:"field_configuration,omitempty"`
+	xxx_hidden_Extensions         map[string]*structpb.Value         `protobuf:"bytes,48,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields                 protoimpl.UnknownFields
+	sizeCache                     protoimpl.SizeCache
+}
+
+func (x *JSONSchema) Reset() {
+	*x = JSONSchema{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *JSONSchema) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JSONSchema) ProtoMessage() {}
+
+func (x *JSONSchema) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *JSONSchema) GetRef() string {
+	if x != nil {
+		return x.xxx_hidden_Ref
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetTitle() string {
+	if x != nil {
+		return x.xxx_hidden_Title
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetDefault() string {
+	if x != nil {
+		return x.xxx_hidden_Default
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetReadOnly() bool {
+	if x != nil {
+		return x.xxx_hidden_ReadOnly
+	}
+	return false
+}
+
+func (x *JSONSchema) GetExample() string {
+	if x != nil {
+		return x.xxx_hidden_Example
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetMultipleOf() float64 {
+	if x != nil {
+		return x.xxx_hidden_MultipleOf
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMaximum() float64 {
+	if x != nil {
+		return x.xxx_hidden_Maximum
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetExclusiveMaximum() bool {
+	if x != nil {
+		return x.xxx_hidden_ExclusiveMaximum
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMinimum() float64 {
+	if x != nil {
+		return x.xxx_hidden_Minimum
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetExclusiveMinimum() bool {
+	if x != nil {
+		return x.xxx_hidden_ExclusiveMinimum
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMaxLength() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MaxLength
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinLength() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MinLength
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetPattern() string {
+	if x != nil {
+		return x.xxx_hidden_Pattern
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetMaxItems() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MaxItems
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinItems() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MinItems
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetUniqueItems() bool {
+	if x != nil {
+		return x.xxx_hidden_UniqueItems
+	}
+	return false
+}
+
+func (x *JSONSchema) GetMaxProperties() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MaxProperties
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetMinProperties() uint64 {
+	if x != nil {
+		return x.xxx_hidden_MinProperties
+	}
+	return 0
+}
+
+func (x *JSONSchema) GetRequired() []string {
+	if x != nil {
+		return x.xxx_hidden_Required
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetArray() []string {
+	if x != nil {
+		return x.xxx_hidden_Array
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes {
+	if x != nil {
+		return x.xxx_hidden_Type
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetFormat() string {
+	if x != nil {
+		return x.xxx_hidden_Format
+	}
+	return ""
+}
+
+func (x *JSONSchema) GetEnum() []string {
+	if x != nil {
+		return x.xxx_hidden_Enum
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetFieldConfiguration() *JSONSchema_FieldConfiguration {
+	if x != nil {
+		return x.xxx_hidden_FieldConfiguration
+	}
+	return nil
+}
+
+func (x *JSONSchema) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *JSONSchema) SetRef(v string) {
+	x.xxx_hidden_Ref = v
+}
+
+func (x *JSONSchema) SetTitle(v string) {
+	x.xxx_hidden_Title = v
+}
+
+func (x *JSONSchema) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *JSONSchema) SetDefault(v string) {
+	x.xxx_hidden_Default = v
+}
+
+func (x *JSONSchema) SetReadOnly(v bool) {
+	x.xxx_hidden_ReadOnly = v
+}
+
+func (x *JSONSchema) SetExample(v string) {
+	x.xxx_hidden_Example = v
+}
+
+func (x *JSONSchema) SetMultipleOf(v float64) {
+	x.xxx_hidden_MultipleOf = v
+}
+
+func (x *JSONSchema) SetMaximum(v float64) {
+	x.xxx_hidden_Maximum = v
+}
+
+func (x *JSONSchema) SetExclusiveMaximum(v bool) {
+	x.xxx_hidden_ExclusiveMaximum = v
+}
+
+func (x *JSONSchema) SetMinimum(v float64) {
+	x.xxx_hidden_Minimum = v
+}
+
+func (x *JSONSchema) SetExclusiveMinimum(v bool) {
+	x.xxx_hidden_ExclusiveMinimum = v
+}
+
+func (x *JSONSchema) SetMaxLength(v uint64) {
+	x.xxx_hidden_MaxLength = v
+}
+
+func (x *JSONSchema) SetMinLength(v uint64) {
+	x.xxx_hidden_MinLength = v
+}
+
+func (x *JSONSchema) SetPattern(v string) {
+	x.xxx_hidden_Pattern = v
+}
+
+func (x *JSONSchema) SetMaxItems(v uint64) {
+	x.xxx_hidden_MaxItems = v
+}
+
+func (x *JSONSchema) SetMinItems(v uint64) {
+	x.xxx_hidden_MinItems = v
+}
+
+func (x *JSONSchema) SetUniqueItems(v bool) {
+	x.xxx_hidden_UniqueItems = v
+}
+
+func (x *JSONSchema) SetMaxProperties(v uint64) {
+	x.xxx_hidden_MaxProperties = v
+}
+
+func (x *JSONSchema) SetMinProperties(v uint64) {
+	x.xxx_hidden_MinProperties = v
+}
+
+func (x *JSONSchema) SetRequired(v []string) {
+	x.xxx_hidden_Required = v
+}
+
+func (x *JSONSchema) SetArray(v []string) {
+	x.xxx_hidden_Array = v
+}
+
+func (x *JSONSchema) SetType(v []JSONSchema_JSONSchemaSimpleTypes) {
+	x.xxx_hidden_Type = v
+}
+
+func (x *JSONSchema) SetFormat(v string) {
+	x.xxx_hidden_Format = v
+}
+
+func (x *JSONSchema) SetEnum(v []string) {
+	x.xxx_hidden_Enum = v
+}
+
+func (x *JSONSchema) SetFieldConfiguration(v *JSONSchema_FieldConfiguration) {
+	x.xxx_hidden_FieldConfiguration = v
+}
+
+func (x *JSONSchema) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *JSONSchema) HasFieldConfiguration() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_FieldConfiguration != nil
+}
+
+func (x *JSONSchema) ClearFieldConfiguration() {
+	x.xxx_hidden_FieldConfiguration = nil
+}
+
+type JSONSchema_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Ref is used to define an external reference to include in the message.
+	// This could be a fully qualified proto message reference, and that type must
+	// be imported into the protofile. If no message is identified, the Ref will
+	// be used verbatim in the output.
+	// For example:
+	//
+	//	`ref: ".google.protobuf.Timestamp"`.
+	Ref string
+	// The title of the schema.
+	Title string
+	// A short description of the schema.
+	Description string
+	Default     string
+	ReadOnly    bool
+	// A free-form property to include a JSON example of this field. This is copied
+	// verbatim to the output swagger.json. Quotes must be escaped.
+	// This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+	Example    string
+	MultipleOf float64
+	// Maximum represents an inclusive upper limit for a numeric instance. The
+	// value of MUST be a number,
+	Maximum          float64
+	ExclusiveMaximum bool
+	// minimum represents an inclusive lower limit for a numeric instance. The
+	// value of MUST be a number,
+	Minimum          float64
+	ExclusiveMinimum bool
+	MaxLength        uint64
+	MinLength        uint64
+	Pattern          string
+	MaxItems         uint64
+	MinItems         uint64
+	UniqueItems      bool
+	MaxProperties    uint64
+	MinProperties    uint64
+	Required         []string
+	// Items in 'array' must be unique.
+	Array []string
+	Type  []JSONSchema_JSONSchemaSimpleTypes
+	// `Format`
+	Format string
+	// Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+	Enum []string
+	// Additional field level properties used when generating the OpenAPI v2 file.
+	FieldConfiguration *JSONSchema_FieldConfiguration
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 JSONSchema_builder) Build() *JSONSchema {
+	m0 := &JSONSchema{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Ref = b.Ref
+	x.xxx_hidden_Title = b.Title
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Default = b.Default
+	x.xxx_hidden_ReadOnly = b.ReadOnly
+	x.xxx_hidden_Example = b.Example
+	x.xxx_hidden_MultipleOf = b.MultipleOf
+	x.xxx_hidden_Maximum = b.Maximum
+	x.xxx_hidden_ExclusiveMaximum = b.ExclusiveMaximum
+	x.xxx_hidden_Minimum = b.Minimum
+	x.xxx_hidden_ExclusiveMinimum = b.ExclusiveMinimum
+	x.xxx_hidden_MaxLength = b.MaxLength
+	x.xxx_hidden_MinLength = b.MinLength
+	x.xxx_hidden_Pattern = b.Pattern
+	x.xxx_hidden_MaxItems = b.MaxItems
+	x.xxx_hidden_MinItems = b.MinItems
+	x.xxx_hidden_UniqueItems = b.UniqueItems
+	x.xxx_hidden_MaxProperties = b.MaxProperties
+	x.xxx_hidden_MinProperties = b.MinProperties
+	x.xxx_hidden_Required = b.Required
+	x.xxx_hidden_Array = b.Array
+	x.xxx_hidden_Type = b.Type
+	x.xxx_hidden_Format = b.Format
+	x.xxx_hidden_Enum = b.Enum
+	x.xxx_hidden_FieldConfiguration = b.FieldConfiguration
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `Tag` is a representation of OpenAPI v2 specification's Tag object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
+type Tag struct {
+	state                   protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Name         string                     `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	xxx_hidden_Description  string                     `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_ExternalDocs *ExternalDocumentation     `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"`
+	xxx_hidden_Extensions   map[string]*structpb.Value `protobuf:"bytes,4,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields           protoimpl.UnknownFields
+	sizeCache               protoimpl.SizeCache
+}
+
+func (x *Tag) Reset() {
+	*x = Tag{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[13]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Tag) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Tag) ProtoMessage() {}
+
+func (x *Tag) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[13]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Tag) GetName() string {
+	if x != nil {
+		return x.xxx_hidden_Name
+	}
+	return ""
+}
+
+func (x *Tag) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *Tag) GetExternalDocs() *ExternalDocumentation {
+	if x != nil {
+		return x.xxx_hidden_ExternalDocs
+	}
+	return nil
+}
+
+func (x *Tag) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *Tag) SetName(v string) {
+	x.xxx_hidden_Name = v
+}
+
+func (x *Tag) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *Tag) SetExternalDocs(v *ExternalDocumentation) {
+	x.xxx_hidden_ExternalDocs = v
+}
+
+func (x *Tag) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *Tag) HasExternalDocs() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_ExternalDocs != nil
+}
+
+func (x *Tag) ClearExternalDocs() {
+	x.xxx_hidden_ExternalDocs = nil
+}
+
+type Tag_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The name of the tag. Use it to allow override of the name of a
+	// global Tag object, then use that name to reference the tag throughout the
+	// OpenAPI file.
+	Name string
+	// A short description for the tag. GFM syntax can be used for rich text
+	// representation.
+	Description string
+	// Additional external documentation for this tag.
+	ExternalDocs *ExternalDocumentation
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 Tag_builder) Build() *Tag {
+	m0 := &Tag{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Name = b.Name
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_ExternalDocs = b.ExternalDocs
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
+// Security Definitions object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
+//
+// A declaration of the security schemes available to be used in the
+// specification. This does not enforce the security schemes on the operations
+// and only serves to provide the relevant details for each scheme.
+type SecurityDefinitions struct {
+	state               protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *SecurityDefinitions) Reset() {
+	*x = SecurityDefinitions{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[14]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityDefinitions) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityDefinitions) ProtoMessage() {}
+
+func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[14]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme {
+	if x != nil {
+		return x.xxx_hidden_Security
+	}
+	return nil
+}
+
+func (x *SecurityDefinitions) SetSecurity(v map[string]*SecurityScheme) {
+	x.xxx_hidden_Security = v
+}
+
+type SecurityDefinitions_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// A single security scheme definition, mapping a "name" to the scheme it
+	// defines.
+	Security map[string]*SecurityScheme
+}
+
+func (b0 SecurityDefinitions_builder) Build() *SecurityDefinitions {
+	m0 := &SecurityDefinitions{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Security = b.Security
+	return m0
+}
+
+// `SecurityScheme` is a representation of OpenAPI v2 specification's
+// Security Scheme object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
+//
+// Allows the definition of a security scheme that can be used by the
+// operations. Supported schemes are basic authentication, an API key (either as
+// a header or as a query parameter) and OAuth2's common flows (implicit,
+// password, application and access code).
+type SecurityScheme struct {
+	state                       protoimpl.MessageState     `protogen:"opaque.v1"`
+	xxx_hidden_Type             SecurityScheme_Type        `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_Type" json:"type,omitempty"`
+	xxx_hidden_Description      string                     `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+	xxx_hidden_Name             string                     `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+	xxx_hidden_In               SecurityScheme_In          `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_In" json:"in,omitempty"`
+	xxx_hidden_Flow             SecurityScheme_Flow        `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme_Flow" json:"flow,omitempty"`
+	xxx_hidden_AuthorizationUrl string                     `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"`
+	xxx_hidden_TokenUrl         string                     `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"`
+	xxx_hidden_Scopes           *Scopes                    `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"`
+	xxx_hidden_Extensions       map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields               protoimpl.UnknownFields
+	sizeCache                   protoimpl.SizeCache
+}
+
+func (x *SecurityScheme) Reset() {
+	*x = SecurityScheme{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[15]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityScheme) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityScheme) ProtoMessage() {}
+
+func (x *SecurityScheme) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[15]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityScheme) GetType() SecurityScheme_Type {
+	if x != nil {
+		return x.xxx_hidden_Type
+	}
+	return SecurityScheme_TYPE_INVALID
+}
+
+func (x *SecurityScheme) GetDescription() string {
+	if x != nil {
+		return x.xxx_hidden_Description
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetName() string {
+	if x != nil {
+		return x.xxx_hidden_Name
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetIn() SecurityScheme_In {
+	if x != nil {
+		return x.xxx_hidden_In
+	}
+	return SecurityScheme_IN_INVALID
+}
+
+func (x *SecurityScheme) GetFlow() SecurityScheme_Flow {
+	if x != nil {
+		return x.xxx_hidden_Flow
+	}
+	return SecurityScheme_FLOW_INVALID
+}
+
+func (x *SecurityScheme) GetAuthorizationUrl() string {
+	if x != nil {
+		return x.xxx_hidden_AuthorizationUrl
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetTokenUrl() string {
+	if x != nil {
+		return x.xxx_hidden_TokenUrl
+	}
+	return ""
+}
+
+func (x *SecurityScheme) GetScopes() *Scopes {
+	if x != nil {
+		return x.xxx_hidden_Scopes
+	}
+	return nil
+}
+
+func (x *SecurityScheme) GetExtensions() map[string]*structpb.Value {
+	if x != nil {
+		return x.xxx_hidden_Extensions
+	}
+	return nil
+}
+
+func (x *SecurityScheme) SetType(v SecurityScheme_Type) {
+	x.xxx_hidden_Type = v
+}
+
+func (x *SecurityScheme) SetDescription(v string) {
+	x.xxx_hidden_Description = v
+}
+
+func (x *SecurityScheme) SetName(v string) {
+	x.xxx_hidden_Name = v
+}
+
+func (x *SecurityScheme) SetIn(v SecurityScheme_In) {
+	x.xxx_hidden_In = v
+}
+
+func (x *SecurityScheme) SetFlow(v SecurityScheme_Flow) {
+	x.xxx_hidden_Flow = v
+}
+
+func (x *SecurityScheme) SetAuthorizationUrl(v string) {
+	x.xxx_hidden_AuthorizationUrl = v
+}
+
+func (x *SecurityScheme) SetTokenUrl(v string) {
+	x.xxx_hidden_TokenUrl = v
+}
+
+func (x *SecurityScheme) SetScopes(v *Scopes) {
+	x.xxx_hidden_Scopes = v
+}
+
+func (x *SecurityScheme) SetExtensions(v map[string]*structpb.Value) {
+	x.xxx_hidden_Extensions = v
+}
+
+func (x *SecurityScheme) HasScopes() bool {
+	if x == nil {
+		return false
+	}
+	return x.xxx_hidden_Scopes != nil
+}
+
+func (x *SecurityScheme) ClearScopes() {
+	x.xxx_hidden_Scopes = nil
+}
+
+type SecurityScheme_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// The type of the security scheme. Valid values are "basic",
+	// "apiKey" or "oauth2".
+	Type SecurityScheme_Type
+	// A short description for security scheme.
+	Description string
+	// The name of the header or query parameter to be used.
+	// Valid for apiKey.
+	Name string
+	// The location of the API key. Valid values are "query" or
+	// "header".
+	// Valid for apiKey.
+	In SecurityScheme_In
+	// The flow used by the OAuth2 security scheme. Valid values are
+	// "implicit", "password", "application" or "accessCode".
+	// Valid for oauth2.
+	Flow SecurityScheme_Flow
+	// The authorization URL to be used for this flow. This SHOULD be in
+	// the form of a URL.
+	// Valid for oauth2/implicit and oauth2/accessCode.
+	AuthorizationUrl string
+	// The token URL to be used for this flow. This SHOULD be in the
+	// form of a URL.
+	// Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+	TokenUrl string
+	// The available scopes for the OAuth2 security scheme.
+	// Valid for oauth2.
+	Scopes *Scopes
+	// Custom properties that start with "x-" such as "x-foo" used to describe
+	// extra functionality that is not covered by the standard OpenAPI Specification.
+	// See: https://swagger.io/docs/specification/2-0/swagger-extensions/
+	Extensions map[string]*structpb.Value
+}
+
+func (b0 SecurityScheme_builder) Build() *SecurityScheme {
+	m0 := &SecurityScheme{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Type = b.Type
+	x.xxx_hidden_Description = b.Description
+	x.xxx_hidden_Name = b.Name
+	x.xxx_hidden_In = b.In
+	x.xxx_hidden_Flow = b.Flow
+	x.xxx_hidden_AuthorizationUrl = b.AuthorizationUrl
+	x.xxx_hidden_TokenUrl = b.TokenUrl
+	x.xxx_hidden_Scopes = b.Scopes
+	x.xxx_hidden_Extensions = b.Extensions
+	return m0
+}
+
+// `SecurityRequirement` is a representation of OpenAPI v2 specification's
+// Security Requirement object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
+//
+// Lists the required security schemes to execute this operation. The object can
+// have multiple security schemes declared in it which are all required (that
+// is, there is a logical AND between the schemes).
+//
+// The name used for each property MUST correspond to a security scheme
+// declared in the Security Definitions.
+type SecurityRequirement struct {
+	state                          protoimpl.MessageState                                   `protogen:"opaque.v1"`
+	xxx_hidden_SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields                  protoimpl.UnknownFields
+	sizeCache                      protoimpl.SizeCache
+}
+
+func (x *SecurityRequirement) Reset() {
+	*x = SecurityRequirement{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[16]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityRequirement) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityRequirement) ProtoMessage() {}
+
+func (x *SecurityRequirement) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[16]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue {
+	if x != nil {
+		return x.xxx_hidden_SecurityRequirement
+	}
+	return nil
+}
+
+func (x *SecurityRequirement) SetSecurityRequirement(v map[string]*SecurityRequirement_SecurityRequirementValue) {
+	x.xxx_hidden_SecurityRequirement = v
+}
+
+type SecurityRequirement_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Each name must correspond to a security scheme which is declared in
+	// the Security Definitions. If the security scheme is of type "oauth2",
+	// then the value is a list of scope names required for the execution.
+	// For other security scheme types, the array MUST be empty.
+	SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue
+}
+
+func (b0 SecurityRequirement_builder) Build() *SecurityRequirement {
+	m0 := &SecurityRequirement{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_SecurityRequirement = b.SecurityRequirement
+	return m0
+}
+
+// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
+//
+// Lists the available scopes for an OAuth2 security scheme.
+type Scopes struct {
+	state            protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Scope map[string]string      `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Scopes) Reset() {
+	*x = Scopes{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[17]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Scopes) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Scopes) ProtoMessage() {}
+
+func (x *Scopes) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[17]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *Scopes) GetScope() map[string]string {
+	if x != nil {
+		return x.xxx_hidden_Scope
+	}
+	return nil
+}
+
+func (x *Scopes) SetScope(v map[string]string) {
+	x.xxx_hidden_Scope = v
+}
+
+type Scopes_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Maps between a name of a scope to a short description of it (as the value
+	// of the property).
+	Scope map[string]string
+}
+
+func (b0 Scopes_builder) Build() *Scopes {
+	m0 := &Scopes{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Scope = b.Scope
+	return m0
+}
+
+// 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file.
+// These properties are not defined by OpenAPIv2, but they are used to control the generation.
+type JSONSchema_FieldConfiguration struct {
+	state                    protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_PathParamName string                 `protobuf:"bytes,47,opt,name=path_param_name,json=pathParamName,proto3" json:"path_param_name,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *JSONSchema_FieldConfiguration) Reset() {
+	*x = JSONSchema_FieldConfiguration{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[27]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *JSONSchema_FieldConfiguration) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JSONSchema_FieldConfiguration) ProtoMessage() {}
+
+func (x *JSONSchema_FieldConfiguration) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[27]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *JSONSchema_FieldConfiguration) GetPathParamName() string {
+	if x != nil {
+		return x.xxx_hidden_PathParamName
+	}
+	return ""
+}
+
+func (x *JSONSchema_FieldConfiguration) SetPathParamName(v string) {
+	x.xxx_hidden_PathParamName = v
+}
+
+type JSONSchema_FieldConfiguration_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	// Alternative parameter name when used as path parameter. If set, this will
+	// be used as the complete parameter name when this field is used as a path
+	// parameter. Use this to avoid having auto generated path parameter names
+	// for overlapping paths.
+	PathParamName string
+}
+
+func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfiguration {
+	m0 := &JSONSchema_FieldConfiguration{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_PathParamName = b.PathParamName
+	return m0
+}
+
+// If the security scheme is of type "oauth2", then the value is a list of
+// scope names required for the execution. For other security scheme types,
+// the array MUST be empty.
+type SecurityRequirement_SecurityRequirementValue struct {
+	state            protoimpl.MessageState `protogen:"opaque.v1"`
+	xxx_hidden_Scope []string               `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) Reset() {
+	*x = SecurityRequirement_SecurityRequirementValue{}
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[32]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {}
+
+func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message {
+	mi := &file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes[32]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string {
+	if x != nil {
+		return x.xxx_hidden_Scope
+	}
+	return nil
+}
+
+func (x *SecurityRequirement_SecurityRequirementValue) SetScope(v []string) {
+	x.xxx_hidden_Scope = v
+}
+
+type SecurityRequirement_SecurityRequirementValue_builder struct {
+	_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+	Scope []string
+}
+
+func (b0 SecurityRequirement_SecurityRequirementValue_builder) Build() *SecurityRequirement_SecurityRequirementValue {
+	m0 := &SecurityRequirement_SecurityRequirementValue{}
+	b, x := &b0, m0
+	_, _ = b, x
+	x.xxx_hidden_Scope = b.Scope
+	return m0
+}
+
+var File_protoc_gen_openapiv3_options_openapiv3_proto protoreflect.FileDescriptor
+
+var file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc = []byte{
+	0x0a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63,
+	0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x08, 0x0a, 0x07, 0x53, 0x77, 0x61, 0x67,
+	0x67, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x12, 0x43, 0x0a,
+	0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e,
+	0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70,
+	0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50,
+	0x61, 0x74, 0x68, 0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73,
+	0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08,
+	0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
+	0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72,
+	0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09,
+	0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x71, 0x0a, 0x14, 0x73, 0x65, 0x63,
+	0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69,
+	0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69,
+	0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72,
+	0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73,
+	0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x65, 0x0a, 0x0d,
+	0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x0e, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44,
+	0x6f, 0x63, 0x73, 0x12, 0x62, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+	0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52,
+	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0xd6, 0x07,
+	0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74,
+	0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12,
+	0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 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, 0x65, 0x0a, 0x0d, 0x65,
+	0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45,
+	0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f,
+	0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+	0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
+	0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
+	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x73, 0x12, 0x61, 0x0a,
+	0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61,
+	0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65,
+	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x12, 0x4b, 0x0a, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28,
+	0x0e, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63,
+	0x68, 0x65, 0x6d, 0x65, 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x73, 0x12, 0x1e, 0x0a,
+	0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x5a, 0x0a,
+	0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52,
+	0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x64, 0x0a, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+	0x55, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0e, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61,
+	0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x1a, 0x71, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f,
+	0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+	0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c,
+	0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+	0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0x62, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,
+	0x74, 0x65, 0x72, 0x73, 0x12, 0x54, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
+	0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0xa3, 0x02, 0x0a, 0x0f, 0x48,
+	0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x3f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x48,
+	0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2e, 0x54,
+	0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72,
+	0x6d, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x45, 0x0a,
+	0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
+	0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0a,
+	0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e,
+	0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45,
+	0x41, 0x4e, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08,
+	0x22, 0xd8, 0x01, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
+	0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66,
+	0x61, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61,
+	0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x0d,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x4a, 0x04, 0x08,
+	0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a,
+	0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10,
+	0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08,
+	0x0e, 0x10, 0x0f, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a,
+	0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0x9a, 0x05, 0x0a, 0x08,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63,
+	0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73,
+	0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x5a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+	0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64,
+	0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
+	0x73, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+	0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
+	0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66,
+	0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 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, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x65, 0x72,
+	0x6d, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x4f, 0x66, 0x53, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63,
+	0x74, 0x12, 0x4c, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+	0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65,
+	0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c,
+	0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12,
+	0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x45,
+	0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a,
+	0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x22, 0x45, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75,
+	0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x2f, 0x0a, 0x07, 0x4c, 0x69, 0x63, 0x65,
+	0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x4b, 0x0a, 0x15, 0x45, 0x78, 0x74,
+	0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xaa, 0x02, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x12, 0x56, 0x0a, 0x0b, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0a, 0x6a,
+	0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x69, 0x73,
+	0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x72, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12,
+	0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a, 0x0d,
+	0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44,
+	0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08,
+	0x04, 0x10, 0x05, 0x22, 0xe8, 0x03, 0x0a, 0x0a, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x69, 0x74, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
+	0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x65, 0x0a,
+	0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e,
+	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
+	0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x10,
+	0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66,
+	0x12, 0x65, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f,
+	0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65,
+	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd7,
+	0x0a, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a,
+	0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12,
+	0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+	0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08,
+	0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18,
+	0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x75, 0x6c, 0x74,
+	0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x6d,
+	0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78,
+	0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69,
+	0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65,
+	0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
+	0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d,
+	0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28,
+	0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78,
+	0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18,
+	0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65,
+	0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x6c,
+	0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x78,
+	0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x65,
+	0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x4c,
+	0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e,
+	0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12,
+	0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09,
+	0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x69,
+	0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e,
+	0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x18,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74,
+	0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65,
+	0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e,
+	0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18,
+	0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x5f, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, 0x2e, 0x67, 0x72, 0x70,
+	0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a,
+	0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66,
+	0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0x2e, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x12, 0x7a, 0x0a, 0x13, 0x66, 0x69, 0x65,
+	0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x46,
+	0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+	0x6e, 0x52, 0x12, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+	0x6f, 0x6e, 0x73, 0x18, 0x30, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x72, 0x70, 0x63,
+	0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f,
+	0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,
+	0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3c, 0x0a, 0x12,
+	0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x74,
+	0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78,
+	0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53,
+	0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e,
+	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59,
+	0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12,
+	0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04,
+	0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52,
+	0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a,
+	0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02,
+	0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x12,
+	0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04,
+	0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e,
+	0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a,
+	0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0xd9, 0x02, 0x0a, 0x03, 0x54, 0x61, 0x67,
+	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e,
+	0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e,
+	0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+	0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x5e, 0x0a,
+	0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e,
+	0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x54, 0x61,
+	0x67, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a,
+	0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0xf7, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x68, 0x0a, 0x08,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4c,
+	0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69,
+	0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72,
+	0x69, 0x74, 0x79, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53,
+	0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65,
+	0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x1a, 0x76, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+	0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e,
+	0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67,
+	0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68,
+	0x65, 0x6d, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xff,
+	0x06, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x65, 0x12, 0x52, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70,
+	0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
+	0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x02, 0x69,
+	0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x65, 0x2e, 0x49, 0x6e, 0x52, 0x02, 0x69, 0x6e, 0x12, 0x52, 0x0a, 0x04, 0x66, 0x6c, 0x6f,
+	0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65,
+	0x6d, 0x65, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x2b, 0x0a,
+	0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75,
+	0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
+	0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f,
+	0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74,
+	0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65,
+	0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70,
+	0x65, 0x73, 0x12, 0x69, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+	0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e,
+	0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d,
+	0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x55, 0x0a,
+	0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0e,
+	0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x01, 0x12, 0x10,
+	0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02,
+	0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, 0x10,
+	0x03, 0x22, 0x31, 0x0a, 0x02, 0x49, 0x6e, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x5f, 0x49, 0x4e,
+	0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x5f, 0x51, 0x55,
+	0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x48, 0x45, 0x41, 0x44,
+	0x45, 0x52, 0x10, 0x02, 0x22, 0x6a, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x10, 0x0a, 0x0c,
+	0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x11,
+	0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, 0x10,
+	0x01, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f,
+	0x52, 0x44, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x41, 0x50, 0x50,
+	0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x4c,
+	0x4f, 0x57, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x04,
+	0x22, 0xf6, 0x02, 0x0a, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71,
+	0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x8a, 0x01, 0x0a, 0x14, 0x73, 0x65, 0x63,
+	0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e,
+	0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65,
+	0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75,
+	0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+	0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72,
+	0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x30, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+	0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x9f, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75,
+	0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x6d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x57, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74,
+	0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f,
+	0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72,
+	0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65,
+	0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x53, 0x63,
+	0x6f, 0x70, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77,
+	0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70,
+	0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x33, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+	0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x1a, 0x38, 0x0a, 0x0a, 0x53, 0x63, 0x6f, 0x70,
+	0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
+	0x38, 0x01, 0x2a, 0x3b, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x0b, 0x0a, 0x07,
+	0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54,
+	0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x02, 0x12, 0x06,
+	0x0a, 0x02, 0x57, 0x53, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x57, 0x53, 0x53, 0x10, 0x04, 0x42,
+	0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72,
+	0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70,
+	0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76,
+	0x33, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
+}
+
+var file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
+var file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes = make([]protoimpl.MessageInfo, 35)
+var file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes = []any{
+	(Scheme)(0),                           // 0: grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	(HeaderParameter_Type)(0),             // 1: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.Type
+	(JSONSchema_JSONSchemaSimpleTypes)(0), // 2: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.JSONSchemaSimpleTypes
+	(SecurityScheme_Type)(0),              // 3: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Type
+	(SecurityScheme_In)(0),                // 4: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.In
+	(SecurityScheme_Flow)(0),              // 5: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Flow
+	(*Swagger)(nil),                       // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger
+	(*Operation)(nil),                     // 7: grpc.gateway.protoc_gen_openapiv3.options.Operation
+	(*Parameters)(nil),                    // 8: grpc.gateway.protoc_gen_openapiv3.options.Parameters
+	(*HeaderParameter)(nil),               // 9: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter
+	(*Header)(nil),                        // 10: grpc.gateway.protoc_gen_openapiv3.options.Header
+	(*Response)(nil),                      // 11: grpc.gateway.protoc_gen_openapiv3.options.Response
+	(*Info)(nil),                          // 12: grpc.gateway.protoc_gen_openapiv3.options.Info
+	(*Contact)(nil),                       // 13: grpc.gateway.protoc_gen_openapiv3.options.Contact
+	(*License)(nil),                       // 14: grpc.gateway.protoc_gen_openapiv3.options.License
+	(*ExternalDocumentation)(nil),         // 15: grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	(*Schema)(nil),                        // 16: grpc.gateway.protoc_gen_openapiv3.options.Schema
+	(*EnumSchema)(nil),                    // 17: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema
+	(*JSONSchema)(nil),                    // 18: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	(*Tag)(nil),                           // 19: grpc.gateway.protoc_gen_openapiv3.options.Tag
+	(*SecurityDefinitions)(nil),           // 20: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions
+	(*SecurityScheme)(nil),                // 21: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme
+	(*SecurityRequirement)(nil),           // 22: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	(*Scopes)(nil),                        // 23: grpc.gateway.protoc_gen_openapiv3.options.Scopes
+	nil,                                   // 24: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry
+	nil,                                   // 25: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry
+	nil,                                   // 26: grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry
+	nil,                                   // 27: grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry
+	nil,                                   // 28: grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry
+	nil,                                   // 29: grpc.gateway.protoc_gen_openapiv3.options.Response.ExamplesEntry
+	nil,                                   // 30: grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry
+	nil,                                   // 31: grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry
+	nil,                                   // 32: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry
+	(*JSONSchema_FieldConfiguration)(nil), // 33: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.FieldConfiguration
+	nil,                                   // 34: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry
+	nil,                                   // 35: grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry
+	nil,                                   // 36: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry
+	nil,                                   // 37: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry
+	(*SecurityRequirement_SecurityRequirementValue)(nil), // 38: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementValue
+	nil,                    // 39: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry
+	nil,                    // 40: grpc.gateway.protoc_gen_openapiv3.options.Scopes.ScopeEntry
+	(*structpb.Value)(nil), // 41: google.protobuf.Value
+}
+var file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs = []int32{
+	12, // 0: grpc.gateway.protoc_gen_openapiv3.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Info
+	0,  // 1: grpc.gateway.protoc_gen_openapiv3.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	24, // 2: grpc.gateway.protoc_gen_openapiv3.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry
+	20, // 3: grpc.gateway.protoc_gen_openapiv3.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions
+	22, // 4: grpc.gateway.protoc_gen_openapiv3.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	19, // 5: grpc.gateway.protoc_gen_openapiv3.options.Swagger.tags:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag
+	15, // 6: grpc.gateway.protoc_gen_openapiv3.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	25, // 7: grpc.gateway.protoc_gen_openapiv3.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry
+	15, // 8: grpc.gateway.protoc_gen_openapiv3.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	26, // 9: grpc.gateway.protoc_gen_openapiv3.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry
+	0,  // 10: grpc.gateway.protoc_gen_openapiv3.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scheme
+	22, // 11: grpc.gateway.protoc_gen_openapiv3.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement
+	27, // 12: grpc.gateway.protoc_gen_openapiv3.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry
+	8,  // 13: grpc.gateway.protoc_gen_openapiv3.options.Operation.parameters:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Parameters
+	9,  // 14: grpc.gateway.protoc_gen_openapiv3.options.Parameters.headers:type_name -> grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter
+	1,  // 15: grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.HeaderParameter.Type
+	16, // 16: grpc.gateway.protoc_gen_openapiv3.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Schema
+	28, // 17: grpc.gateway.protoc_gen_openapiv3.options.Response.headers:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry
+	29, // 18: grpc.gateway.protoc_gen_openapiv3.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.ExamplesEntry
+	30, // 19: grpc.gateway.protoc_gen_openapiv3.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry
+	13, // 20: grpc.gateway.protoc_gen_openapiv3.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Contact
+	14, // 21: grpc.gateway.protoc_gen_openapiv3.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv3.options.License
+	31, // 22: grpc.gateway.protoc_gen_openapiv3.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry
+	18, // 23: grpc.gateway.protoc_gen_openapiv3.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema
+	15, // 24: grpc.gateway.protoc_gen_openapiv3.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	15, // 25: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	32, // 26: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry
+	2,  // 27: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.JSONSchemaSimpleTypes
+	33, // 28: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.field_configuration:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.FieldConfiguration
+	34, // 29: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry
+	15, // 30: grpc.gateway.protoc_gen_openapiv3.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv3.options.ExternalDocumentation
+	35, // 31: grpc.gateway.protoc_gen_openapiv3.options.Tag.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry
+	36, // 32: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry
+	3,  // 33: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Type
+	4,  // 34: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.In
+	5,  // 35: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.Flow
+	23, // 36: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scopes
+	37, // 37: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry
+	39, // 38: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry
+	40, // 39: grpc.gateway.protoc_gen_openapiv3.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Scopes.ScopeEntry
+	11, // 40: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response
+	41, // 41: grpc.gateway.protoc_gen_openapiv3.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	11, // 42: grpc.gateway.protoc_gen_openapiv3.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Response
+	41, // 43: grpc.gateway.protoc_gen_openapiv3.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	10, // 44: grpc.gateway.protoc_gen_openapiv3.options.Response.HeadersEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.Header
+	41, // 45: grpc.gateway.protoc_gen_openapiv3.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 46: grpc.gateway.protoc_gen_openapiv3.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 47: grpc.gateway.protoc_gen_openapiv3.options.EnumSchema.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 48: grpc.gateway.protoc_gen_openapiv3.options.JSONSchema.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	41, // 49: grpc.gateway.protoc_gen_openapiv3.options.Tag.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	21, // 50: grpc.gateway.protoc_gen_openapiv3.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme
+	41, // 51: grpc.gateway.protoc_gen_openapiv3.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value
+	38, // 52: grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv3.options.SecurityRequirement.SecurityRequirementValue
+	53, // [53:53] is the sub-list for method output_type
+	53, // [53:53] is the sub-list for method input_type
+	53, // [53:53] is the sub-list for extension type_name
+	53, // [53:53] is the sub-list for extension extendee
+	0,  // [0:53] is the sub-list for field type_name
+}
+
+func init() { file_protoc_gen_openapiv3_options_openapiv3_proto_init() }
+func file_protoc_gen_openapiv3_options_openapiv3_proto_init() {
+	if File_protoc_gen_openapiv3_options_openapiv3_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc,
+			NumEnums:      6,
+			NumMessages:   35,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes,
+		DependencyIndexes: file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs,
+		EnumInfos:         file_protoc_gen_openapiv3_options_openapiv3_proto_enumTypes,
+		MessageInfos:      file_protoc_gen_openapiv3_options_openapiv3_proto_msgTypes,
+	}.Build()
+	File_protoc_gen_openapiv3_options_openapiv3_proto = out.File
+	file_protoc_gen_openapiv3_options_openapiv3_proto_rawDesc = nil
+	file_protoc_gen_openapiv3_options_openapiv3_proto_goTypes = nil
+	file_protoc_gen_openapiv3_options_openapiv3_proto_depIdxs = nil
+}