feat: updated grpc gateway related code

This commit is contained in:
Andrey Melnikov
2020-12-17 14:09:20 -08:00
parent 2a01138cf3
commit d99189807d
42 changed files with 12143 additions and 419 deletions

View File

@@ -19,10 +19,17 @@ protoc:
protoc -I/usr/local/include \
-Iapi/third_party/ \
-Iapi/ \
api/*.proto \
--go_out=plugins=grpc:api \
--grpc-gateway_out=logtostderr=true,allow_delete_body=true:api \
--swagger_out=allow_merge=true,fqn_for_swagger_name=true,allow_delete_body=true,logtostderr=true,simple_operation_ids=true:api
--grpc-gateway_out ./api \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
--grpc-gateway_opt generate_unbound_methods=true \
--openapiv2_out ./api \
--openapiv2_opt allow_merge=true \
--openapiv2_opt fqn_for_openapi_name=true \
--openapiv2_opt allow_delete_body=true \
--openapiv2_opt logtostderr=true \
--openapiv2_opt simple_operation_ids=true \
api/*.proto
api: init protoc jq

View File

@@ -2,9 +2,9 @@ syntax = "proto3";
package api;
import "protoc-gen-swagger/options/annotations.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Onepanel";
description: "Onepanel API";

View File

@@ -3,7 +3,7 @@ syntax = "proto3";
package api;
import "google/api/annotations.proto";
import "protoc-gen-swagger/options/annotations.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
service AuthService {
rpc IsValidToken(IsValidTokenRequest) returns (IsValidTokenResponse) {
@@ -19,7 +19,8 @@ service AuthService {
post: "/apis/v1beta1/auth/get_access_token"
body: "*"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
security: {
}
};

0
api/third_party/google/LICENSE → api/third_party/LICENSE vendored Executable file → Normal file
View File

23
api/third_party/README.grpc-gateway vendored Normal file
View File

@@ -0,0 +1,23 @@
Google APIs
============
Project: Google APIs
URL: https://github.com/google/googleapis
Revision: 3544ab16c3342d790b00764251e348705991ea4b
License: Apache License 2.0
Imported Files
---------------
- google/api/annotations.proto
- google/api/http.proto
- google/api/httpbody.proto
Generated Files
----------------
They are generated from the .proto files by protoc-gen-go.
- google/api/annotations.pb.go
- google/api/http.pb.go

0
api/third_party/google/api/annotations.proto vendored Executable file → Normal file
View File

View File

@@ -0,0 +1,78 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/protobuf/descriptor.proto";
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "FieldBehaviorProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.FieldOptions {
// A designation of a specific field behavior (required, output only, etc.)
// in protobuf messages.
//
// Examples:
//
// string name = 1 [(google.api.field_behavior) = REQUIRED];
// State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
// google.protobuf.Duration ttl = 1
// [(google.api.field_behavior) = INPUT_ONLY];
// google.protobuf.Timestamp expire_time = 1
// [(google.api.field_behavior) = OUTPUT_ONLY,
// (google.api.field_behavior) = IMMUTABLE];
repeated google.api.FieldBehavior field_behavior = 1052;
}
// An indicator of the behavior of a given field (for example, that a field
// is required in requests, or given as output but ignored as input).
// This **does not** change the behavior in protocol buffers itself; it only
// denotes the behavior and may affect how API tooling handles the field.
//
// Note: This enum **may** receive new values in the future.
enum FieldBehavior {
// Conventional default for enums. Do not use this.
FIELD_BEHAVIOR_UNSPECIFIED = 0;
// Specifically denotes a field as optional.
// While all fields in protocol buffers are optional, this may be specified
// for emphasis if appropriate.
OPTIONAL = 1;
// Denotes a field as required.
// This indicates that the field **must** be provided as part of the request,
// and failure to do so will cause an error (usually `INVALID_ARGUMENT`).
REQUIRED = 2;
// Denotes a field as output only.
// This indicates that the field is provided in responses, but including the
// field in a request does nothing (the server *must* ignore it and
// *must not* throw an error as a result of the field's presence).
OUTPUT_ONLY = 3;
// Denotes a field as input only.
// This indicates that the field is provided in requests, and the
// corresponding field is not included in output.
INPUT_ONLY = 4;
// Denotes a field as immutable.
// This indicates that the field may be set once in a request to create a
// resource, but may not be changed thereafter.
IMMUTABLE = 5;
}

0
api/third_party/google/api/http.proto vendored Executable file → Normal file
View File

0
api/third_party/google/api/httpbody.proto vendored Executable file → Normal file
View File

0
api/third_party/google/rpc/code.proto vendored Executable file → Normal file
View File

0
api/third_party/google/rpc/error_details.proto vendored Executable file → Normal file
View File

0
api/third_party/google/rpc/status.proto vendored Executable file → Normal file
View File

View File

@@ -0,0 +1,30 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
package(default_visibility = ["//visibility:private"])
go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2",
deps = [
"//internal/codegenerator:go_default_library",
"//internal/descriptor:go_default_library",
"//protoc-gen-openapiv2/internal/genopenapi:go_default_library",
"@com_github_golang_glog//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//types/pluginpb:go_default_library",
],
)
go_binary(
name = "protoc-gen-openapiv2",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
size = "small",
srcs = ["main_test.go"],
embed = [":go_default_library"],
)

View File

@@ -0,0 +1,308 @@
"""Generated an open-api spec for a grpc api spec.
Reads the 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.direct_sources]
offset = len(source_root) + 1 # + '/'.
infos = []
for src in proto_info.direct_sources:
# 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 happend, 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_openapiv2,
single_output,
allow_delete_body,
grpc_api_configuration,
json_names_for_fields,
repeated_path_param_separator,
include_package_in_tags,
fqn_for_openapi_name,
use_go_templates,
disable_default_errors,
enums_as_ints,
simple_operation_ids,
openapi_configuration,
generate_unbound_methods):
args = actions.args()
args.add("--plugin", "protoc-gen-openapiv2=%s" % protoc_gen_openapiv2.path)
args.add("--openapiv2_opt", "logtostderr=true")
args.add("--openapiv2_opt", "allow_repeated_fields_in_body=true")
extra_inputs = []
if grpc_api_configuration:
extra_inputs.append(grpc_api_configuration)
args.add("--openapiv2_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path)
if openapi_configuration:
extra_inputs.append(openapi_configuration)
args.add("--openapiv2_opt", "openapi_configuration=%s" % openapi_configuration.path)
if not json_names_for_fields:
args.add("--openapiv2_opt", "json_names_for_fields=false")
if fqn_for_openapi_name:
args.add("--openapiv2_opt", "fqn_for_openapi_name=true")
if generate_unbound_methods:
args.add("--openapiv2_opt", "generate_unbound_methods=true")
if simple_operation_ids:
args.add("--openapiv2_opt", "simple_operation_ids=true")
if allow_delete_body:
args.add("--openapiv2_opt", "allow_delete_body=true")
if include_package_in_tags:
args.add("--openapiv2_opt", "include_package_in_tags=true")
if use_go_templates:
args.add("--openapiv2_opt", "use_go_templates=true")
if disable_default_errors:
args.add("--openapiv2_opt", "disable_default_errors=true")
if enums_as_ints:
args.add("--openapiv2_opt", "enums_as_ints=true")
args.add("--openapiv2_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("--openapiv2_opt", "allow_merge=true")
args.add("--openapiv2_opt", "merge_file_name=%s" % target_name)
openapi_file = actions.declare_file("%s.swagger.json" % target_name)
args.add("--openapiv2_out", openapi_file.dirname)
args.add_all([f.import_path for f in proto_file_infos])
actions.run(
executable = protoc,
tools = [protoc_gen_openapiv2],
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("--openapiv2_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("--openapiv2_out", openapi_file.path[:-offset])
file_args.add(proto_file_info.import_path)
actions.run(
executable = protoc,
tools = [protoc_gen_openapiv2],
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_openapiv2 = 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,
use_go_templates = ctx.attr.use_go_templates,
disable_default_errors = ctx.attr.disable_default_errors,
enums_as_ints = ctx.attr.enums_as_ints,
simple_operation_ids = ctx.attr.simple_operation_ids,
openapi_configuration = ctx.file.openapi_configuration,
generate_unbound_methods = ctx.attr.generate_unbound_methods,
),
),
),
]
protoc_gen_openapiv2 = 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",
),
"use_go_templates": attr.bool(
default = False,
mandatory = False,
doc = "if set, you can use Go templates in protofile 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",
),
"enums_as_ints": attr.bool(
default = False,
mandatory = False,
doc = "whether to render enum values as integers, as opposed to string values",
),
"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.",
),
"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",
),
"_protoc": attr.label(
default = "@com_google_protobuf//:protoc",
executable = True,
cfg = "host",
),
"_well_known_protos": attr.label(
default = "@com_google_protobuf//:well_known_protos",
allow_files = True,
),
"_protoc_gen_openapi": attr.label(
default = Label("//protoc-gen-openapiv2:protoc-gen-openapiv2"),
executable = True,
cfg = "host",
),
},
implementation = _proto_gen_openapi_impl,
)

View File

@@ -0,0 +1,57 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(default_visibility = ["//protoc-gen-openapiv2:__subpackages__"])
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"generator.go",
"helpers.go",
"helpers_go111_old.go",
"template.go",
"types.go",
],
importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi",
deps = [
"//internal/casing:go_default_library",
"//internal/descriptor:go_default_library",
"//internal/generator:go_default_library",
"//protoc-gen-openapiv2/options:go_default_library",
"@com_github_golang_glog//:go_default_library",
"@com_github_golang_protobuf//descriptor:go_default_library_gen",
"@go_googleapis//google/api:annotations_go_proto",
"@go_googleapis//google/rpc:status_go_proto",
"@io_bazel_rules_go//proto/wkt:any_go_proto",
"@io_bazel_rules_go//proto/wkt:struct_go_proto",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
"@org_golang_google_protobuf//types/pluginpb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = ["template_test.go"],
embed = [":go_default_library"],
deps = [
"//internal/descriptor:go_default_library",
"//internal/descriptor/openapiconfig:go_default_library",
"//internal/httprule:go_default_library",
"//protoc-gen-openapiv2/options:go_default_library",
"//runtime:go_default_library",
"@com_github_google_go_cmp//cmp:go_default_library",
"@go_googleapis//google/api:annotations_go_proto",
"@io_bazel_rules_go//proto/wkt:field_mask_go_proto",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
"@org_golang_google_protobuf//types/pluginpb:go_default_library",
],
)

View File

@@ -0,0 +1,2 @@
// Package genopenapi provides a code generator for OpenAPI v2.
package genopenapi

View File

@@ -0,0 +1,241 @@
package genopenapi
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"path/filepath"
"reflect"
"strings"
"github.com/golang/glog"
anypb "github.com/golang/protobuf/ptypes/any"
"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator"
openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
statuspb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/pluginpb"
//nolint:staticcheck // Known issue, will be replaced when possible
legacydescriptor "github.com/golang/protobuf/descriptor"
)
var (
errNoTargetService = errors.New("no target service defined in the file")
)
type generator struct {
reg *descriptor.Registry
}
type wrapper struct {
fileName string
swagger *openapiSwaggerObject
}
// New returns a new generator which generates grpc gateway files.
func New(reg *descriptor.Registry) gen.Generator {
return &generator{reg: reg}
}
// 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.Paths {
mergedTarget.swagger.Paths[k] = v
}
for k, v := range f.swagger.SecurityDefinitions {
mergedTarget.swagger.SecurityDefinitions[k] = v
}
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)
}
func (so openapiInfoObject) MarshalJSON() ([]byte, error) {
type alias openapiInfoObject
return extensionMarshalJSON(alias(so), so.extensions)
}
func (so openapiSecuritySchemeObject) MarshalJSON() ([]byte, error) {
type alias openapiSecuritySchemeObject
return extensionMarshalJSON(alias(so), so.extensions)
}
func (so openapiOperationObject) MarshalJSON() ([]byte, error) {
type alias openapiOperationObject
return extensionMarshalJSON(alias(so), so.extensions)
}
func (so openapiResponseObject) MarshalJSON() ([]byte, error) {
type alias openapiResponseObject
return extensionMarshalJSON(alias(so), so.extensions)
}
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) (*descriptor.ResponseFile, error) {
var formatted bytes.Buffer
enc := json.NewEncoder(&formatted)
enc.SetIndent("", " ")
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.json", base)
return &descriptor.ResponseFile{
CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{
Name: proto.String(output),
Content: proto.String(formatted.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, openapi_options.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 {
glog.V(1).Infof("Processing %s", file.GetName())
swagger, err := applyTemplate(param{File: file, reg: g.reg})
if err == errNoTargetService {
glog.V(1).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())
f, err := encodeOpenAPI(targetOpenAPI)
if err != nil {
return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", g.reg.GetMergeFileName(), err)
}
files = append(files, f)
glog.V(1).Infof("New OpenAPI file will emit")
} else {
for _, file := range openapis {
f, err := encodeOpenAPI(file)
if err != nil {
return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", file.fileName, err)
}
files = append(files, f)
glog.V(1).Infof("New OpenAPI file will emit")
}
}
return files, nil
}
// 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, _ := legacydescriptor.MessageDescriptorProto(&anypb.Any{})
any.SourceCodeInfo = new(descriptorpb.SourceCodeInfo)
status, _ := legacydescriptor.MessageDescriptorProto(&statuspb.Status{})
status.SourceCodeInfo = new(descriptorpb.SourceCodeInfo)
// TODO(johanbrandhorst): Use new conversion later when possible
// any := protodesc.ToFileDescriptorProto((&anypb.Any{}).ProtoReflect().Descriptor().ParentFile())
// status := protodesc.ToFileDescriptorProto((&statuspb.Status{}).ProtoReflect().Descriptor().ParentFile())
return reg.Load(&pluginpb.CodeGeneratorRequest{
ProtoFile: []*descriptorpb.FileDescriptorProto{
any,
status,
},
})
}

View File

@@ -0,0 +1,9 @@
//+build go1.12
package genopenapi
import "strings"
func fieldName(k string) string {
return strings.ReplaceAll(strings.Title(k), "-", "_")
}

View File

@@ -0,0 +1,9 @@
//+build !go1.12
package genopenapi
import "strings"
func fieldName(k string) string {
return strings.Replace(strings.Title(k), "-", "_", -1)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,276 @@
package genopenapi
import (
"bytes"
"encoding/json"
"fmt"
"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
)
type param struct {
*descriptor.File
reg *descriptor.Registry
}
// http://swagger.io/specification/#infoObject
type openapiInfoObject struct {
Title string `json:"title"`
Description string `json:"description,omitempty"`
TermsOfService string `json:"termsOfService,omitempty"`
Version string `json:"version"`
Contact *openapiContactObject `json:"contact,omitempty"`
License *openapiLicenseObject `json:"license,omitempty"`
extensions []extension
}
// https://swagger.io/specification/#tagObject
type openapiTagObject struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"`
}
// http://swagger.io/specification/#contactObject
type openapiContactObject struct {
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
Email string `json:"email,omitempty"`
}
// http://swagger.io/specification/#licenseObject
type openapiLicenseObject struct {
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
}
// http://swagger.io/specification/#externalDocumentationObject
type openapiExternalDocumentationObject struct {
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
}
type extension struct {
key string
value json.RawMessage
}
// http://swagger.io/specification/#swaggerObject
type openapiSwaggerObject struct {
Swagger string `json:"swagger"`
Info openapiInfoObject `json:"info"`
Tags []openapiTagObject `json:"tags,omitempty"`
Host string `json:"host,omitempty"`
BasePath string `json:"basePath,omitempty"`
Schemes []string `json:"schemes,omitempty"`
Consumes []string `json:"consumes"`
Produces []string `json:"produces"`
Paths openapiPathsObject `json:"paths"`
Definitions openapiDefinitionsObject `json:"definitions"`
SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty"`
Security []openapiSecurityRequirementObject `json:"security,omitempty"`
ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"`
extensions []extension
}
// http://swagger.io/specification/#securityDefinitionsObject
type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject
// http://swagger.io/specification/#securitySchemeObject
type openapiSecuritySchemeObject struct {
Type string `json:"type"`
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
In string `json:"in,omitempty"`
Flow string `json:"flow,omitempty"`
AuthorizationURL string `json:"authorizationUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty"`
Scopes openapiScopesObject `json:"scopes,omitempty"`
extensions []extension
}
// 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 map[string]openapiPathItemObject
// http://swagger.io/specification/#pathItemObject
type openapiPathItemObject struct {
Get *openapiOperationObject `json:"get,omitempty"`
Delete *openapiOperationObject `json:"delete,omitempty"`
Post *openapiOperationObject `json:"post,omitempty"`
Put *openapiOperationObject `json:"put,omitempty"`
Patch *openapiOperationObject `json:"patch,omitempty"`
}
// http://swagger.io/specification/#operationObject
type openapiOperationObject struct {
Summary string `json:"summary,omitempty"`
Description string `json:"description,omitempty"`
OperationID string `json:"operationId"`
Responses openapiResponsesObject `json:"responses"`
Parameters openapiParametersObject `json:"parameters,omitempty"`
Tags []string `json:"tags,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
Produces []string `json:"produces,omitempty"`
Security *[]openapiSecurityRequirementObject `json:"security,omitempty"`
ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"`
extensions []extension
}
type openapiParametersObject []openapiParameterObject
// http://swagger.io/specification/#parameterObject
type openapiParameterObject struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
In string `json:"in,omitempty"`
Required bool `json:"required"`
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Items *openapiItemsObject `json:"items,omitempty"`
Enum []string `json:"enum,omitempty"`
CollectionFormat string `json:"collectionFormat,omitempty"`
Default string `json:"default,omitempty"`
MinItems *int `json:"minItems,omitempty"`
// Or you can explicitly refer to another type. If this is defined all
// other fields should be empty
Schema *openapiSchemaObject `json:"schema,omitempty"`
}
// core part of schema, which is common to itemsObject and schemaObject.
// http://swagger.io/specification/#itemsObject
type schemaCore struct {
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Ref string `json:"$ref,omitempty"`
Example json.RawMessage `json:"example,omitempty"`
Items *openapiItemsObject `json:"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 []string `json:"enum,omitempty"`
Default string `json:"default,omitempty"`
}
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 '%v'", ref)
}
s.Ref = fmt.Sprintf("#/definitions/%s", name)
return nil
}
type openapiItemsObject schemaCore
// http://swagger.io/specification/#responsesObject
type openapiResponsesObject map[string]openapiResponseObject
// http://swagger.io/specification/#responseObject
type openapiResponseObject struct {
Description string `json:"description"`
Schema openapiSchemaObject `json:"schema"`
Examples map[string]interface{} `json:"examples,omitempty"`
Headers openapiHeadersObject `json:"headers,omitempty"`
extensions []extension
}
type openapiHeadersObject map[string]openapiHeaderObject
// http://swagger.io/specification/#headerObject
type openapiHeaderObject struct {
Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Default json.RawMessage `json:"default,omitempty"`
Pattern string `json:"pattern,omitempty"`
}
type keyVal struct {
Key string
Value interface{}
}
type openapiSchemaObjectProperties []keyVal
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
// Properties can be recursively defined
Properties *openapiSchemaObjectProperties `json:"properties,omitempty"`
AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty"`
Description string `json:"description,omitempty"`
Title string `json:"title,omitempty"`
ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"`
MultipleOf float64 `json:"multipleOf,omitempty"`
Maximum float64 `json:"maximum,omitempty"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
Minimum float64 `json:"minimum,omitempty"`
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
MaxLength uint64 `json:"maxLength,omitempty"`
MinLength uint64 `json:"minLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
MaxItems uint64 `json:"maxItems,omitempty"`
MinItems uint64 `json:"minItems,omitempty"`
UniqueItems bool `json:"uniqueItems,omitempty"`
MaxProperties uint64 `json:"maxProperties,omitempty"`
MinProperties uint64 `json:"minProperties,omitempty"`
Required []string `json:"required,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{}

View File

@@ -0,0 +1,220 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/golang/glog"
"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-openapiv2/internal/genopenapi"
"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")
allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option")
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")
useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile 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.")
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")
)
// Variables set by goreleaser at build time
var (
version = "dev"
commit = "unknown"
date = "unknown"
)
func main() {
flag.Parse()
defer glog.Flush()
if *versionFlag {
fmt.Printf("Version %v, commit %v, built at %v\n", version, commit, date)
os.Exit(0)
}
reg := descriptor.NewRegistry()
glog.V(1).Info("Processing code generator request")
f := os.Stdin
if *file != "-" {
var err error
f, err = os.Open(*file)
if err != nil {
glog.Fatal(err)
}
}
glog.V(1).Info("Parsing code generator request")
req, err := codegenerator.ParseRequest(f)
if err != nil {
glog.Fatal(err)
}
glog.V(1).Info("Parsed code generator request")
pkgMap := make(map[string]string)
if req.Parameter != nil {
err := parseReqParam(req.GetParameter(), flag.CommandLine, pkgMap)
if err != nil {
glog.Fatalf("Error parsing flags: %v", err)
}
}
reg.SetPrefix(*importPrefix)
reg.SetAllowDeleteBody(*allowDeleteBody)
reg.SetAllowMerge(*allowMerge)
reg.SetMergeFileName(*mergeFileName)
reg.SetUseJSONNamesForFields(*useJSONNamesForFields)
reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody)
reg.SetIncludePackageInTags(*includePackageInTags)
reg.SetUseFQNForOpenAPIName(*useFQNForOpenAPIName)
reg.SetUseGoTemplate(*useGoTemplate)
reg.SetEnumsAsInts(*enumsAsInts)
reg.SetDisableDefaultErrors(*disableDefaultErrors)
reg.SetSimpleOperationIDs(*simpleOperationIDs)
reg.SetGenerateUnboundMethods(*generateUnboundMethods)
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
}
}
g := genopenapi.New(reg)
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
}
}
var targets []*descriptor.File
for _, target := range req.FileToGenerate {
f, err := reg.LookupFile(target)
if err != nil {
glog.Fatal(err)
}
targets = append(targets, f)
}
out, err := g.Generate(targets)
glog.V(1).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
}
emitResp(&pluginpb.CodeGeneratorResponse{File: files})
}
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 {
glog.Fatal(err)
}
if _, err := os.Stdout.Write(buf); err != nil {
glog.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 {
if spec[0] == "allow_delete_body" {
err := f.Set(spec[0], "true")
if err != nil {
return fmt.Errorf("cannot set flag %s: %v", p, err)
}
continue
}
if spec[0] == "allow_merge" {
err := f.Set(spec[0], "true")
if err != nil {
return fmt.Errorf("cannot set flag %s: %v", p, err)
}
continue
}
if spec[0] == "allow_repeated_fields_in_body" {
err := f.Set(spec[0], "true")
if err != nil {
return fmt.Errorf("cannot set flag %s: %v", p, err)
}
continue
}
if spec[0] == "include_package_in_tags" {
err := f.Set(spec[0], "true")
if err != nil {
return fmt.Errorf("cannot set flag %s: %v", p, err)
}
continue
}
err := f.Set(spec[0], "")
if err != nil {
return fmt.Errorf("cannot set flag %s: %v", 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: %v", p, err)
}
}
return nil
}

View File

@@ -0,0 +1,186 @@
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
allowRepeatedFieldsInBodyV bool
includePackageInTagsV bool
fileV string
importPathV string
mergeFileNameV string
useFQNForOpenAPINameV bool
}{
{
// 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, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false,
fileV: "-", importPathV: "", mergeFileNameV: "apidocs",
},
{
name: "Test 1",
expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/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/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api",
allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true,
fileV: "./foo.pb", importPathV: "/bar/baz", mergeFileNameV: "apidocs",
},
{
name: "Test 2",
expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/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/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api",
allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false,
fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs",
},
{
name: "Test 4",
expected: map[string]string{},
request: "",
allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: false, 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, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: 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, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: true,
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.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i)
clearFlags()
})
}
}
func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePackageInTagsV bool, useFQNForOpenAPINameV bool, 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 *allowRepeatedFieldsInBody != allowRepeatedFieldsInBodyV {
t.Errorf("Test %v: allow_repeated_fields_in_body misparsed, expected '%v', got '%v'", tid, allowRepeatedFieldsInBodyV, *allowRepeatedFieldsInBody)
}
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)
}
}
func clearFlags() {
*importPrefix = ""
*file = "stdin"
*allowDeleteBody = false
*allowMerge = false
*allowRepeatedFieldsInBody = false
*includePackageInTags = false
*mergeFileName = "apidocs"
}

View File

@@ -0,0 +1,38 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
package(default_visibility = ["//visibility:public"])
filegroup(
name = "options_proto_files",
srcs = [
"annotations.proto",
"openapiv2.proto",
],
)
go_library(
name = "go_default_library",
embed = [":options_go_proto"],
importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options",
)
proto_library(
name = "options_proto",
srcs = [
"annotations.proto",
"openapiv2.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-openapiv2/options",
proto = ":options_proto",
)

View File

@@ -0,0 +1,241 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.0
// source: protoc-gen-openapiv2/options/annotations.proto
package options
import (
proto "github.com/golang/protobuf/proto"
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
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)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
var file_protoc_gen_openapiv2_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{
{
ExtendedType: (*descriptor.FileOptions)(nil),
ExtensionType: (*Swagger)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger",
Tag: "bytes,1042,opt,name=openapiv2_swagger",
Filename: "protoc-gen-openapiv2/options/annotations.proto",
},
{
ExtendedType: (*descriptor.MethodOptions)(nil),
ExtensionType: (*Operation)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation",
Tag: "bytes,1042,opt,name=openapiv2_operation",
Filename: "protoc-gen-openapiv2/options/annotations.proto",
},
{
ExtendedType: (*descriptor.MessageOptions)(nil),
ExtensionType: (*Schema)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema",
Tag: "bytes,1042,opt,name=openapiv2_schema",
Filename: "protoc-gen-openapiv2/options/annotations.proto",
},
{
ExtendedType: (*descriptor.ServiceOptions)(nil),
ExtensionType: (*Tag)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag",
Tag: "bytes,1042,opt,name=openapiv2_tag",
Filename: "protoc-gen-openapiv2/options/annotations.proto",
},
{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*JSONSchema)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field",
Tag: "bytes,1042,opt,name=openapiv2_field",
Filename: "protoc-gen-openapiv2/options/annotations.proto",
},
}
// Extension fields to descriptor.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_openapiv2.options.Swagger openapiv2_swagger = 1042;
E_Openapiv2Swagger = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[0]
)
// Extension fields to descriptor.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_openapiv2.options.Operation openapiv2_operation = 1042;
E_Openapiv2Operation = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[1]
)
// Extension fields to descriptor.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_openapiv2.options.Schema openapiv2_schema = 1042;
E_Openapiv2Schema = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[2]
)
// Extension fields to descriptor.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_openapiv2.options.Tag openapiv2_tag = 1042;
E_Openapiv2Tag = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[3]
)
// Extension fields to descriptor.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_openapiv2.options.JSONSchema openapiv2_field = 1042;
E_Openapiv2Field = &file_protoc_gen_openapiv2_options_annotations_proto_extTypes[4]
)
var File_protoc_gen_openapiv2_options_annotations_proto protoreflect.FileDescriptor
var file_protoc_gen_openapiv2_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, 0x32, 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, 0x32, 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, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
0x61, 0x70, 0x69, 0x76, 0x32, 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, 0x92,
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, 0x32, 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, 0x92, 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, 0x32, 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, 0x92, 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, 0x32, 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, 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, 0x92, 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,
0x32, 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, 0x92, 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, 0x32, 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, 0x32, 0x2f, 0x6f, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_protoc_gen_openapiv2_options_annotations_proto_goTypes = []interface{}{
(*descriptor.FileOptions)(nil), // 0: google.protobuf.FileOptions
(*descriptor.MethodOptions)(nil), // 1: google.protobuf.MethodOptions
(*descriptor.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
(*descriptor.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions
(*descriptor.FieldOptions)(nil), // 4: google.protobuf.FieldOptions
(*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger
(*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation
(*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema
(*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag
(*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema
}
var file_protoc_gen_openapiv2_options_annotations_proto_depIdxs = []int32{
0, // 0: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions
1, // 1: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:extendee -> google.protobuf.MethodOptions
2, // 2: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:extendee -> google.protobuf.MessageOptions
3, // 3: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:extendee -> google.protobuf.ServiceOptions
4, // 4: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:extendee -> google.protobuf.FieldOptions
5, // 5: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger
6, // 6: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation
7, // 7: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema
8, // 8: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Tag
9, // 9: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
5, // [5:10] is the sub-list for extension type_name
0, // [0:5] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_protoc_gen_openapiv2_options_annotations_proto_init() }
func file_protoc_gen_openapiv2_options_annotations_proto_init() {
if File_protoc_gen_openapiv2_options_annotations_proto != nil {
return
}
file_protoc_gen_openapiv2_options_openapiv2_proto_init()
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_protoc_gen_openapiv2_options_annotations_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 5,
NumServices: 0,
},
GoTypes: file_protoc_gen_openapiv2_options_annotations_proto_goTypes,
DependencyIndexes: file_protoc_gen_openapiv2_options_annotations_proto_depIdxs,
ExtensionInfos: file_protoc_gen_openapiv2_options_annotations_proto_extTypes,
}.Build()
File_protoc_gen_openapiv2_options_annotations_proto = out.File
file_protoc_gen_openapiv2_options_annotations_proto_rawDesc = nil
file_protoc_gen_openapiv2_options_annotations_proto_goTypes = nil
file_protoc_gen_openapiv2_options_annotations_proto_depIdxs = nil
}

View File

@@ -1,42 +1,42 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_swagger.options;
package grpc.gateway.protoc_gen_openapiv2.options;
option go_package = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options";
option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
import "google/protobuf/descriptor.proto";
import "protoc-gen-swagger/options/openapiv2.proto";
import "protoc-gen-openapiv2/options/openapiv2.proto";
extend google.protobuf.FileOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
// 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 = 1042;
}
extend google.protobuf.MethodOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
// 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 = 1042;
}
extend google.protobuf.MessageOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
// 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 = 1042;
}
extend google.protobuf.ServiceOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
// 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 = 1042;
}
extend google.protobuf.FieldOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
// 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.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,645 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_openapiv2.options;
option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
import "google/protobuf/struct.proto";
// 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/master/LICENSE.txt";
// };
// };
// 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<string, Response> 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;
// field 13 is reserved for 'tags', which are supposed to be exposed as and
// customizable as proto services. TODO(ivucica): add processing of proto
// service objects into OpenAPI v2 Tag objects.
reserved 13;
// Additional external documentation.
ExternalDocumentation external_docs = 14;
map<string, google.protobuf.Value> 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<string, Response> 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;
map<string, google.protobuf.Value> extensions = 13;
}
// `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<string, Header> 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<string, string> examples = 4;
map<string, google.protobuf.Value> 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/master/LICENSE.txt";
// };
// };
// ...
// };
//
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;
map<string, google.protobuf.Value> 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/master/LICENSE.txt";
// };
// ...
// };
// ...
// };
//
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;
}
// `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;
}
// `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 {
// field 1 is reserved for 'name'. In our generator, this is (to be) extracted
// from the name of proto service, and thus not exposed to the user, as
// changing tag object's name would break the link to the references to the
// tag in individual operation specifications.
//
// TODO(ivucica): Add 'name' property. Use it to allow override of the name of
// global Tag object, then use that name to reference the tag throughout the
// OpenAPI file.
reserved 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;
}
// `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<string, SecurityScheme> 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;
map<string, google.protobuf.Value> 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<string, SecurityRequirementValue> 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<string, string> scope = 1;
}

View File

@@ -1,380 +0,0 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_swagger.options;
option go_package = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options";
import "google/protobuf/any.proto";
import "google/protobuf/struct.proto";
// `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
//
// TODO(ivucica): document fields
message Swagger {
string swagger = 1;
Info info = 2;
string host = 3;
// `base_path` is the common prefix path used on all API endpoints (ie. /api, /v1, etc.). By adding this,
// it allows you to remove this portion from the path endpoints in your Swagger file making them easier
// to read. Note that using `base_path` does not change the endpoint paths that are generated in the resulting
// Swagger file. If you wish to use `base_path` with relatively generated Swagger 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;
enum SwaggerScheme {
UNKNOWN = 0;
HTTP = 1;
HTTPS = 2;
WS = 3;
WSS = 4;
}
repeated SwaggerScheme schemes = 5;
repeated string consumes = 6;
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;
map<string, Response> responses = 10;
SecurityDefinitions security_definitions = 11;
repeated SecurityRequirement security = 12;
// field 13 is reserved for 'tags', which are supposed to be exposed as and
// customizable as proto services. TODO(ivucica): add processing of proto
// service objects into OpenAPI v2 Tag objects.
reserved 13;
ExternalDocumentation external_docs = 14;
map<string, google.protobuf.Value> 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
//
// TODO(ivucica): document fields
message Operation {
repeated string tags = 1;
string summary = 2;
string description = 3;
ExternalDocumentation external_docs = 4;
string operation_id = 5;
repeated string consumes = 6;
repeated string produces = 7;
// field 8 is reserved for 'parameters'.
reserved 8;
map<string, Response> responses = 9;
repeated string schemes = 10;
bool deprecated = 11;
repeated SecurityRequirement security = 12;
map<string, google.protobuf.Value> extensions = 13;
}
// `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;
// field 3 is reserved for 'headers'.
reserved 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<string, string> examples = 4;
map<string, google.protobuf.Value> 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
//
// TODO(ivucica): document fields
message Info {
string title = 1;
string description = 2;
string terms_of_service = 3;
Contact contact = 4;
License license = 5;
string version = 6;
map<string, google.protobuf.Value> 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
//
// TODO(ivucica): document fields
message Contact {
string name = 1;
string url = 2;
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
//
message License {
// Required. The license name used for the API.
string name = 1;
// A URL to the license used for the API.
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
//
// TODO(ivucica): document fields
message ExternalDocumentation {
string description = 1;
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
//
// TODO(ivucica): document fields
message Schema {
JSONSchema json_schema = 1;
string discriminator = 2;
bool read_only = 3;
// field 4 is reserved for 'xml'.
reserved 4;
ExternalDocumentation external_docs = 5;
google.protobuf.Any example = 6;
}
// `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
//
// TODO(ivucica): document fields
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;
string title = 5;
string description = 6;
string default = 7;
bool read_only = 8;
// field 9 is reserved for 'examples', which is omitted from OpenAPI v2 in favor of 'example' field.
reserved 9;
double multiple_of = 10;
double maximum = 11;
bool exclusive_maximum = 12;
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;
// following fields are reserved, as the properties have been omitted from OpenAPI v2:
// format, contentMediaType, contentEncoding, if, then, else
reserved 36 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;
}
// `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
//
// TODO(ivucica): document fields
message Tag {
// field 1 is reserved for 'name'. In our generator, this is (to be) extracted
// from the name of proto service, and thus not exposed to the user, as
// changing tag object's name would break the link to the references to the
// tag in individual operation specifications.
//
// TODO(ivucica): Add 'name' property. Use it to allow override of the name of
// global Tag object, then use that name to reference the tag throughout the
// Swagger file.
reserved 1;
// TODO(ivucica): Description should be extracted from comments on the proto
// service object.
string description = 2;
ExternalDocumentation external_docs = 3;
}
// `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<string, SecurityScheme> 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 {
// Required. 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;
}
// Required. The location of the API key. Valid values are "query" or "header".
enum In {
IN_INVALID = 0;
IN_QUERY = 1;
IN_HEADER = 2;
}
// Required. 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;
}
// Required. 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;
// Required. The name of the header or query parameter to be used.
//
// Valid for apiKey.
string name = 3;
// Required. The location of the API key. Valid values are "query" or "header".
//
// Valid for apiKey.
In in = 4;
// Required. The flow used by the OAuth2 security scheme. Valid values are
// "implicit", "password", "application" or "accessCode".
//
// Valid for oauth2.
Flow flow = 5;
// Required. 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;
// Required. 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;
// Required. The available scopes for the OAuth2 security scheme.
//
// Valid for oauth2.
Scopes scopes = 8;
map<string, google.protobuf.Value> 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<string, SecurityRequirementValue> 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<string, string> scope = 1;
}

25
main.go
View File

@@ -8,7 +8,7 @@ import (
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/jmoiron/sqlx"
"github.com/onepanelio/core/api"
migrations "github.com/onepanelio/core/db/go"
@@ -171,17 +171,18 @@ func startHTTPProxy() {
opts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(math.MaxInt64),
grpc.MaxCallRecvMsgSize(math.MaxInt64))}
registerHandler(api.RegisterWorkflowTemplateServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterWorkflowServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterCronWorkflowServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterSecretServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterNamespaceServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterAuthServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterLabelServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterWorkspaceTemplateServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterWorkspaceServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterConfigServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
registerHandler(api.RegisterServiceServiceHandlerFromEndpoint, ctx, mux, endpoint, opts)
api.RegisterWorkflowTemplateServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterWorkflowTemplateServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterWorkflowServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterCronWorkflowServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterSecretServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterNamespaceServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterAuthServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterLabelServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterWorkspaceTemplateServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterWorkspaceServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterConfigServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
api.RegisterServiceServiceHandlerFromEndpoint(ctx, mux, endpoint, opts)
log.Printf("Starting HTTP proxy on port %v", *httpPort)

View File

@@ -14,6 +14,7 @@ import (
// AuthServer contains logic for checking Authorization of resources in the system
type AuthServer struct {
api.UnimplementedAuthServiceServer
}
// NewAuthServer creates a new AuthServer

View File

@@ -8,7 +8,9 @@ import (
)
// ConfigServer contains actions for system configuration related items
type ConfigServer struct{}
type ConfigServer struct {
api.UnimplementedConfigServiceServer
}
// NewConfigServer creates a new ConfigServer
func NewConfigServer() *ConfigServer {

View File

@@ -11,7 +11,9 @@ import (
"github.com/onepanelio/core/server/converter"
)
type CronWorkflowServer struct{}
type CronWorkflowServer struct {
api.UnimplementedCronWorkflowServiceServer
}
func NewCronWorkflowServer() *CronWorkflowServer {
return &CronWorkflowServer{}

View File

@@ -49,7 +49,9 @@ func mapKeyValuesToMap(keyValues []*api.KeyValue) map[string]string {
return result
}
type LabelServer struct{}
type LabelServer struct {
api.UnimplementedLabelServiceServer
}
func NewLabelServer() *LabelServer {
return &LabelServer{}

View File

@@ -10,7 +10,9 @@ import (
"github.com/onepanelio/core/server/auth"
)
type NamespaceServer struct{}
type NamespaceServer struct {
api.UnimplementedNamespaceServiceServer
}
func NewNamespaceServer() *NamespaceServer {
return &NamespaceServer{}

View File

@@ -9,7 +9,9 @@ import (
"github.com/onepanelio/core/server/auth"
)
type SecretServer struct{}
type SecretServer struct {
api.UnimplementedSecretServiceServer
}
func NewSecretServer() *SecretServer {
return &SecretServer{}

View File

@@ -8,7 +8,9 @@ import (
)
// ServiceServer contains actions for installed services
type ServiceServer struct{}
type ServiceServer struct {
api.UnimplementedServiceServiceServer
}
// NewServiceServer creates a new ServiceServer
func NewServiceServer() *ServiceServer {

View File

@@ -9,6 +9,7 @@ import (
"github.com/onepanelio/core/pkg/util/request/pagination"
"github.com/onepanelio/core/pkg/util/router"
"github.com/onepanelio/core/server/converter"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sort"
@@ -24,7 +25,9 @@ import (
requestSort "github.com/onepanelio/core/pkg/util/request/sort"
)
type WorkflowServer struct{}
type WorkflowServer struct {
api.UnimplementedWorkflowServiceServer
}
func NewWorkflowServer() *WorkflowServer {
return &WorkflowServer{}
@@ -217,6 +220,7 @@ func (s *WorkflowServer) WatchWorkflowExecution(req *api.WatchWorkflowExecutionR
}
wf.Namespace = req.Namespace
if err := stream.Send(apiWorkflowExecution(wf, webRouter)); err != nil {
log.Printf("Stream Send failed: %v\n", err)
return err
}
}

View File

@@ -11,7 +11,9 @@ import (
"github.com/onepanelio/core/server/converter"
)
type WorkflowTemplateServer struct{}
type WorkflowTemplateServer struct {
api.UnimplementedWorkflowTemplateServiceServer
}
func NewWorkflowTemplateServer() *WorkflowTemplateServer {
return &WorkflowTemplateServer{}

View File

@@ -21,7 +21,9 @@ var reservedWorkspaceNames = map[string]bool{
"modeldb": true,
}
type WorkspaceServer struct{}
type WorkspaceServer struct {
api.UnimplementedWorkspaceServiceServer
}
func apiWorkspace(wt *v1.Workspace, config v1.SystemConfig) *api.Workspace {
protocol := config.APIProtocol()

View File

@@ -14,7 +14,9 @@ import (
"time"
)
type WorkspaceTemplateServer struct{}
type WorkspaceTemplateServer struct {
api.UnimplementedWorkspaceTemplateServiceServer
}
func apiWorkspaceTemplate(wt *v1.WorkspaceTemplate) *api.WorkspaceTemplate {
res := &api.WorkspaceTemplate{