refactor: openpitrix module

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-09-25 14:07:15 +08:00
parent d0dc66cf28
commit 1b5681c12b
314 changed files with 72092 additions and 25762 deletions

View File

@@ -0,0 +1,202 @@
# Created by .ignore support plugin (hsz.mobi)
### Go template
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
### Windows template
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Kate template
# Swap Files #
.*.kate-swp
.swp.*
### SublimeText template
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# workspace files are user-specific
*.sublime-workspace
# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project
# sftp configuration file
sftp-config.json
### Linux template
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Xcode template
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
### Eclipse template
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
coverage.txt
#vendor
vendor/

View File

@@ -0,0 +1,22 @@
sudo: false
language: go
go:
- 1.8.x
env:
- DEP_VERSION="0.3.2"
before_install:
# Download the binary to bin folder in $GOPATH
- curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep
# Make the binary executable
- chmod +x $GOPATH/bin/dep
install:
- dep ensure
script:
- make checkdocs
- make test
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@@ -0,0 +1,20 @@
# Contributing
We would love to have people submit pull requests and help make `grpc-ecosystem/go-grpc-middleware` even better 👍.
Fork, then clone the repo:
```bash
git clone git@github.com:your-username/go-grpc-middleware.git
```
Before checking in please run the following:
```bash
make all
```
This will `vet`, `fmt`, regenerate documentation and run all tests.
Push to your fork and open a pull request.

View File

@@ -0,0 +1,166 @@
# grpc_middleware
`import "github.com/grpc-ecosystem/go-grpc-middleware"`
* [Overview](#pkg-overview)
* [Imported Packages](#pkg-imports)
* [Index](#pkg-index)
## <a name="pkg-overview">Overview</a>
`grpc_middleware` is a collection of gRPC middleware packages: interceptors, helpers and tools.
### Middleware
gRPC is a fantastic RPC middleware, which sees a lot of adoption in the Golang world. However, the
upstream gRPC codebase is relatively bare bones.
This package, and most of its child packages provides commonly needed middleware for gRPC:
client-side interceptors for retires, server-side interceptors for input validation and auth,
functions for chaining said interceptors, metadata convenience methods and more.
### Chaining
By default, gRPC doesn't allow one to have more than one interceptor either on the client nor on
the server side. `grpc_middleware` provides convenient chaining methods
Simple way of turning a multiple interceptors into a single interceptor. Here's an example for
server chaining:
myServer := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(loggingStream, monitoringStream, authStream)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(loggingUnary, monitoringUnary, authUnary),
)
These interceptors will be executed from left to right: logging, monitoring and auth.
Here's an example for client side chaining:
clientConn, err = grpc.Dial(
address,
grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(monitoringClientUnary, retryUnary)),
grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(monitoringClientStream, retryStream)),
)
client = pb_testproto.NewTestServiceClient(clientConn)
resp, err := client.PingEmpty(s.ctx, &myservice.Request{Msg: "hello"})
These interceptors will be executed from left to right: monitoring and then retry logic.
The retry interceptor will call every interceptor that follows it whenever when a retry happens.
### Writing Your Own
Implementing your own interceptor is pretty trivial: there are interfaces for that. But the interesting
bit exposing common data to handlers (and other middleware), similarly to HTTP Middleware design.
For example, you may want to pass the identity of the caller from the auth interceptor all the way
to the handling function.
For example, a client side interceptor example for auth looks like:
func FakeAuthUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
newCtx := context.WithValue(ctx, "user_id", "john@example.com")
return handler(newCtx, req)
}
Unfortunately, it's not as easy for streaming RPCs. These have the `context.Context` embedded within
the `grpc.ServerStream` object. To pass values through context, a wrapper (`WrappedServerStream`) is
needed. For example:
func FakeAuthStreamingInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
newStream := grpc_middleware.WrapServerStream(stream)
newStream.WrappedContext = context.WithValue(ctx, "user_id", "john@example.com")
return handler(srv, stream)
}
## <a name="pkg-imports">Imported Packages</a>
- [golang.org/x/net/context](https://godoc.org/golang.org/x/net/context)
- [google.golang.org/grpc](https://godoc.org/google.golang.org/grpc)
## <a name="pkg-index">Index</a>
* [func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor](#ChainStreamClient)
* [func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor](#ChainStreamServer)
* [func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor](#ChainUnaryClient)
* [func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor](#ChainUnaryServer)
* [func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption](#WithStreamServerChain)
* [func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption](#WithUnaryServerChain)
* [type WrappedServerStream](#WrappedServerStream)
* [func WrapServerStream(stream grpc.ServerStream) \*WrappedServerStream](#WrapServerStream)
* [func (w \*WrappedServerStream) Context() context.Context](#WrappedServerStream.Context)
#### <a name="pkg-files">Package files</a>
[chain.go](./chain.go) [doc.go](./doc.go) [wrappers.go](./wrappers.go)
## <a name="ChainStreamClient">func</a> [ChainStreamClient](./chain.go#L136)
``` go
func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor
```
ChainStreamClient creates a single interceptor out of a chain of many interceptors.
Execution is done in left-to-right order, including passing of context.
For example ChainStreamClient(one, two, three) will execute one before two before three.
## <a name="ChainStreamServer">func</a> [ChainStreamServer](./chain.go#L58)
``` go
func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor
```
ChainStreamServer creates a single interceptor out of a chain of many interceptors.
Execution is done in left-to-right order, including passing of context.
For example ChainUnaryServer(one, two, three) will execute one before two before three.
If you want to pass context between interceptors, use WrapServerStream.
## <a name="ChainUnaryClient">func</a> [ChainUnaryClient](./chain.go#L97)
``` go
func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor
```
ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
Execution is done in left-to-right order, including passing of context.
For example ChainUnaryClient(one, two, three) will execute one before two before three.
## <a name="ChainUnaryServer">func</a> [ChainUnaryServer](./chain.go#L18)
``` go
func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor
```
ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
Execution is done in left-to-right order, including passing of context.
For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
will see context changes of one and two.
## <a name="WithStreamServerChain">func</a> [WithStreamServerChain](./chain.go#L181)
``` go
func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption
```
WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
Basically syntactic sugar.
## <a name="WithUnaryServerChain">func</a> [WithUnaryServerChain](./chain.go#L175)
``` go
func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption
```
Chain creates a single interceptor out of a chain of many interceptors.
WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
Basically syntactic sugar.
## <a name="WrappedServerStream">type</a> [WrappedServerStream](./wrappers.go#L12-L16)
``` go
type WrappedServerStream struct {
grpc.ServerStream
// WrappedContext is the wrapper's own Context. You can assign it.
WrappedContext context.Context
}
```
WrappedServerStream is a thin wrapper around grpc.ServerStream that allows modifying context.
### <a name="WrapServerStream">func</a> [WrapServerStream](./wrappers.go#L24)
``` go
func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream
```
WrapServerStream returns a ServerStream that has the ability to overwrite context.
### <a name="WrappedServerStream.Context">func</a> (\*WrappedServerStream) [Context](./wrappers.go#L19)
``` go
func (w *WrappedServerStream) Context() context.Context
```
Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
- - -
Generated by [godoc2ghmd](https://github.com/GandalfUK/godoc2ghmd)

View File

@@ -0,0 +1,123 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "cloud.google.com/go"
packages = ["compute/metadata"]
revision = "2d3a6656c17a60b0815b7e06ab0be04eacb6e613"
version = "v0.16.0"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/gogo/protobuf"
packages = ["gogoproto","proto","protoc-gen-gogo/descriptor"]
revision = "342cbe0a04158f6dcb03ca0079991a51a4248c02"
version = "v0.5"
[[projects]]
branch = "master"
name = "github.com/golang/protobuf"
packages = ["jsonpb","proto","ptypes","ptypes/any","ptypes/duration","ptypes/struct","ptypes/timestamp"]
revision = "1e59b77b52bf8e4b449a57e6f79f21226d571845"
[[projects]]
name = "github.com/opentracing/opentracing-go"
packages = [".","ext","log","mocktracer"]
revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38"
version = "v1.0.2"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e"
version = "v1.0.3"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert","require","suite"]
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
version = "v1.1.4"
[[projects]]
name = "go.uber.org/atomic"
packages = ["."]
revision = "8474b86a5a6f79c443ce4b2992817ff32cf208b8"
version = "v1.3.1"
[[projects]]
name = "go.uber.org/multierr"
packages = ["."]
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0"
[[projects]]
name = "go.uber.org/zap"
packages = [".","buffer","internal/bufferpool","internal/color","internal/exit","zapcore"]
revision = "35aad584952c3e7020db7b839f6b102de6271f89"
version = "v1.7.1"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "94eea52f7b742c7cbe0b03b22f0c4c8631ece122"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["context","context/ctxhttp","http2","http2/hpack","idna","internal/timeseries","lex/httplex","trace"]
revision = "a8b9294777976932365dabb6640cf1468d95c70f"
[[projects]]
branch = "master"
name = "golang.org/x/oauth2"
packages = [".","google","internal","jws","jwt"]
revision = "f95fa95eaa936d9d87489b15d1d18b97c1ba9c28"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix","windows"]
revision = "13fcbd661c8ececa8807a29b48407d674b1d8ed8"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
revision = "75cc3cad82b5f47d3fb229ddda8c5167da14f294"
[[projects]]
name = "google.golang.org/appengine"
packages = [".","internal","internal/app_identity","internal/base","internal/datastore","internal/log","internal/modules","internal/remote_api","internal/urlfetch","urlfetch"]
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "7f0da29060c682909f650ad8ed4e515bd74fa12a"
[[projects]]
name = "google.golang.org/grpc"
packages = [".","balancer","balancer/roundrobin","codes","connectivity","credentials","credentials/oauth","encoding","grpclb/grpc_lb_v1/messages","grpclog","internal","keepalive","metadata","naming","peer","resolver","resolver/dns","resolver/passthrough","stats","status","tap","transport"]
revision = "5a9f7b402fe85096d2e1d0383435ee1876e863d0"
version = "v1.8.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "b24c6670412eb0bc44ed1db77fecc52333f8725f3e3272bdc568f5683a63031f"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -0,0 +1,35 @@
[[constraint]]
name = "github.com/gogo/protobuf"
version = "0.5.0"
[[constraint]]
branch = "master"
name = "github.com/golang/protobuf"
[[constraint]]
name = "github.com/opentracing/opentracing-go"
version = "1.0.2"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.3"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.1.4"
[[constraint]]
name = "go.uber.org/zap"
version = "1.7.1"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/oauth2"
[[constraint]]
name = "google.golang.org/grpc"
version = "1.8.0"

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -0,0 +1,86 @@
# Go gRPC Middleware
[![Travis Build](https://travis-ci.org/grpc-ecosystem/go-grpc-middleware.svg?branch=master)](https://travis-ci.org/grpc-ecosystem/go-grpc-middleware)
[![Go Report Card](https://goreportcard.com/badge/github.com/grpc-ecosystem/go-grpc-middleware)](https://goreportcard.com/report/github.com/grpc-ecosystem/go-grpc-middleware)
[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/grpc-ecosystem/go-grpc-middleware)
[![SourceGraph](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-middleware/-/badge.svg)](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-middleware/?badge)
[![codecov](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware/branch/master/graph/badge.svg)](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware)
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![quality: production](https://img.shields.io/badge/quality-production-orange.svg)](#status)
[![Slack](slack.png)](https://join.slack.com/t/improbable-eng/shared_invite/enQtMzQ1ODcyMzQ5MjM4LWY5ZWZmNGM2ODc5MmViNmQ3ZTA3ZTY3NzQwOTBlMTkzZmIxZTIxODk0OWU3YjZhNWVlNDU3MDlkZGViZjhkMjc)
[gRPC Go](https://github.com/grpc/grpc-go) Middleware: interceptors, helpers, utilities.
**Important** The repo recently moved to `github.com/grpc-ecosystem/go-grpc-middleware`, please update your import paths.
## Middleware
[gRPC Go](https://github.com/grpc/grpc-go) recently acquired support for
Interceptors, i.e. [middleware](https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.gv7tdlghs)
that is executed either on the gRPC Server before the request is passed onto the user's application logic, or on the gRPC client either around the user call. It is a perfect way to implement
common patterns: auth, logging, message, validation, retries or monitoring.
These are generic building blocks that make it easy to build multiple microservices easily.
The purpose of this repository is to act as a go-to point for such reusable functionality. It contains
some of them itself, but also will link to useful external repos.
`grpc_middleware` itself provides support for chaining interceptors. See [Documentation](DOC.md), but here's an example:
```go
import "github.com/grpc-ecosystem/go-grpc-middleware"
myServer := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
grpc_opentracing.StreamServerInterceptor(),
grpc_prometheus.StreamServerInterceptor,
grpc_zap.StreamServerInterceptor(zapLogger),
grpc_auth.StreamServerInterceptor(myAuthFunction),
grpc_recovery.StreamServerInterceptor(),
)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_ctxtags.UnaryServerInterceptor(),
grpc_opentracing.UnaryServerInterceptor(),
grpc_prometheus.UnaryServerInterceptor,
grpc_zap.UnaryServerInterceptor(zapLogger),
grpc_auth.UnaryServerInterceptor(myAuthFunction),
grpc_recovery.UnaryServerInterceptor(),
)),
)
```
## Interceptors
*Please send a PR to add new interceptors or middleware to this list*
#### Auth
* [`grpc_auth`](auth) - a customizable (via `AuthFunc`) piece of auth middleware
#### Logging
* [`grpc_ctxtags`](tags/) - a library that adds a `Tag` map to context, with data populated from request body
* [`grpc_zap`](logging/zap/) - integration of [zap](https://github.com/uber-go/zap) logging library into gRPC handlers.
* [`grpc_logrus`](logging/logrus/) - integration of [logrus](https://github.com/sirupsen/logrus) logging library into gRPC handlers.
#### Monitoring
* [`grpc_prometheus`⚡](https://github.com/grpc-ecosystem/go-grpc-prometheus) - Prometheus client-side and server-side monitoring middleware
* [`otgrpc`⚡](https://github.com/grpc-ecosystem/grpc-opentracing/tree/master/go/otgrpc) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors
* [`grpc_opentracing`](tracing/opentracing) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors with support for streaming and handler-returned tags
#### Client
* [`grpc_retry`](retry/) - a generic gRPC response code retry mechanism, client-side middleware
#### Server
* [`grpc_validator`](validator/) - codegen inbound message validation from `.proto` options
* [`grpc_recovery`](recovery/) - turn panics into gRPC errors
## Status
This code has been running in *production* since May 2016 as the basis of the gRPC micro services stack at [Improbable](https://improbable.io).
Additional tooling will be added, and contributions are welcome.
## License
`go-grpc-middleware` is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.

View File

@@ -0,0 +1,183 @@
// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
// gRPC Server Interceptor chaining middleware.
package grpc_middleware
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
//
// Execution is done in left-to-right order, including passing of context.
// For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
// will see context changes of one and two.
func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
n := len(interceptors)
if n > 1 {
lastI := n - 1
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
var (
chainHandler grpc.UnaryHandler
curI int
)
chainHandler = func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
if curI == lastI {
return handler(currentCtx, currentReq)
}
curI++
resp, err := interceptors[curI](currentCtx, currentReq, info, chainHandler)
curI--
return resp, err
}
return interceptors[0](ctx, req, info, chainHandler)
}
}
if n == 1 {
return interceptors[0]
}
// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
return handler(ctx, req)
}
}
// ChainStreamServer creates a single interceptor out of a chain of many interceptors.
//
// Execution is done in left-to-right order, including passing of context.
// For example ChainUnaryServer(one, two, three) will execute one before two before three.
// If you want to pass context between interceptors, use WrapServerStream.
func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
n := len(interceptors)
if n > 1 {
lastI := n - 1
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
var (
chainHandler grpc.StreamHandler
curI int
)
chainHandler = func(currentSrv interface{}, currentStream grpc.ServerStream) error {
if curI == lastI {
return handler(currentSrv, currentStream)
}
curI++
err := interceptors[curI](currentSrv, currentStream, info, chainHandler)
curI--
return err
}
return interceptors[0](srv, stream, info, chainHandler)
}
}
if n == 1 {
return interceptors[0]
}
// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
return func(srv interface{}, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
return handler(srv, stream)
}
}
// ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
//
// Execution is done in left-to-right order, including passing of context.
// For example ChainUnaryClient(one, two, three) will execute one before two before three.
func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
n := len(interceptors)
if n > 1 {
lastI := n - 1
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
var (
chainHandler grpc.UnaryInvoker
curI int
)
chainHandler = func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
if curI == lastI {
return invoker(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentOpts...)
}
curI++
err := interceptors[curI](currentCtx, currentMethod, currentReq, currentRepl, currentConn, chainHandler, currentOpts...)
curI--
return err
}
return interceptors[0](ctx, method, req, reply, cc, chainHandler, opts...)
}
}
if n == 1 {
return interceptors[0]
}
// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
return invoker(ctx, method, req, reply, cc, opts...)
}
}
// ChainStreamClient creates a single interceptor out of a chain of many interceptors.
//
// Execution is done in left-to-right order, including passing of context.
// For example ChainStreamClient(one, two, three) will execute one before two before three.
func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
n := len(interceptors)
if n > 1 {
lastI := n - 1
return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
var (
chainHandler grpc.Streamer
curI int
)
chainHandler = func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
if curI == lastI {
return streamer(currentCtx, currentDesc, currentConn, currentMethod, currentOpts...)
}
curI++
stream, err := interceptors[curI](currentCtx, currentDesc, currentConn, currentMethod, chainHandler, currentOpts...)
curI--
return stream, err
}
return interceptors[0](ctx, desc, cc, method, chainHandler, opts...)
}
}
if n == 1 {
return interceptors[0]
}
// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
return streamer(ctx, desc, cc, method, opts...)
}
}
// Chain creates a single interceptor out of a chain of many interceptors.
//
// WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
// Basically syntactic sugar.
func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...))
}
// WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
// Basically syntactic sugar.
func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
return grpc.StreamInterceptor(ChainStreamServer(interceptors...))
}

View File

@@ -0,0 +1,69 @@
// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
/*
`grpc_middleware` is a collection of gRPC middleware packages: interceptors, helpers and tools.
Middleware
gRPC is a fantastic RPC middleware, which sees a lot of adoption in the Golang world. However, the
upstream gRPC codebase is relatively bare bones.
This package, and most of its child packages provides commonly needed middleware for gRPC:
client-side interceptors for retires, server-side interceptors for input validation and auth,
functions for chaining said interceptors, metadata convenience methods and more.
Chaining
By default, gRPC doesn't allow one to have more than one interceptor either on the client nor on
the server side. `grpc_middleware` provides convenient chaining methods
Simple way of turning a multiple interceptors into a single interceptor. Here's an example for
server chaining:
myServer := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(loggingStream, monitoringStream, authStream)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(loggingUnary, monitoringUnary, authUnary),
)
These interceptors will be executed from left to right: logging, monitoring and auth.
Here's an example for client side chaining:
clientConn, err = grpc.Dial(
address,
grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(monitoringClientUnary, retryUnary)),
grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(monitoringClientStream, retryStream)),
)
client = pb_testproto.NewTestServiceClient(clientConn)
resp, err := client.PingEmpty(s.ctx, &myservice.Request{Msg: "hello"})
These interceptors will be executed from left to right: monitoring and then retry logic.
The retry interceptor will call every interceptor that follows it whenever when a retry happens.
Writing Your Own
Implementing your own interceptor is pretty trivial: there are interfaces for that. But the interesting
bit exposing common data to handlers (and other middleware), similarly to HTTP Middleware design.
For example, you may want to pass the identity of the caller from the auth interceptor all the way
to the handling function.
For example, a client side interceptor example for auth looks like:
func FakeAuthUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
newCtx := context.WithValue(ctx, "user_id", "john@example.com")
return handler(newCtx, req)
}
Unfortunately, it's not as easy for streaming RPCs. These have the `context.Context` embedded within
the `grpc.ServerStream` object. To pass values through context, a wrapper (`WrappedServerStream`) is
needed. For example:
func FakeAuthStreamingInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
newStream := grpc_middleware.WrapServerStream(stream)
newStream.WrappedContext = context.WithValue(ctx, "user_id", "john@example.com")
return handler(srv, stream)
}
*/
package grpc_middleware

View File

@@ -0,0 +1,22 @@
SHELL="/bin/bash"
GOFILES_NOVENDOR = $(shell go list ./... | grep -v /vendor/)
all: vet fmt docs test
docs:
./scripts/docs.sh generate
checkdocs:
./scripts/docs.sh check
fmt:
go fmt $(GOFILES_NOVENDOR)
vet:
go vet $(GOFILES_NOVENDOR)
test: vet
./scripts/test_all.sh
.PHONY: all docs validate test

View File

@@ -0,0 +1,107 @@
# grpc_recovery
`import "github.com/grpc-ecosystem/go-grpc-middleware/recovery"`
* [Overview](#pkg-overview)
* [Imported Packages](#pkg-imports)
* [Index](#pkg-index)
* [Examples](#pkg-examples)
## <a name="pkg-overview">Overview</a>
`grpc_recovery` are intereceptors that recover from gRPC handler panics.
### Server Side Recovery Middleware
By default a panic will be converted into a gRPC error with `code.Internal`.
Handling can be customised by providing an alternate recovery function.
Please see examples for simple examples of use.
#### Example:
<details>
<summary>Click to expand code.</summary>
```go
package grpc_recovery_test
import (
"github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"google.golang.org/grpc"
)
var (
customFunc grpc_recovery.RecoveryHandlerFunc
)
// Initialization shows an initialization sequence with a custom recovery handler func.
func Example_initialization() {
// Shared options for the logger, with a custom gRPC code to log level function.
opts := []grpc_recovery.Option{
grpc_recovery.WithRecoveryHandler(customFunc),
}
// Create a server. Recovery handlers should typically be last in the chain so that other middleware
// (e.g. logging) can operate on the recovered state instead of being directly affected by any panic
_ = grpc.NewServer(
grpc_middleware.WithUnaryServerChain(
grpc_recovery.UnaryServerInterceptor(opts...),
),
grpc_middleware.WithStreamServerChain(
grpc_recovery.StreamServerInterceptor(opts...),
),
)
}
```
</details>
## <a name="pkg-imports">Imported Packages</a>
- [golang.org/x/net/context](https://godoc.org/golang.org/x/net/context)
- [google.golang.org/grpc](https://godoc.org/google.golang.org/grpc)
- [google.golang.org/grpc/codes](https://godoc.org/google.golang.org/grpc/codes)
## <a name="pkg-index">Index</a>
* [func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor](#StreamServerInterceptor)
* [func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor](#UnaryServerInterceptor)
* [type Option](#Option)
* [func WithRecoveryHandler(f RecoveryHandlerFunc) Option](#WithRecoveryHandler)
* [type RecoveryHandlerFunc](#RecoveryHandlerFunc)
#### <a name="pkg-examples">Examples</a>
* [Package (Initialization)](#example__initialization)
#### <a name="pkg-files">Package files</a>
[doc.go](./doc.go) [interceptors.go](./interceptors.go) [options.go](./options.go)
## <a name="StreamServerInterceptor">func</a> [StreamServerInterceptor](./interceptors.go#L30)
``` go
func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor
```
StreamServerInterceptor returns a new streaming server interceptor for panic recovery.
## <a name="UnaryServerInterceptor">func</a> [UnaryServerInterceptor](./interceptors.go#L16)
``` go
func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor
```
UnaryServerInterceptor returns a new unary server interceptor for panic recovery.
## <a name="Option">type</a> [Option](./options.go#L25)
``` go
type Option func(*options)
```
### <a name="WithRecoveryHandler">func</a> [WithRecoveryHandler](./options.go#L28)
``` go
func WithRecoveryHandler(f RecoveryHandlerFunc) Option
```
WithRecoveryHandler customizes the function for recovering from a panic.
## <a name="RecoveryHandlerFunc">type</a> [RecoveryHandlerFunc](./interceptors.go#L13)
``` go
type RecoveryHandlerFunc func(p interface{}) (err error)
```
RecoveryHandlerFunc is a function that recovers from the panic `p` by returning an `error`.
- - -
Generated by [godoc2ghmd](https://github.com/GandalfUK/godoc2ghmd)

View File

@@ -0,0 +1,15 @@
// Copyright 2017 David Ackroyd. All Rights Reserved.
// See LICENSE for licensing terms.
/*
`grpc_recovery` are intereceptors that recover from gRPC handler panics.
Server Side Recovery Middleware
By default a panic will be converted into a gRPC error with `code.Internal`.
Handling can be customised by providing an alternate recovery function.
Please see examples for simple examples of use.
*/
package grpc_recovery

View File

@@ -0,0 +1,48 @@
// Copyright 2017 David Ackroyd. All Rights Reserved.
// See LICENSE for licensing terms.
package grpc_recovery
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
)
// RecoveryHandlerFunc is a function that recovers from the panic `p` by returning an `error`.
type RecoveryHandlerFunc func(p interface{}) (err error)
// UnaryServerInterceptor returns a new unary server interceptor for panic recovery.
func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
o := evaluateOptions(opts)
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ interface{}, err error) {
defer func() {
if r := recover(); r != nil {
err = recoverFrom(r, o.recoveryHandlerFunc)
}
}()
return handler(ctx, req)
}
}
// StreamServerInterceptor returns a new streaming server interceptor for panic recovery.
func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
o := evaluateOptions(opts)
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) (err error) {
defer func() {
if r := recover(); r != nil {
err = recoverFrom(r, o.recoveryHandlerFunc)
}
}()
return handler(srv, stream)
}
}
func recoverFrom(p interface{}, r RecoveryHandlerFunc) error {
if r == nil {
return grpc.Errorf(codes.Internal, "%s", p)
}
return r(p)
}

View File

@@ -0,0 +1,32 @@
// Copyright 2017 David Ackroyd. All Rights Reserved.
// See LICENSE for licensing terms.
package grpc_recovery
var (
defaultOptions = &options{
recoveryHandlerFunc: nil,
}
)
type options struct {
recoveryHandlerFunc RecoveryHandlerFunc
}
func evaluateOptions(opts []Option) *options {
optCopy := &options{}
*optCopy = *defaultOptions
for _, o := range opts {
o(optCopy)
}
return optCopy
}
type Option func(*options)
// WithRecoveryHandler customizes the function for recovering from a panic.
func WithRecoveryHandler(f RecoveryHandlerFunc) Option {
return func(o *options) {
o.recoveryHandlerFunc = f
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,80 @@
# grpc_validator
`import "github.com/grpc-ecosystem/go-grpc-middleware/validator"`
* [Overview](#pkg-overview)
* [Imported Packages](#pkg-imports)
* [Index](#pkg-index)
## <a name="pkg-overview">Overview</a>
`grpc_validator` is a generic request contents validator server-side middleware for gRPC.
### Request Validator Middleware
Validating input is important, and hard. It also causes a lot of boilerplate code. This middleware
checks for the existence of a `Validate` method on each of the messages of a gRPC request. This
includes the single request of the `Unary` calls, as well as each message of the inbound Stream calls.
In case of a validation failure, an `InvalidArgument` gRPC status is returned, along with a
description of the validation failure.
While it is generic, it was intended to be used with <a href="https://github.com/mwitkow/go-proto-validators">https://github.com/mwitkow/go-proto-validators</a>,
a Go protocol buffers codegen plugin that creates the `Validate` methods (including nested messages)
based on declarative options in the `.proto` files themselves. For example:
syntax = "proto3";
package validator.examples;
import "github.com/mwitkow/go-proto-validators/validator.proto";
message InnerMessage {
// some_integer can only be in range (1, 100).
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
// some_float can only be in range (0;1).
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}
message OuterMessage {
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}
The `OuterMessage.Validate` would include validation of regexes, existence of the InnerMessage and
the range values within it. The `grpc_validator` middleware would then automatically use that to
check all messages processed by the server.
Please consult <a href="https://github.com/mwitkow/go-proto-validators">https://github.com/mwitkow/go-proto-validators</a> for details on `protoc` invocation and
other parameters of customization.
## <a name="pkg-imports">Imported Packages</a>
- [golang.org/x/net/context](https://godoc.org/golang.org/x/net/context)
- [google.golang.org/grpc](https://godoc.org/google.golang.org/grpc)
- [google.golang.org/grpc/codes](https://godoc.org/google.golang.org/grpc/codes)
## <a name="pkg-index">Index</a>
* [func StreamServerInterceptor() grpc.StreamServerInterceptor](#StreamServerInterceptor)
* [func UnaryServerInterceptor() grpc.UnaryServerInterceptor](#UnaryServerInterceptor)
#### <a name="pkg-files">Package files</a>
[doc.go](./doc.go) [validator.go](./validator.go)
## <a name="StreamServerInterceptor">func</a> [StreamServerInterceptor](./validator.go#L36)
``` go
func StreamServerInterceptor() grpc.StreamServerInterceptor
```
StreamServerInterceptor returns a new streaming server interceptor that validates incoming messages.
The stage at which invalid messages will be rejected with `InvalidArgument` varies based on the
type of the RPC. For `ServerStream` (1:m) requests, it will happen before reaching any userspace
handlers. For `ClientStream` (n:1) or `BidiStream` (n:m) RPCs, the messages will be rejected on
calls to `stream.Recv()`.
## <a name="UnaryServerInterceptor">func</a> [UnaryServerInterceptor](./validator.go#L19)
``` go
func UnaryServerInterceptor() grpc.UnaryServerInterceptor
```
UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages.
Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers.
- - -
Generated by [godoc2ghmd](https://github.com/GandalfUK/godoc2ghmd)

View File

@@ -0,0 +1,73 @@
# grpc_validator
import "github.com/grpc-ecosystem/go-grpc-middleware/validator"
`grpc_validator` is a generic request contents validator server-side middleware for
gRPC.
### Request Validator Middleware
Validating input is important, and hard. It also causes a lot of boilerplate code.
This middleware checks for the existence of a `Validate` method on each of the
messages of a gRPC request. This includes the single request of the `Unary`
calls, as well as each message of the inbound Stream calls. In case of a
validation failure, an `InvalidArgument` gRPC status is returned, along with
a description of the validation failure.
While it is generic, it was intended to be used with
https://github.com/mwitkow/go-proto-validators, a Go protocol buffers codegen
plugin that creates the `Validate` methods (including nested messages) based on
declarative options in the `.proto` files themselves. For example:
syntax = "proto3";
package validator.examples;
import "github.com/mwitkow/go-proto-validators/validator.proto";
message InnerMessage {
// some_integer can only be in range (1, 100).
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
// some_float can only be in range (0;1).
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}
message OuterMessage {
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}
The `OuterMessage.Validate` would include validation of regexes, existence of
the InnerMessage and the range values within it. The `grpc_validator` middleware
would then automatically use that to check all messages processed by the server.
Please consult https://github.com/mwitkow/go-proto-validators for details on
`protoc` invocation and other parameters of customization.
## Usage
#### func StreamServerInterceptor
```go
func StreamServerInterceptor() grpc.StreamServerInterceptor
```
StreamServerInterceptor returns a new streaming server interceptor that
validates incoming messages.
The stage at which invalid messages will be rejected with `InvalidArgument`
varies based on the type of the RPC. For `ServerStream` (1:m) requests, it will
happen before reaching any userspace handlers. For `ClientStream` (n:1) or
`BidiStream` (n:m) RPCs, the messages will be rejected on calls to
`stream.Recv()`.
#### func UnaryServerInterceptor
```go
func UnaryServerInterceptor() grpc.UnaryServerInterceptor
```
UnaryServerInterceptor returns a new unary server interceptor that validates
incoming messages.
Invalid messages will be rejected with `InvalidArgument` before reaching any
userspace handlers.

View File

@@ -0,0 +1,45 @@
// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
/*
`grpc_validator` is a generic request contents validator server-side middleware for gRPC.
Request Validator Middleware
Validating input is important, and hard. It also causes a lot of boilerplate code. This middleware
checks for the existence of a `Validate` method on each of the messages of a gRPC request. This
includes the single request of the `Unary` calls, as well as each message of the inbound Stream calls.
In case of a validation failure, an `InvalidArgument` gRPC status is returned, along with a
description of the validation failure.
While it is generic, it was intended to be used with https://github.com/mwitkow/go-proto-validators,
a Go protocol buffers codegen plugin that creates the `Validate` methods (including nested messages)
based on declarative options in the `.proto` files themselves. For example:
syntax = "proto3";
package validator.examples;
import "github.com/mwitkow/go-proto-validators/validator.proto";
message InnerMessage {
// some_integer can only be in range (1, 100).
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
// some_float can only be in range (0;1).
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}
message OuterMessage {
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}
The `OuterMessage.Validate` would include validation of regexes, existence of the InnerMessage and
the range values within it. The `grpc_validator` middleware would then automatically use that to
check all messages processed by the server.
Please consult https://github.com/mwitkow/go-proto-validators for details on `protoc` invocation and
other parameters of customization.
*/
package grpc_validator

View File

@@ -0,0 +1,57 @@
// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
package grpc_validator
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
)
type validator interface {
Validate() error
}
// UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages.
//
// Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers.
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if v, ok := req.(validator); ok {
if err := v.Validate(); err != nil {
return nil, grpc.Errorf(codes.InvalidArgument, err.Error())
}
}
return handler(ctx, req)
}
}
// StreamServerInterceptor returns a new streaming server interceptor that validates incoming messages.
//
// The stage at which invalid messages will be rejected with `InvalidArgument` varies based on the
// type of the RPC. For `ServerStream` (1:m) requests, it will happen before reaching any userspace
// handlers. For `ClientStream` (n:1) or `BidiStream` (n:m) RPCs, the messages will be rejected on
// calls to `stream.Recv()`.
func StreamServerInterceptor() grpc.StreamServerInterceptor {
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
wrapper := &recvWrapper{stream}
return handler(srv, wrapper)
}
}
type recvWrapper struct {
grpc.ServerStream
}
func (s *recvWrapper) RecvMsg(m interface{}) error {
if err := s.ServerStream.RecvMsg(m); err != nil {
return err
}
if v, ok := m.(validator); ok {
if err := v.Validate(); err != nil {
return grpc.Errorf(codes.InvalidArgument, err.Error())
}
}
return nil
}

View File

@@ -0,0 +1,29 @@
// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
package grpc_middleware
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// WrappedServerStream is a thin wrapper around grpc.ServerStream that allows modifying context.
type WrappedServerStream struct {
grpc.ServerStream
// WrappedContext is the wrapper's own Context. You can assign it.
WrappedContext context.Context
}
// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
func (w *WrappedServerStream) Context() context.Context {
return w.WrappedContext
}
// WrapServerStream returns a ServerStream that has the ability to overwrite context.
func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream {
if existing, ok := stream.(*WrappedServerStream); ok {
return existing
}
return &WrappedServerStream{ServerStream: stream, WrappedContext: stream.Context()}
}

View File

@@ -0,0 +1,37 @@
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/protoc-gen-swagger/options",
)
proto_library(
name = "options_proto",
srcs = [
"annotations.proto",
"openapiv2.proto",
],
deps = [
"@com_google_protobuf//:any_proto",
"@com_google_protobuf//:descriptor_proto",
],
)
go_proto_library(
name = "options_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options",
proto = ":options_proto",
)

View File

@@ -0,0 +1,103 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: protoc-gen-swagger/options/annotations.proto
package options // import "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
var E_Openapiv2Swagger = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FileOptions)(nil),
ExtensionType: (*Swagger)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger",
Tag: "bytes,1042,opt,name=openapiv2_swagger,json=openapiv2Swagger",
Filename: "protoc-gen-swagger/options/annotations.proto",
}
var E_Openapiv2Operation = &proto.ExtensionDesc{
ExtendedType: (*descriptor.MethodOptions)(nil),
ExtensionType: (*Operation)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_operation",
Tag: "bytes,1042,opt,name=openapiv2_operation,json=openapiv2Operation",
Filename: "protoc-gen-swagger/options/annotations.proto",
}
var E_Openapiv2Schema = &proto.ExtensionDesc{
ExtendedType: (*descriptor.MessageOptions)(nil),
ExtensionType: (*Schema)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_schema",
Tag: "bytes,1042,opt,name=openapiv2_schema,json=openapiv2Schema",
Filename: "protoc-gen-swagger/options/annotations.proto",
}
var E_Openapiv2Tag = &proto.ExtensionDesc{
ExtendedType: (*descriptor.ServiceOptions)(nil),
ExtensionType: (*Tag)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_tag",
Tag: "bytes,1042,opt,name=openapiv2_tag,json=openapiv2Tag",
Filename: "protoc-gen-swagger/options/annotations.proto",
}
var E_Openapiv2Field = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*JSONSchema)(nil),
Field: 1042,
Name: "grpc.gateway.protoc_gen_swagger.options.openapiv2_field",
Tag: "bytes,1042,opt,name=openapiv2_field,json=openapiv2Field",
Filename: "protoc-gen-swagger/options/annotations.proto",
}
func init() {
proto.RegisterExtension(E_Openapiv2Swagger)
proto.RegisterExtension(E_Openapiv2Operation)
proto.RegisterExtension(E_Openapiv2Schema)
proto.RegisterExtension(E_Openapiv2Tag)
proto.RegisterExtension(E_Openapiv2Field)
}
func init() {
proto.RegisterFile("protoc-gen-swagger/options/annotations.proto", fileDescriptor_annotations_8378bd63c2853a5a)
}
var fileDescriptor_annotations_8378bd63c2853a5a = []byte{
// 346 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x4f, 0xea, 0x40,
0x14, 0xc5, 0xc3, 0xe6, 0xe5, 0xa5, 0xef, 0xa9, 0x58, 0x37, 0x86, 0xf8, 0x87, 0x9d, 0xc6, 0xc0,
0x8c, 0x81, 0x5d, 0x77, 0x6a, 0xe2, 0xc2, 0x44, 0x49, 0x0a, 0x2b, 0x37, 0x64, 0x18, 0x2e, 0x97,
0x49, 0x4a, 0xef, 0x64, 0x66, 0x80, 0x90, 0xb0, 0xf4, 0x13, 0xf8, 0x89, 0x8d, 0xd3, 0xd2, 0x9a,
0x8a, 0xa6, 0xbb, 0xde, 0xdb, 0x39, 0xe7, 0x77, 0x7a, 0x3a, 0x41, 0x47, 0x1b, 0x72, 0x24, 0xbb,
0x08, 0x69, 0xd7, 0xae, 0x05, 0x22, 0x18, 0x4e, 0xda, 0x29, 0x4a, 0x2d, 0x17, 0x69, 0x4a, 0x4e,
0xf8, 0x67, 0xe6, 0x8f, 0x85, 0x57, 0x68, 0xb4, 0x64, 0x28, 0x1c, 0xac, 0xc5, 0x26, 0xdb, 0xc9,
0x31, 0x42, 0x3a, 0xce, 0xa5, 0x2c, 0x97, 0xb6, 0x6e, 0x7e, 0xb1, 0x25, 0x0d, 0xa9, 0xd0, 0x6a,
0xd5, 0xcb, 0x0c, 0x5a, 0x6d, 0x24, 0xc2, 0x04, 0xb8, 0x9f, 0x26, 0xcb, 0x19, 0x9f, 0x82, 0x95,
0x46, 0x69, 0x47, 0x26, 0x3b, 0x11, 0x6d, 0x83, 0xe3, 0x42, 0xb4, 0x43, 0x85, 0x67, 0x2c, 0xd3,
0xb1, 0x9d, 0x8e, 0x3d, 0xaa, 0x04, 0x06, 0x19, 0xe4, 0xf4, 0xfd, 0x6f, 0xbb, 0x71, 0xfd, 0xaf,
0x77, 0xcb, 0x6a, 0x26, 0x66, 0xc3, 0x6c, 0x8e, 0x9b, 0x05, 0x29, 0xdf, 0x44, 0x6f, 0x8d, 0xe0,
0xa4, 0xc4, 0x93, 0x06, 0xe3, 0x3b, 0x09, 0x2f, 0xbe, 0x05, 0x78, 0x06, 0x37, 0xa7, 0x69, 0x25,
0x42, 0xaf, 0x76, 0x84, 0xc1, 0xce, 0x3a, 0x0e, 0x0b, 0x5e, 0xb1, 0x8b, 0xb6, 0x41, 0xf3, 0x4b,
0x09, 0x72, 0x0e, 0x0b, 0x11, 0x5e, 0xee, 0x89, 0x60, 0xad, 0xc0, 0x6a, 0x0d, 0xbc, 0x7e, 0x0d,
0xde, 0x38, 0x3e, 0x2a, 0x5b, 0xf0, 0x8b, 0xc8, 0x06, 0x07, 0x25, 0xdd, 0x09, 0xdc, 0x83, 0x1e,
0x82, 0x59, 0x29, 0x59, 0x45, 0x77, 0x6a, 0xa3, 0x47, 0x02, 0xe3, 0xff, 0x05, 0x64, 0x24, 0x30,
0xda, 0x06, 0x65, 0x8e, 0xf1, 0x4c, 0x41, 0x32, 0x0d, 0xcf, 0xf7, 0xfc, 0x75, 0x48, 0xaa, 0x9d,
0xf7, 0x6b, 0x43, 0x9f, 0x86, 0x83, 0x97, 0xfc, 0x9b, 0x0f, 0x0b, 0x96, 0xb7, 0xbc, 0x7f, 0x78,
0xbd, 0x43, 0xe5, 0xe6, 0xcb, 0x09, 0x93, 0xb4, 0xe0, 0x9f, 0x86, 0x5d, 0x90, 0x64, 0x37, 0xd6,
0x41, 0x3e, 0xe6, 0xfe, 0xfc, 0xe7, 0xcb, 0x3e, 0xf9, 0xe3, 0xdf, 0xf5, 0x3f, 0x02, 0x00, 0x00,
0xff, 0xff, 0x4b, 0xc4, 0x41, 0xfb, 0x68, 0x03, 0x00, 0x00,
}

View File

@@ -0,0 +1,44 @@
syntax = "proto3";
package grpc.gateway.protoc_gen_swagger.options;
option go_package = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options";
import "protoc-gen-swagger/options/openapiv2.proto";
import "google/protobuf/descriptor.proto";
extend google.protobuf.FileOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Swagger openapiv2_swagger = 1042;
}
extend google.protobuf.MethodOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Operation openapiv2_operation = 1042;
}
extend google.protobuf.MessageOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Schema openapiv2_schema = 1042;
}
extend google.protobuf.ServiceOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
Tag openapiv2_tag = 1042;
}
extend google.protobuf.FieldOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
JSONSchema openapiv2_field = 1042;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,373 @@
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";
// `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;
}
// `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;
}
// `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;
// field 3 is reserved for 'example'.
reserved 4;
}
// `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;
}
// `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;
}
// `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;
}